现代富文本编辑器Quill的模块化机制

前端开发 作者: 2024-08-20 13:20:01
通过阅读本文,你将收获: 1. 了解Quill模块是什么,怎么配置Quill模块 2. 为什么要创建Quill模块,怎么创建自定义Quill模块 3. Quill模块如何与Quill进行通信 4. 深

引言

  1. 了解Quill模块是什么,怎么配置Quill模块
  2. 为什么要创建Quill模块,怎么创建自定义Quill模块
  3. Quill模块如何与Quill进行通信
  4. 深入了解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 }
  1. Clipboard 粘贴版
  2. History 操作历史
  3. Keyboard 键盘事件
  4. Syntax 语法高亮
  5. Toolbar 工具栏
  6. Uploader 文件上传
  1. 加粗的快捷键是Ctrl+B;
  2. 超链接的快捷键是Ctrl+K;
  3. 撤销/回退的快捷键是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 }
{
6 }
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 }
  1. 模块加载的起点是Theme类的init方法,该方法将option.modules参数里配置的所有模块加载到主题类的成员变量modules中,并与内置必需模块合并;
  2. addModule方法会先通过import方法导入模块类,然后通过new关键字创建模块实例;
  3. 创建模块实例时会执行模块的初始化方法,执行模块的具体逻辑。

总结

加入我们

原创声明
本站部分文章基于互联网的整理,我们会把真正“有用/优质”的文章整理提供给各位开发者。本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
本文链接:http://www.jiecseo.com/news/show_65533.html