安装使用
$> npm i quill
创建quill实例,加载基本的样式、设置主题snow
。
<template>
<div class="rich-editor">
<div ref="root"></div>
</div>
</template>
<script setup lang="ts">
import { onMounted, ref } from "vue";
import Quill from "quill";
// 核心样式
// import "quill/dist/quill.core.css";
// 主题
import "quill/dist/quill.snow.css";
defineOptions({
name: "RichEditor",
});
const root = ref<HTMLElement>();
let editor = null;
onMounted(() => {
editor = new Quill(root.value!, {
modules: { toolbar: true },
theme: "snow",
});
});
</script>
这是基础的完整代码,之后的更改不再贴重复代码。
效果如下,提供了主题snow
,如果我们需要自定义主题,则只需要加载核心样式import "quill/dist/quill.core.css";
然后自定义设置其他样式。
quill 已经提供了两种主题:snow
和bubble
。上面已经展示主题snow
,bubble
是基于弹出提示的主题
import "quill/dist/quill.bubble.css";
editor = new Quill(root.value!, {
theme: "bubble",
});
工具栏不会直接展示在页面上,当你选中文本时弹出操作。双击时也会触发,因为编辑器内容末尾默认有一个\n
会被选中,从而实现交互。
配置工具栏
主题的定制更多是对工具栏的定义以及节点样式的调整。我们可以通过自定义modules.toolbar
来定义工具栏;定义css
来定义节点DOM的样式。自定义主题时,我们需要加载基本的样式
创建工具栏,我们可以在snow
主题基础上去配置,两种方式:一是配置定义toolbar
需要哪些内容格式的功能,罗列出来;还可以指定DOM节点,DOM元素内使用已经注册过的format
,也可以不用注册,自己管理DOM样式、事件,并通过API调用将自己处理过的格式应用到内容。
editor = new Quill(root.value!, {
modules: {
toolbar: [
{ font: [] },
{ size: [] },
"bold",
"italic",
{ list: "ordered" },
{ list: "bullet" },
{ list: "check" },
{ align: [] },
{ background: [] },
{ color: [] },
"table",
],
},
theme: "snow",
});
系统提供的formats
类型不一样,使用方式也不一样。对于一些属性bold \ italic
语义是与否,则直接罗列出来即可;而对于有选择的格式font \ size
等都需要配置选择的值。
要知道某个格式该怎么配置,区分节点Blots
还是属性Attributor
的实现,这是Parchment
提供的来个两种数据模型,实现方式不同,使用方式也不一致。通常属性Attributor
都是多值配置,而Blots
则取决于代码实现。
比如加粗bold
,继承自Inline
并重写了一些方法。静态方法formats
的实现标识它的值为boolean类型。
import Inline from '../blots/inline.js';
class Bold extends Inline {
static blotName = 'bold';
static tagName = ['STRONG', 'B'];
static create() {
return super.create();
}
static formats() {
return true;
}
optimize(context) {
super.optimize(context);
if (this.domNode.tagName !== this.statics.tagName[0]) {
this.replaceWith(this.statics.blotName);
}
}
}
export default Bold;
自定义size
quill
提供了这些格式默认的值,如果我们想自定义提供了一些值,比如size
替换掉原来的值.
editor = new Quill(root.value!, {
modules: {
toolbar: [
{ size: ['12px','14px','16px','18px'] },
],
},
theme: "snow",
});
改过之后发现下拉展示的内容并不对,但是查看元素时元素的data-value
绑定的值是对的,查看原来主题的css时,可以看到snow
主题是覆盖样式写的,那我们也加一下。
.ql-snow {
.ql-picker.ql-size {
.ql-picker-label::before {
content: attr(data-value);
}
.ql-picker-item {
&::before {
content: attr(data-value);
}
&[data-value="12px"]::before {
font-size: 12px;
}
&[data-value="14px"]::before {
font-size: 14px;
}
&[data-value="16px"]::before {
font-size: 16px;
}
&[data-value="18px"]::before {
font-size: 18px;
}
}
}
}
改完之后显示正常了,也可以正常切换了。但是在输入后切换字号,内容并没有追加对应的class
,按照逻辑不同的字号会有classql-size-${value}
这样的。
这里再处理完主题定义的默认值之外,我们去查看formats/size
的实现,发现它这里也定义了属性值。
好家伙,为啥要设置两次,不能从这里取吗。
为什么主题设置了到这里不生效,是因为Parchment.Attributor
定义了属性whitelist
不在其中的则会被忽略。
还好这里是两个实例,我们导入后进行修改。quill
要求不要直接修改导入的对象,会全局影响,一种做法是我们也创建相同的两个实例,把它覆盖掉,或者你不在意就直接修改吧。最后需要Quill.registerister
保证生效,不然会有输入上的问题。
import { SizeClass, SizeStyle } from "quill/formats/size";
SizeClass.whitelist = ["12px", "14px", "16px", "18px"];
SizeStyle.whitelist = ["12px", "14px", "16px", "18px"];
Quill.register(SizeStyle, true);
Quill.register(SizeClass, true);
修改完成后,再次进行编辑,可以看到生成的DOM结构是正常,我们还需自己书写这些class的样式。
.ql-snow{
.ql-editor {
.ql-size-12px {
font-size: 12px;
}
.ql-size-14px {
font-size: 14px;
}
.ql-size-16px {
font-size: 16px;
}
.ql-size-18px {
font-size: 18px;
}
}
}
好了,这样输入可以看到没有问题,但是我们自定义字体并没有设置默认值,也就是可以上图中第一行你好!
是随着系统默认大小,并不是12px
。可以初始化一个字号作为默认字体大小。
editor!.format("size", "12px");
但是如果你初始设置了14px
,初始默认显示还是12px
,当你输入后就会跳显示为14px
。这种配置方式没有发现怎么去设置默认值,但是可以通过另一种配置工具栏绑定DOM的方式解决。
<template>
<div class="rich-editor">
<div ref="toolbar">
<select class="ql-size">
<option value="12px">12px</option>
<option value="14px" selected>14px</option>
<option value="16px">16px</option>
<option value="18px">18px</option>
</select>
<button class="ql-bold"></button>
</div>
<div ref="root"></div>
</div>
</template>
<script setup lang="ts">
const root = ref<HTMLElement>();
const toolbar = ref<HTMLElement>();
onMounted(() => {
editor = new Quill(root.value!, {
modules: {
toolbar: {
container: toolbar.value!,
},
},
theme: "snow",
});
})
</script>
完美实现
这样就完美了,可以看到初始显示就是正常的。其他format可以通过button
的value
属性定义默认值;select
则可以通过option
的selected
设置默认值。
当然了,如果我们就想初始跟随系统字号,那么需要在定义值中加值为false
的选项,quill会添加一个空的option
表示,然后需要我们定义calss追加默认的显示名称,比如Normal
editor = new Quill(root.value!, {
modules: {
toolbar: [
{ size: ['12px',false,'14px','16px','18px'] },
],
},
theme: "snow",
});
这时工具栏上已经默认展示了值false
的空options
,但是由于它没有具体的值,之前设置的attr(data-value)
取不到值。进行调整修改,给一个默认的值
.ql-snow {
.ql-picker.ql-size {
.ql-picker-label {
&::before {
content: "Normal";
}
&[data-value="12px"]::before {
content: "12px";
}
&[data-value="14px"]::before {
content: "14px";
}
&[data-value="16px"]::before {
content: "16px";
}
&[data-value="18px"]::before {
content: "18px";
}
}
.ql-picker-item {
&::before {
content: "Normal";
}
&[data-value="12px"]::before {
content: "12px";
font-size: 12px;
}
&[data-value="14px"]::before {
content: "14px";
font-size: 14px;
}
&[data-value="16px"]::before {
content: "16px";
font-size: 16px;
}
&[data-value="18px"]::before {
content: "18px";
font-size: 18px;
}
}
}
}
这样就是书写的样式多了点,如果使用了一些其他的css库,可以动态生成的就能方便很多。比如使用了less,通过定义字体数组变量循环生成。
.ql-snow {
@font-sizes: 12px, 14px, 16px, 18px;
// 默认
@font-default: "Normal";
.generate-font-size(@sizes,@set-font:false) {
each(@sizes,{
@value: extract(@sizes,@index);
&[data-value="@{value}"]::before{
content:"@{value}"
}
&[data-value="@{value}"]::before when (@set-font){
font-size:@value;
}
});
}
.ql-editor {
each(@font-sizes,{
@value: extract(@font-sizes,@index);
.ql-size-@{value} {
font-size: @value;
}
});
}
.ql-picker.ql-size {
.ql-picker-label,
.ql-picker-item {
&::before {
content: @font-default;
}
}
.ql-picker-label {
.generate-font-size( @font-sizes);
}
.ql-picker-item {
.generate-font-size( @font-sizes,true);
}
}
}
ok,搞定了,这样针对其他默认的格式,如果我们需要自定义值,按照此方法进行调整即可。
😀enjoy it!