引言
- 了解Quill模块是什么,怎么配置Quill模块
- 为什么要创建Quill模块,怎么创建自定义Quill模块
- Quill模块如何与Quill进行通信
- 深入了解Quill的模块化机制
Quill模块初探
1 var quill = new Quill('#editor',{
2 theme: 'snow'3 modules: {
4 toolbar: [['bold','italic'],['link','image']]
5 }
6 });
1 class Toolbar {
2 constructor(quill,options) {
3 // 解析传入模块的工具栏配置(就是前面介绍的二维数组),并渲染工具栏
4 5
6 addHandler(format,handler) {
7 this.handlers[format] = handler;
8 9 ...
10 }
- Clipboard 粘贴版
- History 操作历史
- Keyboard 键盘事件
- Syntax 语法高亮
- Toolbar 工具栏
- Uploader 文件上传
- 加粗的快捷键是Ctrl+B;
- 超链接的快捷键是Ctrl+K;
- 撤销/回退的快捷键是Ctrl+Z/Y。
modules: {
keyboard: {
3 bindings: {
strike: {
5 key: 'S' 6 ctrlKey: true 7 shiftKey: 8 handler: function(range,context) {
9 const format = this.quill.getFormat(range);
10 this.quill.format('strike',!format.strike);
11 }
12 },1)">13 }
14 },1)">15 toolbar: [['bold','italic','strike'],1)">16 }
创建自定义模块
class Counter {
2 3 console.log('quill:'4 console.log('options:'6 }
7
8 export default Counter;
toolbar: [
3 ['bold','italic'],1)">4 ['link',1)">]
],1)">6 counter: true
7 }
1 import Quill from 'quill';
2 import Counter from './counter'3 Quill.register('modules/counter',Counter);
constructor(quill,1)">2 this.container = quill.addContainer('ql-counter');
3 quill.on(Quill.events.TEXT_CHANGE,() => {
4 const text = quill.getText(); 获取编辑器中的纯文本内容
5 const char = text.replace(/\s/g,''); 使用正则表达式将空白字符去掉
6 this.container.innerHTML = `当前字数:${char.length}`;
7 });
8 }
模块加载机制
1 constructor(container,options = {}) {
2 this.options = expandConfig(container,options); 扩展配置数据,包括增加主题类等
4 this.theme = new this.options.theme(this,this.options); 1.使用options中的主题类初始化主题实例
6 2.增加必需模块
7 this.keyboard = this.theme.addModule('keyboard' 8 this.clipboard = this.theme.addModule('clipboard' 9 this.history = this.theme.addModule('history'10
11 this.theme.init(); 3.初始化主题,这个方法是模块渲染的核心(实际的核心是其中调用的addModule方法),会遍历配置的所有模块类,并将它们渲染到DOM中
...
13 }
init() {
遍历Quill options中的modules参数,将所有用户配置的modules挂载到主题类中
3 Object.keys(this.options.modules).forEach(name =>4 if (this.modules[name] == null) {
5 .addModule(name);
8 }
addModule(name) {
2 const module = super.addModule(name);
3 if (name === 'toolbar'.extendToolbar(module);
6 return module;
7 }
2 const ModuleClass = this.quill.constructor.import(`modules/${name}`); // 导入模块类,创建自定义模块的时候需要通过Quill.register方法将类注册到Quill,才能导入
初始化模块类
4 this.modules[name] = new ModuleClass(
5 .quill,1)">this.options.modules[name] || {},1)"> );
8 return .modules[name];
9 }
super(quill,1)"> 4
5 解析modules.toolbar参数,生成工具栏结构
6 if (Array.isArray(.options.container)) {
7 const container = document.createElement('div' 8 addControls(container,1)">.options.container);
quill.container.parentNode.insertBefore(container,quill.container);
10 this.container = container;
11 } else ...
14
15 this.container.classList.add('ql-toolbar'16
17 绑定工具栏事件
18 this.controls = [];
19 this.handlers = {};
20 Object.keys(this.options.handlers).forEach(format =>21 this.addHandler(format,1)">.options.handlers[format]);
22 });
23 Array.from(this.container.querySelectorAll('button,select')).forEach(
24 input =>25 .attach(input);
26 27 );
28 ...
29 30 }
addControls(container,groups) {
2 if (!Array.isArray(groups[0])) {
3 groups = [groups];
}
5 groups.forEach(controls => 6 const group = document.createElement('span' 7 group.classList.add('ql-formats' 8 controls.forEach(control => 9 typeof control === 'string'10 addButton(group,control);
12 const format = Object.keys(control)[0];
13 const value = control[format];
14 if (Array.isArray(value)) {
15 addSelect(group,format,value);
16 } 17 addButton(group,1)">18 }
19 20 21 container.appendChild(group);
});
23 }
- 模块加载的起点是Theme类的init方法,该方法将option.modules参数里配置的所有模块加载到主题类的成员变量modules中,并与内置必需模块合并;
- addModule方法会先通过import方法导入模块类,然后通过new关键字创建模块实例;
- 创建模块实例时会执行模块的初始化方法,执行模块的具体逻辑。
总结
加入我们