有問題的插入方案

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> <style>#edit{height:500px;width:500px;border:1px solid red;}</style> </head> <body> <div id="edit" contenteditable></div> <input type="text" id="emojiInput"> <button id="sendEmoji">發送表情</button> <script> var sendEmoji = document.getElementById('sendEmoji') // 定義最后光標對象 var lastEditRange; // 編輯框點擊事件 document.getElementById('edit').onclick = function() { // 獲取選定對象 var selection = getSelection() // 設置最后光標對象 lastEditRange = selection.getRangeAt(0) } // 編輯框按鍵彈起事件 document.getElementById('edit').onkeyup = function() { // 獲取選定對象 var selection = getSelection() // 設置最后光標對象 lastEditRange = selection.getRangeAt(0) } // 表情點擊事件 document.getElementById('sendEmoji').onclick = function() { // 獲取編輯框對象 var edit = document.getElementById('edit') // 獲取輸入框對象 var emojiInput = document.getElementById('emojiInput') // 編輯框設置焦點 edit.focus() // 獲取選定對象 var selection = getSelection() // 判斷是否有最后光標對象存在 if (lastEditRange) { // 存在最后光標對象,選定對象清除所有光標並添加最后光標還原之前的狀態 selection.removeAllRanges() selection.addRange(lastEditRange) } // 判斷選定對象范圍是編輯框還是文本節點 if (selection.anchorNode.nodeName != '#text') { // 如果是編輯框范圍。則創建表情文本節點進行插入 var emojiText = document.createTextNode(emojiInput.value) if (edit.childNodes.length > 0) { // 如果文本框的子元素大於0,則表示有其他元素,則按照位置插入表情節點 for (var i = 0; i < edit.childNodes.length; i++) { if (i == selection.anchorOffset) { edit.insertBefore(emojiText, edit.childNodes[i]) } } } else { // 否則直接插入一個表情元素 edit.appendChild(emojiText) } // 創建新的光標對象 var range = document.createRange() // 光標對象的范圍界定為新建的表情節點 range.selectNodeContents(emojiText) // 光標位置定位在表情節點的最大長度 range.setStart(emojiText, emojiText.length) // 使光標開始和光標結束重疊 range.collapse(true) // 清除選定對象的所有光標對象 selection.removeAllRanges() // 插入新的光標對象 selection.addRange(range) } else { //debugger; // 如果是文本節點則先獲取光標對象 var range = selection.getRangeAt(0) // 獲取光標對象的范圍界定對象,一般就是textNode對象 var textNode = range.startContainer; // 獲取光標位置 var rangeStartOffset = range.startOffset; // 文本節點在光標位置處插入新的表情內容 textNode.insertData(rangeStartOffset, emojiInput.value) // 光標移動到到原來的位置加上新內容的長度 range.setStart(textNode, rangeStartOffset + emojiInput.value.length) // 光標開始和光標結束重疊 range.collapse(true) // 清除選定對象的所有光標對象 selection.removeAllRanges() // 插入新的光標對象 selection.addRange(range) } // 無論如何都要記錄最后光標對象 lastEditRange = selection.getRangeAt(0) } </script> </body> </html>
插入時 應該考慮的問題,
第一 原來容器內 有文本內容,現在在文本內容中間插入dom元素, 以上方法未解決,
第二 插入后定位到新插入的元素的位置
另附 :上面方法最有價值的地方在於 定義全局唯一range 和selection 對象,在每次變化時候記錄下最新的range和selection
變化的時候包括
1) blur 事件 2) onclick 事件 3) onkeyup 事件 --這些事件都有可能會改變光標位置
4)代碼觸發時候 比如 用代碼向輸入框內插入一些節點時候 這時候應該也要記錄最新的selection 和range
ok的方案
/** * 在輸入區插入各種東東通用 * @param html */ function insertImg(html) { var dthis = $("#input-content")[0]; var sel = getSelection(); 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('div'); 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的div 獲得焦點 ierange = document.selection.createRange();// 獲取光標位置 ierange.pasteHTML(html); // 在光標位置插入html 如果只是插入text 則就是fus.text="..." $(dthis).focus(); } }