vue中使用vue-quill-editor富文本编辑器:自定义行高、选中后工具栏初始化
1、引入组件
<quill-editor ref="myQuillEditor" v-model="content" class="editor ql-editor" :options="editorOption" @blur="onEditorBlur($event)" @focus="onEditorFocus($event)" @change="onEditorChange($event)" @ready="ready($event)" />
// 工具栏配置 import { quillEditor } from 'vue-quill-editor' import { Uploads } from '@/api/hpms/qiniu' import 'quill/dist/quill.core.css' import 'quill/dist/quill.snow.css' import 'quill/dist/quill.bubble.css'
2、设置行高
//lineHeight.js import Quill from "quill"; const Parchment = Quill.import("parchment"); class lineHeightAttributor extends Parchment.Attributor.Style { } const lineHeightStyle = new lineHeightAttributor("lineHeight", "line-height", { scope: Parchment.Scope.INLINE, whitelist: ["1", "2", "3", "4", "5"] }); export { lineHeightStyle };
import { lineHeightStyle } from "./lineHeight";
ready() { Quill.register({ "formats/lineHeight": lineHeightStyle }, true) },
editorOption: { placeholder: '您想说点什么?', theme: 'snow', // or 'bubble' modules: { toolbar: { container: toolbarOptions, // container: "#toolbar", handlers: { lineHeight: (value) => { if (value) { const quill = this.$refs.myQuillEditor.quill quill.format("lineHeight", value); } } } } } },
3、行高样式
.ql-snow .ql-picker.ql-lineHeight .ql-picker-label::before { content: "行高"; } .ql-snow .ql-picker.ql-lineHeight .ql-picker-item[data-value="1"]::before,.ql-snow .ql-picker.ql-lineHeight .ql-picker-label[data-value="1"]::before { content: "行高1"; } .ql-snow .ql-picker.ql-lineHeight .ql-picker-item[data-value="1.5"]::before, .ql-snow .ql-picker.ql-lineHeight .ql-picker-label[data-value="1.5"]::before { content: "行高1.5"; } .ql-snow .ql-picker.ql-lineHeight .ql-picker-item[data-value="1.75"]::before,.ql-snow .ql-picker.ql-lineHeight .ql-picker-label[data-value="1.75"]::before { content: "行高1.75"; } .ql-snow .ql-picker.ql-lineHeight .ql-picker-item[data-value="2"]::before,.ql-snow .ql-picker.ql-lineHeight .ql-picker-label[data-value="2"]::before { content: "行高2"; } .ql-snow .ql-picker.ql-lineHeight .ql-picker-item[data-value="3"]::before,.ql-snow .ql-picker.ql-lineHeight .ql-picker-label[data-value="3"]::before { content: "行高3"; } .ql-snow .ql-picker.ql-lineHeight .ql-picker-item[data-value="4"]::before,.ql-snow .ql-picker.ql-lineHeight .ql-picker-label[data-value="4"]::before { content: "行高4"; } .ql-snow .ql-picker.ql-lineHeight .ql-picker-item[data-value="5"]::before ,.ql-snow .ql-picker.ql-lineHeight .ql-picker-label[data-value="5"]::before{ content: "行高5"; } .ql-snow .ql-picker.ql-lineHeight { width: 70px; }
4、效果图
5、完整代码
<template> <div> <!-- 图片上传组件辅助--> <el-upload v-show="false" class="avatar-uploader" action="/bmms/web-bm/file" name="img" accept=".jpg, .png" :show-file-list="false" :on-change="handleChange" :http-request="httpRequest" :before-upload="beforeUpload" /> <quill-editor ref="myQuillEditor" v-model="content" class="editor ql-editor" :options="editorOption" @blur="onEditorBlur($event)" @focus="onEditorFocus($event)" @change="onEditorChange($event)" @ready="ready($event)" /> </div> </template> <script> // 工具栏配置 import { quillEditor } from 'vue-quill-editor' import { Uploads } from '@/api/hpms/qiniu' import 'quill/dist/quill.core.css' import 'quill/dist/quill.snow.css' import 'quill/dist/quill.bubble.css' import ImageResize from 'quill-image-resize-module' import * as Quill from 'quill' import { lineHeightStyle } from "./lineHeight"; var Size = Quill.import('attributors/style/size') Size.whitelist = ['10px', '12px', '14px', '16px', '18px', '20px', '30px', '32px', '38px', '48px', '64px'] // 引入编辑器 Quill.register(Size, true) Quill.register('modules/imageResize', ImageResize) const toolbarOptions = [ ['bold', 'italic', 'underline', 'strike'], // 加粗 斜体 下划线 删除线 // ['blockquote', 'code-block'], // 引用 代码块 [{ header: 1 }, { header: 2 }], // 1、2 级标题 [{ list: 'ordered' }, { list: 'bullet' }], // 有序、无序列表 // [{ script: 'sub' }, { script: 'super' }], // 上标/下标 [{ indent: '-1' }, { indent: '+1' }], // 缩进 [{ size: Size.whitelist }], [{ 'align': [] }], [{ header: [1, 2, 3, 4, 5, 6, false] }], // 标题 [{ color: [] }, { background: [] }], // 字体颜色、字体背景颜色 ['clean'], // 清除文本格式 [{ lineHeight: lineHeightStyle.whitelist }], // 对齐方式 ['image'] // 链接、图片 ] const toolbarTips = [ { Choice: '.ql-bold', title: '加粗' }, { Choice: '.ql-italic', title: '倾斜' }, { Choice: '.ql-underline', title: '下划线' }, { Choice: '.ql-header', title: '段落格式' }, { Choice: '.ql-strike', title: '删除线' }, { Choice: '.ql-blockquote', title: '块引用' }, { Choice: '.ql-code-block', title: '插入代码段' }, { Choice: '.ql-size', title: '字体大小' }, { Choice: '.ql-list[value="ordered"]', title: '编号列表' }, { Choice: '.ql-list[value="bullet"]', title: '项目列表' }, { Choice: '.ql-header[value="1"]', title: 'h1' }, { Choice: '.ql-header[value="2"]', title: 'h2' }, { Choice: '.ql-align', title: '对齐方式' }, { Choice: '.ql-color', title: '字体颜色' }, { Choice: '.ql-background', title: '背景颜色' }, { Choice: '.ql-image', title: '图像' }, { Choice: '.ql-video', title: '视频' }, { Choice: '.ql-link', title: '添加链接' }, { Choice: '.ql-formula', title: '插入公式' }, { Choice: '.ql-clean', title: '清除格式' }, { Choice: '.ql-lineHeight', title: '设置行高' }, { Choice: '.ql-indent[value="-1"]', title: '向左缩进' }, { Choice: '.ql-indent[value="+1"]', title: '向右缩进' }, { Choice: '.ql-header .ql-picker-label', title: '标题大小' }, { Choice: '.ql-header .ql-picker-item[data-value="1"]', title: '标题一' }, { Choice: '.ql-header .ql-picker-item[data-value="2"]', title: '标题二' }, { Choice: '.ql-header .ql-picker-item[data-value="3"]', title: '标题三' }, { Choice: '.ql-header .ql-picker-item[data-value="4"]', title: '标题四' }, { Choice: '.ql-header .ql-picker-item[data-value="5"]', title: '标题五' }, { Choice: '.ql-header .ql-picker-item[data-value="6"]', title: '标题六' }, { Choice: '.ql-header .ql-picker-item:last-child', title: '标准' }, { Choice: '.ql-size .ql-picker-item[data-value="small"]', title: '小号' }, { Choice: '.ql-size .ql-picker-item[data-value="large"]', title: '大号' }, { Choice: '.ql-size .ql-picker-item[data-value="huge"]', title: '超大号' }, { Choice: '.ql-size .ql-picker-item:nth-child(2)', title: '标准' }, { Choice: '.ql-align .ql-picker-item:first-child', title: '居左对齐' }, { Choice: '.ql-align .ql-picker-item[data-value="center"]', title: '居中对齐' }, { Choice: '.ql-align .ql-picker-item[data-value="right"]', title: '居右对齐' }, { Choice: '.ql-align .ql-picker-item[data-value="justify"]', title: '两端对齐' } ] export default { components: { quillEditor }, props: { /* 编辑器的内容 */ value: { type: String, default: () => {} }, /* 图片大小 */ maxSize: { type: Number, default: 4000 // kb } }, data () { return { params: { token: '', FileName: '' }, content: this.value, quillUpdateImg: false, // 根据图片上传状态来确定是否显示loading动画,刚开始是false,不显示 editorOption: { placeholder: '您想说点什么?', theme: 'snow', // or 'bubble' modules: { imageResize: { displayStyles: { backgroundColor: 'black', border: 'none', color: 'white' }, modules: ['Resize', 'DisplaySize', 'Toolbar'] }, toolbar: { container: toolbarOptions, // container: "#toolbar", handlers: { image: function (value) { if (value) { // 触发input框选择图片文件 document.querySelector('.avatar-uploader input').click() } else { this.quill.format('image', false) } }, lineHeight: (value) => { if (value) { const quill = this.$refs.myQuillEditor.quill quill.format("lineHeight", value); } } // link: function(value) { // if (value) { // var href = prompt('请输入url'); // this.quill.format("link", href); // } else { // this.quill.format("link", false); // } // }, } } } }, serverUrl: this.UploadFile(), // 这里写你要上传的图片服务器地址 header: { // token: sessionStorage.token } // 有的图片服务器要求请求头需要有token } }, watch: { value (val) { this.content = this.value } }, // computed: { // content () { // return this.value // } // }, mounted () { for (let item of toolbarTips) { let tip = document.querySelector('.quill-editor ' + item.Choice) if (!tip) continue tip.setAttribute('title', item.title) } }, created () { // this.$nextTick(() => { // document.getElementById('self_typt-add-container').scrollTop = 0 // }) }, methods: { ready() { Quill.register({ "formats/lineHeight": lineHeightStyle }, true) }, UploadFile () { return '/bmms/web-bm/file' }, onEditorBlur () { // 失去焦点事件 }, onEditorFocus (val) { // 获得焦点事件 const quill = this.$refs.myQuillEditor.quill quill.format("lineHeight", 3); console.log('获得焦点事件----',lineHeightStyle.whitelist) }, onEditorChange () { // 内容改变事件 this.content = this.content.replace(/href=/g, '') this.$emit('input', this.content) }, cuFocus () { this.$nextTick(function () { document.getElementById('self_typt-add-container').scrollTop = 0 }) }, httpRequest (param) { const form = new FormData() form.append('file', param.file, param.file.name) Uploads(form).then(res => { if (res.status === 200) { const quill = this.$refs.myQuillEditor.quill // 如果上传成功 if (res.status === 200) { // 获取光标所在位置 const length = quill.getSelection().index // 插入图片 res.url为服务器返回的图片地址 quill.insertEmbed(length, 'image', res.data.urlPath) // 调整光标到最后 quill.setSelection(length + 1) } else { this.$message.error('图片插入失败') } // loading动画消失 this.quillUpdateImg = false } }) }, // 富文本图片上传前 beforeUpload (file) { // 显示loading动画 this.quillUpdateImg = true const filetype = file.name.slice( file.name.lastIndexOf('.'), file.name.length ) if (filetype === '.jpg' || filetype === '.png') { const isLt2M = file.size / 1024 / 1024 < 2 if (!isLt2M) { this.$message.error('上传文件大小不能超过 2MB!') return false } else { return true } } else { this.$message.error('请上传PNG,JPG格式文件') return false } }, handleChange (file, fileList) { var fileObj = file const form = new FormData() form.append('token', 'wnms') form.append('FileName', '44324') form.append('File', fileObj) } } } </script> <style lang="scss"> .ql-container{ >div:not(.ql-editor){ >div{ >span{ display: none !important; border:1px solid red !important; } } } } .editor { line-height: normal !important; height: 28rem; overflow: hidden; margin-top: -1vh; } .ql-container { overflow: auto; height: calc(100% - 50px); } .ql-editor { p{ img{ max-width: 100%; margin: auto ; display: block ; float: none !important; } } } .ql-snow .ql-editor,.ql-snow .ql-editor img { display: block; } .ql-snow .ql-tooltip[data-mode='link']::before { content: '请输入链接地址:'; } .ql-snow .ql-tooltip.ql-editing a.ql-action::after { border-right: 0px; content: '保存'; padding-right: 0px; } .ql-snow .ql-tooltip[data-mode='video']::before { content: '请输入视频地址:'; } .ql-snow .ql-picker.ql-header .ql-picker-label::before, .ql-snow .ql-picker.ql-header .ql-picker-item::before { content: '文本'; } .ql-snow .ql-picker.ql-header .ql-picker-label[data-value='1']::before, .ql-snow .ql-picker.ql-header .ql-picker-item[data-value='1']::before { content: '标题1'; } .ql-snow .ql-picker.ql-header .ql-picker-label[data-value='2']::before, .ql-snow .ql-picker.ql-header .ql-picker-item[data-value='2']::before { content: '标题2'; } .ql-snow .ql-picker.ql-header .ql-picker-label[data-value='3']::before, .ql-snow .ql-picker.ql-header .ql-picker-item[data-value='3']::before { content: '标题3'; } .ql-snow .ql-picker.ql-header .ql-picker-label[data-value='4']::before, .ql-snow .ql-picker.ql-header .ql-picker-item[data-value='4']::before { content: '标题4'; } .ql-snow .ql-picker.ql-header .ql-picker-label[data-value='5']::before, .ql-snow .ql-picker.ql-header .ql-picker-item[data-value='5']::before { content: '标题5'; } .ql-snow .ql-picker.ql-header .ql-picker-label[data-value='6']::before, .ql-snow .ql-picker.ql-header .ql-picker-item[data-value='6']::before { content: '标题6'; } .ql-toolbar { white-space: normal; } .ql-picker-item[data-value='10px']::before, .ql-picker-label[data-value='10px']::before { content: '10px' !important; } .ql-picker-item[data-value='12px']::before, .ql-picker-label[data-value='12px']::before { content: '12px' !important; } .ql-picker-item[data-value='14px']::before, .ql-picker-label[data-value='14px']::before { content: '14px' !important; } .ql-picker-item[data-value='16px']::before, .ql-picker-label[data-value='16px']::before { content: '16px' !important; } .ql-picker-item[data-value='18px']::before, .ql-picker-label[data-value='18px']::before { content: '18px' !important; } .ql-picker-item[data-value='20px']::before, .ql-picker-label[data-value='20px']::before { content: '20px' !important; } .ql-picker-item[data-value='24px']::before, .ql-picker-label[data-value='24px']::before { content: '24px' !important; } .ql-picker-item[data-value='30px']::before, .ql-picker-label[data-value='30px']::before { content: '30px' !important; } .ql-picker-item[data-value='32px']::before, .ql-picker-label[data-value='32px']::before { content: '32px' !important; } .ql-picker-item[data-value='38px']::before, .ql-picker-label[data-value='38px']::before { content: '38px' !important; } .ql-picker-item[data-value='48px']::before, .ql-picker-label[data-value='48px']::before { content: '48px' !important; } .ql-picker-item[data-value='64px']::before, .ql-picker-label[data-value='64px']::before { content: '64px' !important; } .ql-picker-item[data-value='72px']::before, .ql-picker-label[data-value='72px']::before { content: '72px' !important; } .ql-picker-item[data-value='36px']::before, .ql-picker-label[data-value='36px']::before { content: '36px' !important; } .ql-editor .ql-indent-1:not(.ql-direction-rtl){ text-indent: 2em; padding-left: 0; } .ql-editor .ql-indent-2:not(.ql-direction-rtl){ text-indent: 4em; padding-left: 0; } .ql-editor .ql-indent-3:not(.ql-direction-rtl){ text-indent: 6em; padding-left: 0; } .ql-editor .ql-indent-4:not(.ql-direction-rtl){ text-indent: 8em; padding-left: 0; } .ql-editor .ql-indent-5:not(.ql-direction-rtl){ text-indent: 10em; padding-left: 0; } .ql-editor .ql-indent-6:not(.ql-direction-rtl){ text-indent: 12em; padding-left: 0; } .ql-editor .ql-indent-7:not(.ql-direction-rtl){ text-indent: 14em; padding-left: 0; } .ql-editor .ql-indent-8:not(.ql-direction-rtl){ text-indent: 16em; padding-left: 0; } .ql-snow .ql-picker.ql-lineHeight .ql-picker-label::before { content: "行高"; } .ql-snow .ql-picker.ql-lineHeight .ql-picker-item[data-value="1"]::before,.ql-snow .ql-picker.ql-lineHeight .ql-picker-label[data-value="1"]::before { content: "行高1"; } .ql-snow .ql-picker.ql-lineHeight .ql-picker-item[data-value="1.5"]::before, .ql-snow .ql-picker.ql-lineHeight .ql-picker-label[data-value="1.5"]::before { content: "行高1.5"; } .ql-snow .ql-picker.ql-lineHeight .ql-picker-item[data-value="1.75"]::before,.ql-snow .ql-picker.ql-lineHeight .ql-picker-label[data-value="1.75"]::before { content: "行高1.75"; } .ql-snow .ql-picker.ql-lineHeight .ql-picker-item[data-value="2"]::before,.ql-snow .ql-picker.ql-lineHeight .ql-picker-label[data-value="2"]::before { content: "行高2"; } .ql-snow .ql-picker.ql-lineHeight .ql-picker-item[data-value="3"]::before,.ql-snow .ql-picker.ql-lineHeight .ql-picker-label[data-value="3"]::before { content: "行高3"; } .ql-snow .ql-picker.ql-lineHeight .ql-picker-item[data-value="4"]::before,.ql-snow .ql-picker.ql-lineHeight .ql-picker-label[data-value="4"]::before { content: "行高4"; } .ql-snow .ql-picker.ql-lineHeight .ql-picker-item[data-value="5"]::before ,.ql-snow .ql-picker.ql-lineHeight .ql-picker-label[data-value="5"]::before{ content: "行高5"; } .ql-snow .ql-picker.ql-lineHeight { width: 70px; } </style>