fritx / vue-at

At.js for Vue.
https://fritx.github.io/vue-at/
MIT License
529 stars 114 forks source link

在首个字符加入custom tag后删除后出现bug #57

Open brynne8 opened 6 years ago

brynne8 commented 6 years ago

我用的是2.5.0-beta版本,浏览器是Chrome 49。在content editable内插入类似

<span slot="embeddedItem" slot-scope="s">
  <span class="tag"><img :src="s.current.avatar">{{ s.current.name }}</span>
</span>

的代码,在首个字符就插入at结构@123,然后退格键把它删掉,此时再加入一个at结构@456的时候,发现at上面的菜单关不掉(在Chrome 49出现,最新版Chrome能关掉),并且出现光标在at结构之前(所有浏览器都这样),且无法将光标定位到at结构之后。再次点击未关掉的menu的某个member,Chrome 49提示

Uncaught IndexSizeError: Failed to execute 'setStart' on 'Range': 
The offset -1 is larger than or equal to the node's length (0).
fritx commented 6 years ago

@AlexanderMisel 感谢反馈,确实可能很不稳定~ 光标无法定位在后方,跟contenteditable=false有关,目前版本已经给前后加上了空格尽量避免这种情况了,但不保证,还得看看

brynne8 commented 6 years ago

我用的版本有你这几行代码,但是还是不行(即删完后加光标出现在前面)。比较奇怪的是<span>的前面的空格好像无效。也可能是我用的富文本编辑器(MediumEditor)的问题。

brynne8 commented 6 years ago

我目前是照着MediumEditor的实现改了一下函数,还有就是加了特殊的空白节点,自己先用着……

insertHtml (html, r) {
    var el, fragment, node, lastNode, toReplace;
    toReplace = r.commonAncestorContainer;
    if (this.isMediumEditorElement(toReplace) && !toReplace.firstChild) {
        r.selectNode(toReplace.appendChild(document.createTextNode('')));
    } else if ((toReplace.nodeType === 3 && r.startOffset === 0 && r.endOffset === toReplace.nodeValue.length) ||
        (toReplace.nodeType !== 3 && toReplace.innerHTML === r.toString())) {
        // Ensure range covers maximum amount of nodes as possible
        // By moving up the DOM and selecting ancestors whose only child is the range
        while (!this.isMediumEditorElement(toReplace) && toReplace.parentNode && toReplace.parentNode.childNodes.length === 1 && !this.isMediumEditorElement(toReplace.parentNode)) {
            toReplace = toReplace.parentNode;
        }
        r.selectNode(toReplace);
    }
    r.deleteContents();

    el = document.createElement('div');
    el.innerHTML = html;
    fragment = document.createDocumentFragment();
    while (el.firstChild) {
        node = el.firstChild;
        fragment.appendChild(node);
    }

    lastNode = document.createTextNode(' \u200B');
    r.insertNode(lastNode);
    r.insertNode(fragment);
    // Preserve the selection:
    r = r.cloneRange();
    r.setStartAfter(lastNode);
    r.collapse(true);
    applyRange(r);
},