程式碼和特性在chrome49下測試有效。
文字渲染的本質是對文字節點的渲染,透過瀏覽器內建的物件Range可以得到選擇的起始點、與終止點
var range = getRangeObject();var start = range.startOffset, end = range.endOffset;var startContainer = range.startContainer;var endContainer = range.endContainer;
getRangeObjec程式碼如下
function getRangeObject(){if(window.getSelection) {var selection = window.getSelection();if(selection.rangeCount > 0) {return selection.getRangeAt(0); } }else if(document.selection) {return document.selection.createRange(); }return null; };
起始點在左面,終止點總是右邊,不受選擇方向的影響。
只有當起始點的開頭或終止點的末尾是
時,返回的不是文字節點,可以透過start,end確定br元素的位置分別是startContainer.childNodes [start],endContainer.childNodes[end-1]。傳回的是文字節點start表示遊標相對於起始文字節點所在的起始位置,end表示遊標相對於終止文字節點所在的終止位置。
得到下一個文字節點的演算法為
function getNextTextNode(startNode,dir = "nextSibling"){//记录startNode变化之前的状态,startNode变化后无效时便于状态的回滚let unchangeNode = startNode;if(startNode.nodeType == 3){ startNode = startNode[dir]; }while (true){if(startNode == undefined){if(unchangeNode == undefined){//保护机制throw new Error("程序会陷入死循环");break; }/*startNode所在的父元素所有选中节点遍历完毕,将sartNode指向父元素的兄弟节点*/let parent = unchangeNode.parentElement; unchangeNode = parent; startNode = parent[dir]; }else if(startNode.nodeType == 3){//文本节点则退出循环break; }else if(startNode.tagName == "BR"){//处理单标签,避免不必要的迭代unchangeNode = startNode; startNode = startNode[dir]; }else if(startNode.nodeType == 1){/*如果是双标签元素则进入*/unchangeNode = startNode;if(dir == "previousSibling"){ startNode = $(startNode).contents().last().get(0); }else if(dir == "nextSibling"){ startNode = $(startNode).contents().first().get(0); }else {//便于错误的定位throw new Error("错误的遍历方向:"+dir); } }else {//便于错误的定位throw new Error("不期待的元素类型=》"+startNode); } } return startNode; }
//上述函數以外部變數+while循環的方式取代遞歸,加入的保護機制減少誤用、潛在bug導致極差的體驗。
取得起始節點與結束節點之間的所有文字節點
function getTextNodes(startTextNode,endTextNode){ let textNodeArray = []; let node = startTextNode;while (true) { node = getNextTextNode(node);if(node == endTextNode){break; } textNodeArray.push(node); } return textNodeArray; }
以上是H5編輯器核心思想的實例分析的詳細內容。更多資訊請關注PHP中文網其他相關文章!