初试富文本编辑器

都说富文本编辑器是天坑,我也去坑边看一眼

为什么都说富文本编辑器是天坑?。早就听说过富文本编辑器,一般看到这种标题都会让人有一种想去试试的冲动,至少也要去溜达一圈,就像地牢围攻1的绝望洞一样。于是我去MDN上找了找教程。原来现成的代码都有。

要尝试点什么?

  1. 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');
    }
    });
    }

  2. 无法取得选中区域的文字。因为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;
    }

难得能用上一点点数据结构的知识

完整代码

尽管惨不忍睹,我还是献丑放上来。不被婊怎么进步,虽然我觉得也不会有人觉得值得花功夫婊。(以后再也不贴大段代码了,调格式好累。这次就当充数了。结果调格式的过程中自己给自己增加了点击量)

posted @ 2017-09-23 11:13  linden5  阅读(262)  评论(0)    收藏  举报