初试富文本编辑器
都说富文本编辑器是天坑,我也去坑边看一眼
为什么都说富文本编辑器是天坑?。早就听说过富文本编辑器,一般看到这种标题都会让人有一种想去试试的冲动,至少也要去溜达一圈,就像地牢围攻1的绝望洞一样。于是我去MDN上找了找教程。原来现成的代码都有。
要尝试点什么?
-
MDN的代码,无法实现光标位置变化之后,读取光标处的文本格式,并改变样式按钮状态的功能。比如word里面,光标处的文本是加粗的话,工具栏的加粗按钮就变成按下状态,离开这段区域之后又会变成未按下状态。要实现这个功能,基本思路就是利用点击和键盘事件加上queryCommandState,大致代码如下:
var editor = document.getElementById('editor');
editor.addEventListener('keyup', function() {
statusCheck(buttons);
});
editor.addEventListener('mouseup', function() {
statusCheck(buttons);
});function statusCheck(buttons) {
commands.forEach(function(command) {
var state = document.queryCommandState(command.cmd);
var className = buttons[command.cmd].className;
if (state) {
buttons[command.cmd].className = addClass(className, 'on');
} else {
buttons[command.cmd].className = removeClass(className, 'on');
}
});
} -
无法取得选中区域的文字。因为getSelection只返回选择的起始和结束的DOM元素及信息,如果想要取得所选文件,必须自己去遍历选中的DOM节点,取出其中的text节点。大致代码实现如下:
function getSelectedText() {
var selection = getSelection();// 取得开始的文字 var anchorNode = selection.anchorNode; var anchorOffset = selection.anchorOffset; var focusNode = selection.focusNode; var focusOffset = selection.focusOffset; // 判断选择的方向 var isForward = isNodeBefore(anchorNode, focusNode); var startNode; var endNode; var startOffset; var endOffset; if (isForward) { startNode = anchorNode; endNode = focusNode; startOffset = anchorOffset; endOffset = focusOffset; } else { startNode = focusNode; endNode = anchorNode; startOffset = focusOffset; endOffset = anchorOffset; } var text1 = ''; if (startNode !== null) { var startText = startNode.data; text1 = startText.substring(startOffset); } // 取得结束的文字 var text2 = ''; if (endNode !== null) { var endText = endNode.data; text2 = endText.substring(0, endOffset); } //取得中间的文字 var middleText = ''; if (startNode !== null && endNode !== null) { middleText = getMiddleText(startNode, endNode); } return text1 + middleText + text2;
}
function getMiddleText(startNode, endNode) {
if (startNode === null && endNode === null) {
return;
}var pivot = startNode; var middleText = ''; var text; while(pivot !== endNode) { text = ''; if (pivot.nextSibling === null) { if (pivot.parentNode === null) { break; } else { pivot = pivot.parentNode; } } else { pivot = pivot.nextSibling; text = traversal(pivot); } middleText += text; } return middleText; // 遍历节点选择文字 function traversal(root) { if (pivot === endNode) { return ''; } if (root.nodeType === 3) { return root.nodeValue; } else { var text = ''; var childNodes = root.childNodes; for (var i = 0; i < childNodes.length; i++) { if (childNodes[i] === endNode) { pivot = endNode; break; } text += traversal(childNodes[i]); } return text; } }
}
function isNodeBefore(startNode, endNode) {
var startParents = getParents(startNode), endParents = getParents(endNode);
var count = Math.min(startParents.length, endParents.length);
var commonParent, startParent, endParent;
for (var i = 0; i < count; i++) {
startParent = startParents[startParents.length - i - 1];
endParent = endParents[endParents.length - i - 1];
if (startParent === endParent) {
commonParent = startParent;
} else {
var startPos = convertToArray(commonParent.childNodes).indexOf(startParent);
var endPos = convertToArray(commonParent.childNodes).indexOf(endParent);
return startPos < endPos;
}
}
return true;
}
难得能用上一点点数据结构的知识
完整代码
尽管惨不忍睹,我还是献丑放上来。不被婊怎么进步,虽然我觉得也不会有人觉得值得花功夫婊。(以后再也不贴大段代码了,调格式好累。这次就当充数了。结果调格式的过程中自己给自己增加了点击量)