vue-quill-editor的使用
最近做项目有个富文本需求,选择用vue-quill-editor,有些个性化设置,在这里记录一下:
功能描述:点击内容,展示富文本,保存后展示文本(如下图):
编辑时候:
提交后变成查看状态:
技术点有一下几个:
1.toolbar个性化设置(字体大小设置item为自定义字体、自定义了一个工作汇报标签,实现点击展示弹窗效果)
实现方法主要是toolbar设置和样式得处理:具体代码入下:
toolbar设置:
//toolbarOptions配置 export const toolbarOptions = [ ['bold', 'italic', 'underline', 'strike'], // 加粗,倾斜,下划线,删除线 ['blockquote', 'code-block'], // 引号,代码 [{ list: 'ordered' }, { list: 'bullet' }], // 有序列表,无序列表 [{ indent: '-1' }, { indent: '+1' }], // 左移,右移 [{ direction: 'rtl' }], // 左右对齐 [{ size: [false, '10px', '14px', '16px', '18px', '20px', '24px'] }], // 字体大小 [{ header: [1, 2, 3, 4, 5, false] }], // 标题大小 [{ color: [] }, { background: [] }], // 文字颜色,文字背景 [{ font: ['SimSun', 'SimHei', 'Microsoft-YaHei', 'KaiTi', 'FangSong', 'Arial', 'Times-New-Roman', 'sans-serif'] }], // 字体风格 [{ align: [] }], // 对齐方式 ['image', 'link', 'clean', 'report']// 图片,链接,清除,自定义行为 ] //在quill中使用 toolbar: { container: toolbarOptions, handlers: { report: this.openWorkReport } }
css配合(全部样式,可以直接复制使用):
/* 字体风格 */ .ql-snow .ql-picker.ql-font .ql-picker-label[data-value='SimSun']::before, .ql-snow .ql-picker.ql-font .ql-picker-item[data-value='SimSun']::before { content: '宋体'; font-family: 'SimSun'; } .ql-snow .ql-picker.ql-font .ql-picker-label[data-value='SimHei']::before, .ql-snow .ql-picker.ql-font .ql-picker-item[data-value='SimHei']::before { content: '黑体'; font-family: 'SimHei'; } .ql-snow .ql-picker.ql-font .ql-picker-label[data-value='Microsoft-YaHei']::before, .ql-snow .ql-picker.ql-font .ql-picker-item[data-value='Microsoft-YaHei']::before { content: '微软雅黑'; font-family: 'Microsoft YaHei'; } .ql-snow .ql-picker.ql-font .ql-picker-label[data-value='KaiTi']::before, .ql-snow .ql-picker.ql-font .ql-picker-item[data-value='KaiTi']::before { content: '楷体'; font-family: 'KaiTi'; } .ql-snow .ql-picker.ql-font .ql-picker-label[data-value='FangSong']::before, .ql-snow .ql-picker.ql-font .ql-picker-item[data-value='FangSong']::before { content: '仿宋'; font-family: 'FangSong'; } .ql-snow .ql-picker.ql-font .ql-picker-label[data-value='Arial']::before, .ql-snow .ql-picker.ql-font .ql-picker-item[data-value='Arial']::before { content: 'Arial'; font-family: 'Arial'; } .ql-snow .ql-picker.ql-font .ql-picker-label[data-value='Times-New-Roman']::before, .ql-snow .ql-picker.ql-font .ql-picker-item[data-value='Times-New-Roman']::before { content: 'Times New Roman'; font-family: 'Times New Roman'; } .ql-snow .ql-picker.ql-font .ql-picker-label[data-value='sans-serif']::before, .ql-snow .ql-picker.ql-font .ql-picker-item[data-value='sans-serif']::before { content: 'sans-serif'; font-family: 'sans-serif'; } .ql-font-SimSun { font-family: 'SimSun'; } .ql-font-SimHei { font-family: 'SimHei'; } .ql-font-Microsoft-YaHei { font-family: 'Microsoft YaHei'; } .ql-font-KaiTi { font-family: 'KaiTi'; } .ql-font-FangSong { font-family: 'FangSong'; } .ql-font-Arial { font-family: 'Arial'; } .ql-font-Times-New-Roman { font-family: 'Times New Roman'; } .ql-font-sans-serif { font-family: 'sans-serif'; } /* 字体大小 */ .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="false"]::before{ content: 'Normal'; } .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="10px"]::before{ content: '10px'; } .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="10px"]::before { content: '10px'; font-size: 10px; } .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="14px"]::before{ content: '14px'; } .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="14px"]::before { content: '14px'; font-size: 14px; } .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="16px"]::before{ content: '16px'; } .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="16px"]::before { content: '16px'; font-size: 16px; } .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="18px"]::before { content: '18px'; } .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="18px"]::before { content: '18px'; font-size: 18px; } .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="20px"]::before{ content: '20px'; } .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="20px"]::before { content: '20px'; font-size: 20px; } .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="24px"]::before{ content: '24px'; } .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="24px"]::before { content: '24px'; font-size: 24px; } /* 段落大小 */ .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"]::before { content: '标题1'; } .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"]::before { content: '标题2'; } .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"]::before { content: '标题3'; } .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"]::before { content: '标题4'; } .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"]::before { content: '标题5'; } .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="false"]::before { content: '正常'; } /* 默认设置 */ .ql-snow .ql-editor{ font-size: 14px; } /* 查看样式 */ .view-editor .ql-toolbar{ display: none; } .view-editor .ql-container.ql-snow{ border: 0; } .view-editor .ql-container.ql-snow .ql-editor{ padding: 0; } /* 编辑样式 */ .edit-editor .ql-toolbar{ display: block; } .edit-editor .ql-container.ql-snow{ border: 1px solid #ccc; min-height: inherit; } /* 自定义toobar样式设计 */ /* 工作汇报弹窗 */ .ql-snow.ql-toolbar .ql-formats .ql-report{ background: url("../images/meeting/report.png") no-repeat; background-size: contain; display: inline-block; height: 18px; margin: 3px 5px; width: 28px; }
2.实现@或者#用户功能,js实现代码入下:
// 1.引入mention 组件 import mention from 'quill-mention' //2.在quill potion配置入下: // mentionList需要格式化为{id, value}形式 modules: { mention: { allowedChars: /^[A-Za-z\sÅÄÖåäö]*$/, source: (searchTerm, renderList) => { renderList(this.mentionList, searchTerm) }, onSelect: (data, insertItem) => { insertItem(data) this.onSelectd() }, mentionDenotationChars: ['@', '#'] } }
最后给出完整得vue配置:
<template> <div @click="$emit('click')" :class="readonly?'view-editor':'edit-editor'" > <quill-editor v-model="content" :disabled="readonly" :options="editorOption" @change="onEditorChange($event)" :style="{minHeight:readonly?'0':minHeigh+'px'}" > </quill-editor> </div> </template> <script> import Quill from 'quill' import { quillEditor } from 'vue-quill-editor' import { ImageDrop } from 'quill-image-drop-module' import ImageResize from 'quill-image-resize-module' import mention from 'quill-mention' // 引入mention 组件 import 'quill/dist/quill.core.css' import 'quill/dist/quill.snow.css' import 'quill/dist/quill.bubble.css' import { fontSize, fonts, toolbarOptions } from './config' Quill.register('modules/imageDrop', ImageDrop) Quill.register('modules/imageResize', ImageResize) Quill.register('modules/mention', mention) const Size = Quill.import('attributors/style/size') Size.whitelist = fontSize Quill.register(Size, true) const Font = Quill.import('formats/font') Font.whitelist = fonts Quill.register(Font, true) export default { name: 'index', components: { quillEditor }, props: { readonly: { type: Boolean, default: false }, value: { type: String, default: '' }, minHeigh: { type: Number, default: 200 }, isPushContent: { type: Boolean, default: false }, mentionList: { // @功能 type: Array, default: () => { // 数据源(遍历成{id, value}形式) return [] } } }, data () { return { flag: true, content: '', editorOption: { placeholder: '请输入', theme: 'snow', modules: { mention: { allowedChars: /^[A-Za-z\sÅÄÖåäö]*$/, source: (searchTerm, renderList) => { renderList(this.mentionList, searchTerm) }, onSelect: (data, insertItem) => { // const item = { text: `@${data.value}`, name: data.value, id: data.id } insertItem(data) this.onSelectd() }, mentionDenotationChars: ['@', '#'] }, imageDrop: true, imageResize: {}, toolbar: { container: toolbarOptions, handlers: { report: this.openWorkReport } } } }, replyTo: '' } }, watch: { value: { handler (val) { this.content = val }, immediate: true } }, methods: { onSelectd () { this.replyTo = this.mentionList .reduce((acc, cur) => { if (this.content.includes(cur.value)) { acc.push(cur.id) } return acc }, []) .toString() }, getEditorValue () { return this.content }, openWorkReport () { this.$emit('openWorkReport') }, setEditorValue (content = '') { this.content = content }, onEditorChange ({ quill, html, text }) { this.content = html this.$emit('input', this.content) this.$emit('change', this.content) } } } </script> <style> @import '~@assets/css/font.css'; </style>
希望对你有用!