代码和特性在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;
};
起始点始终在左面,终止点始终在右面,不受选择方向的影响。
只有当起始点的开头或终止点的末尾是<br/>时,返回的不是文本节点,可以通过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编辑器核心思想的实例分析的详细内容。