淘先锋技术网

首页 1 2 3 4 5 6 7

vue-quill-editor:基于 Quill、适用于 Vue 的富文本编辑器,支持服务端渲染和单页应用。
quill中文文档:https://www.kancloud.cn/liuwave/quill/1409423

实现功能是点击文本区域后,点击表情可以在对应位置插入表情图标。这里用不到插件自带的工具栏,所以隐藏掉了,效果图:
在这里插入图片描述

安装

引入

import { quillEditor } from 'vue-quill-editor'
import 'quill/dist/quill.core.css'
import 'quill/dist/quill.snow.css'
import 'quill/dist/quill.bubble.css'

页面使用

<quill-editor
   ref="editor"
   v-model="form.name"
   :options="editorOption"
   @focus="onEditorFocus"
   @change="onEditorChange"
>
</quill-editor>
// 字数限制
<div class="textLength">{{ text.length + ' / ' + text.maxLength }}</div>

定义下变量

quill: null, //编辑器实例
//options:编辑器配置项,配置插件工具栏等
editorOption: { 
  modules: {
     toolbar: [], 
  },
  placeholder: '',
},
// focus下标
index: -1, 
text: {
   length: 0, // 当前字符长度
   maxLength: 200, // 最大字符长度
},

加载完成后,先拿到编辑器实例,监听页面点击事件。

this.quill = this.$refs.editor.quill
document.addEventListener('click', this.handleClick)

总的思路就是获取 focus 索引下标 index,调用编辑器的 insertEmbed方法插入图片。
insertEmbed(index: Number, type: String, value: any, source: String = ‘api’): Delta

看文档时原本打算使用selection-change时事件,鼠标点击文本区域后触发,可以拿到下标index,但是还有个隐藏需求(点击其他空白区域,再点击表情,不能插入图片),在加载完后还监听了页面点击事件,selection-change触发后,发现页面点击事件监听不到,估计是插件给阻止了,因此弃用。

监听插件focus事件,拿到下标index

onEditorFocus(editor) {
   this.index = editor.selection.savedRange.index
},

监听文本变化,拿到下标值跟文本内容,这里将图片当成1个字符,拿到html内容后匹配img次数。长度大于最大长度时,调用插件deleteText方法删除超出部分。

onEditorChange(editor) {
  this.index = editor.quill.selection.savedRange.index
  
  let img = editor.html.match(/<img/g)
  this.text.length = editor.text.replace(/\n/g, '').length + (img ? img.length : 0)
  if (this.text.length > this.text.maxLength) {
     this.quill.deleteText(this.text.maxLength, 1)
  }
},

监听页面点击事件时,判断点击了除编辑器跟表情时,将Index置为-1

handleClick(e) {
      if (e.path.find(i => i.className === 'ql-container ql-snow') || e.target.className === 'emoji-item') {
        return
      }
      this.index = -1
},

点击表情,判断Index,调用insertEmbed插入图片

addEmoji(data) {
    if (this.index !== -1) {
        this.quill.insertEmbed(this.index, 'image', data.img)
    }
},