在可編輯div中插入文字或圖片的問題解決思路

 最近在網上碰到一個人問瞭我一個問題,在可編輯p中插入文字或者圖片。因為web在線編輯器我從來隻是用,基本不會去研究源代碼。後來正好一個在線聊天web項目中也要用到這個功能,我就特地看看瞭代碼。
   基本上編輯器或者在線聊天web頁面,是不太可能用textarea在做輸入框的,因為我們可能要插入圖片或者超級鏈接,因此選擇在iframe或者p作為輸入框是必須的。
   我這裡用的是 p.
  要使p可編輯 必須 加入 contentEditable="true" 這個屬性。
  然後就是獲取光標位置(或者選擇文字位置)進行文字或者html的插入 。
 由於火狐等標準瀏覽器支持getSelection方法,IE9以上也支持,但是萬惡的iE6-8不支持,因此要分兩部分代碼來寫。由於這些代碼很簡單,以下先貼一遍
[javascript]
function insertHTML(html) 
       { 
           var dthis=$("#p3")[0];//要插入內容的某個p,在標準瀏覽器中 無需這句話 
            var sel, range; 
            if (window.getSelection) 
             { 
                    // IE9 and non-IE 
                    sel = window.getSelection(); 
                    if (sel.getRangeAt && sel.rangeCount) { 
                    range = sel.getRangeAt(0); 
                    range.deleteContents(); 
                    var el = document.createElement('p'); 
                    el.innerHTML = html; 
                    var frag = document.createDocumentFragment(), node, lastNode; 
                    while ( (node = el.firstChild) ) 
                     { 
                        lastNode = frag.appendChild(node); 
                     } 
                    
                range.insertNode(frag); 
                    if (lastNode) { 
                    range = range.cloneRange(); 
                    range.setStartAfter(lastNode); 
                    range.collapse(true); 
                    sel.removeAllRanges(); 
                    sel.addRange(range); 
                    } 
                   } 
            }  
            else if (document.selection && document.selection.type !='Control')  
            { 
              
                $(dthis).focus(); //在非標準瀏覽器中 要先讓你需要插入html的p 獲得焦點 
         ierange= document.selection.createRange();//獲取光標位置 
                ierange.pasteHTML(html);    //在光標位置插入html 如果隻是插入text 則就是fus.text="…" 
                $(dthis).focus();     
              
            } 
       } 
  以上代碼基本 完成瞭 在可編輯p中 插入指定的html內容,這些代碼在baidu或者google中到處可以搜到,因此不再解釋為什麼這麼寫(太普遍瞭)

 執行後 會發現在IE或者非標準瀏覽器中 是正常的。在火狐或者chrome中 就不正常瞭

譬如  以下頁面 ,我有 不定數量的p(可能是程序動態生成),我隻需要其中某一個p進行html的插入,其他不需要。
[html] 
…..其他html元素….. 
<p id="p1" contentEditable="true"  ></p> 
 
<p id="p2" contentEditable="true" ></p> 
 
 <p contentEditable="true"  id="p3"></p> 
 <input type="button" id="cmdInsert" onclick="執行向p3插入html方法"/> 
<pre name="code" class="html">…..其他html元素…..</pre><br> 
<p></p> 
<pre></pre> 
<br> 
 如上頁面 我隻需要p3 支持插入html 其他兩個 隻是可編輯而已。<br> 
