简单记录一下遇到的问题...
一、赋值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对象是
注意,此时的光标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++
(持续更新)