最近做項目有個富文本需求,選擇用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>
希望對你有用!