<p></p> 
<p>使用上述代碼會發現,如果最後一個失去焦點的是 p3 那麼一切正常 如果 不是p3 或者 我又點到頁面其他控件或者空白處,會發現插入的html沒有插入到我們想要的p3中而是插入到瞭 其他地方。</p> 
<p>   這其實不是bug,而是正常現象,getSelection 可以橫跨很多域,因此無法保證 獲得出來的range一定是你需要的p<br> 
</p> 
<p> 這裡我再次申明,我實在不想看(哪怕看一眼)國內的在線web編輯器是如何實現的。經過我翻查瞭度娘和google發現有個思路可以解決。</p> 
<p><br> 
</p> 
<p>  其實我們要解決的就是一件事情,每當頁面上的元素(包括p或者任意元素) 獲得焦點又失去後,我們隻需獲得最後一個失去焦點的p是否是p3,如果是則執行上述代碼,如果不是直接在p3的內容後面加入要插入的html(硬編碼就可以。不要告訴我 不會)</p> 
<p>     一開始我想到的辦法是對p3設置一個click事件以及focus事件,當鼠標點進去或者獲得焦點時 把一個變量 譬如叫做isp3 設置為true,點其他地方設置為false(這個方法實際上是行不通的,這裡我就不多解釋為什麼行不通,有各種不同的情形可以導致即使獲得焦點,isp3依然不會被設置為true,而且需要對每個html元素設置事件讓isp3變為false,這是很恐怖的事情).</p> 
<p><br> 
</p> 
<p>  這裡我放出一種比較通用和不容易被幹擾的解決辦法。</p> 
<p> 首先在 頁面的 最頂部寫上</p> 
<p> <style></p> 
<p> p:focus{z-index:100;}  // 這裡隨意你設置多少值,100隻是舉個列子<br> 
</p> 
<p></style></p> 
<p>上面這個樣式告訴我們,當隻有p 獲得焦點後 他會產生一個css屬性就是 z-index被設置成瞭100,以任何形式失去焦點 這個css屬性就沒瞭。當然你也可以設置其他的css屬性。因為我們在點button執行函數的時候,p3也會失去焦點(getSelection 依然存在)</p> 
<p><br> 
</p> 
<p>以下思路就清晰瞭 我們再寫一個函數</p> 
<p></p><pre name="code" class="javascript">var lastFocusID=""; 
function getFocus() 
       { 
        var plist = document.getElementsByTagName('p'); 
        for(var i=0; i<plist.length; i++) 
         { 
            var ta = plist.item(i); 
            if (window.getComputedStyle(ta, null).zIndex!=null && window.getComputedStyle(ta, null).zIndex == 100) { 
              if(ta.id && ta.id!=null) 
               lastFocusID=ta.id.toString(); 
               else 
                lastFocusID=""; 
               break; 
            } 
            else 
             lastFocusID=""; 
         } 
         
       } 
 //再加入一個全屏事件 
<pre name="code" class="javascript"> $(window).click(function(e) 
          { 
            if (window.getSelection) 
            { 
                 var getevent=e.srcElement?e.srcElement:e.target;//不要告訴我不知道這句的意思 
                
                if(getevent.tagName=="INPUT" && getevent.id!=null && getevent.id=="cmdInsert") 
                { 
                    //代表 點瞭插入html的按鈕 
                    //則不執行getFocus方法 
                 } 
                else 
                  getFocus();//除非點瞭那個插入html的按鈕 其他時候必須要執行getFocus來更新最後失去焦點的p 
            } 
            
            
          })</pre><br> 
<br> 
<p></p> 
<pre></pre> 
<br> 
  然後修改一下 insertHTML 這個方法 <pre name="code" class="javascript"> function insertHTML(html) 
       { 
           var dthis=$("#p3")[0]; 
            var sel, range; 
            if (window.getSelection) 
             { 
                if(lastFocusID!="p3") 
               {   www.aiwalls.com
<pre name="code" class="javascript">                $("#p3).html(dthis.innerHTML+html)     ;//說明 用戶可能在其他控件上 進行焦點或者其他操作 則</pre> return;//後面不執行瞭<br> 
}<br> 
<br> 
。。。。。。。。。。//其他代碼照舊<br> 
<pre></pre> 
<br> 
    這樣就解決火狐或者chrome裡面 會出現亂插入內容的現象。 
<p></p> 
<p><br> 
</p> 
<p>   當然這隻是一個思路, 歡迎大傢提供更好的辦法和性能更高的思路。<br> 
</p> 
<p><br> 
</p> 
 
</pre></pre> 

發佈留言