quill摸索记

1,400 阅读2分钟

简单记录一下遇到的问题...

一、赋值html to quill

方案1: 剪贴板

const delta = quill.clipboard.convert(value)
quill.setContents(delta, 'silent')

可以顺利赋值,但按回退键,range.index会被赋值-1,导致出现报错 Uncaught DOMException: Failed to execute 'setStart' on 'Range': The offset 4294967294 is larger than the node's length quill.js源码好像没有对range.index做正数判断处理

方案2: dangerouslyPasteHTML

quill.clipboard.dangerouslyPasteHTML(value)

同方案1一样回退会报错

方案3: innerHTML

简单粗暴修改根元素的innerHTML

quill.root.innerHTML = value

可行,回退也没有报错,但是重复赋值自定义embed会产生span标签多级嵌套

二、清除剪贴板的样式

当用户复制带有样式的文本,粘贴到quill编辑器中,此时会产生错乱的格式。尤其你的编辑器本身定义了新的Parchment,粘贴回来的效果一言难尽。如果只想单纯的拷贝文本,可以进一步监听编辑器的paste事件,清除样式

    // 复制粘贴清除样式
    handlePaste(evt) {
      var brRegex = /\r?\n/g;
      let clipboard = evt.clipboardData || window.clipboardData;
      let paste = clipboard.getData('text/plain')
      let divText = paste.split(brRegex)
      const selection = window.getSelection();
      if (!selection.rangeCount)
        return false;

      let div = document.createElement('div');
      divText.forEach(text => {
        div.appendChild(document.createTextNode(text));
        div.appendChild(document.createElement("br"));
      });

      selection.deleteFromDocument();
      selection.getRangeAt(0).insertNode(div);

      evt.preventDefault();
    }

三、自定义Parchment

Quill编辑器通过维护自己的文档类型(Parchment)来表示内容。通过Parchment你可以自定义出Quill能够识别的内容和格式,或者添加全新的内容和格式。(更多关于Parchment请戳 原文 | 译文

这是我自定义的一个embed👇


import Quill from "quill";

const InlineEmbed = Quill.import('blots/embed');

class Drama extends InlineEmbed { 

    // 这些Parchment是不可见的,所以必须是静态的(static)
    static create(value) {
        const node = super.create(value);
        node.innerText = (value && value.name) ? `@${value.name}` : `@`;
        node.setAttribute('data-id', value.id);
        node.setAttribute('data-name', value.name);
        node.className = "qr-blot-drama"
        node.appendChild(span)
        return node;
    }


    static value(domNode) {
        const { id, name } = domNode.dataset;
        return { id, name };
    }
}

// 设置blotName和tagName,然后注册到Quill上就可以了
Drama.blotName = 'drama'
Drama.tagName = 'span'

Quill.register({ "formats/drama": Drama });

插入编辑器后,生成对应的Delta对象是

image.png

注意,此时的光标Range.index为1

我遇到的坑主要是,当它处于编辑器delta.ops数组的最后一位时,失去焦点后重新点击编辑器后监听select-change事件得到的Range.index并不正确,此时返回的是0,彷佛插入的embed不复存在

看了一下quill的获取Range.index源码,大概是通过document.getSelection来获取用户选择的文本范围或光标的当前位置的,而我们新增的embed并不属于文本,导致使用Document.activeElement 来返回当前的焦点元素无效,从而返回的Range.index不正确吗??至今没太整明白

目前用了个比较笨拙的方法去解决,就是在插入embed后,再新增一个空格

quill.insertText(range.index, ' ', "user");
range.index++

(持续更新)