Vue-VEditor(富文本)
组件代码:
<!-- 富文本组件,使用说明见README.md-->
<template>
<div class='YxkEditor'>
<!-- 富文本 -->
<template>
<div :class="[{'YxkEditor__noToolbar': params.hideToolbar}]">
<quill-editor v-bind="editorBind(editorObj)" @change="change($event)" @focus="focus($event)"
@blur="blur($event)">
</quill-editor>
</div>
</template>
<!-- 富文本字数统计 -->
<template>
<div v-if="params.size" class="YxkEditor__size">{{params.length}}/{{params.size}}</div>
</template>
<!-- 富文本图片/视频上传 -->
<template>
<YxkUpload v-if="!params.disabledUpload" :uploadObj="uploadBind(uploadObj)" ref="YxkEditor_upload"
@change="changeUrl"></YxkUpload>
</template>
</div>
</template>
<script>
import {
quillEditor
} from "vue-quill-editor"
import "quill/dist/quill.snow.css"
export default {
name: 'YxkEditor',
props: {
editorObj: {
type: Object
},
uploadObj: {
type: Object
}
},
components: {
quillEditor
},
data() {
return {
params: { // 参数
times: 0, // 防止字数统计错误
length: 0, // 富文本输入字数
size: 0, // 字数限制
readOnly: '', // 只读
hideToolbar: '', // 隐藏工具栏
disabledUpload: '', // 禁止上传
},
defaultToolbar: [], // 默认工具栏
}
},
methods: {
// 富文本事件
change(e) { // change
// 字数限制
this.sizeSet(e)
this.$emit("change", {
...e,
length: e.quill.getLength() - 1
})
},
focus(e) { // 获取焦点
this.$emit('focus', {
...e
})
},
blur(e) { // 失去焦点
this.$emit('blur', {
...e
})
},
// 上传图片、视频
uploadBind(obj) {
return Object.assign({
size: 60,
clearFiles: true,
accept: '.png,.jpg,.gif,.mp4'
}, obj)
},
changeUrl(obj) {
obj.uploadUrl.forEach((item, index) => {
let video = obj.fileList[index].name.indexOf('.mp4') != -1
this.imageSet(item.url, video)
})
},
editorUpload() {
if (this.params.readOnly || this.params.disabledUpload) return false
document.querySelector(".YxkEditor .el-icon-plus").click()
},
// 插入视频、图片
imageSet(url, video) {
let quill = this.$refs.YxkEditor.quill;
let length = quill.getSelection().index;
quill.insertEmbed(length, `${video ? 'video' : 'image'}`, url)
quill.setSelection(length + 1)
},
// 字数限制
sizeSet(e) {
this.params.length = e.quill.getLength() - 1
if (this.params.size) {
if (this.params.length > this.params.size) {
e.quill.deleteText(this.params.size, 100000)
}
}
},
// 参数设置
paramsSet(obj) {
this.params.size = obj.size ? Number(obj.size) : 0
this.params.readOnly = obj.readOnly
this.params.hideToolbar = obj.hideToolbar
this.params.disabledUpload = obj.disabledUpload
// 字数统计
if (!this.params.times) {
if (obj.size && obj.content !== undefined) {
this.params.length = obj.content.length
}
this.params.times += 1
}
// 是否只读
if (this.$refs[obj.ref]) {
if (obj.readOnly) {
this.$refs[obj.ref].quill.enable(false)
} else {
this.$refs[obj.ref].quill.enable(true)
}
this.sizeSet(this.$refs[obj.ref])
}
},
// 富文本设置
editorSet(obj) {
let quillRef = this.$refs[obj.ref]
if (quillRef) {
quillRef.quill.clipboard.addMatcher("IMG", // 剪切板删除img
function () {
return {
ops: []
};
}
)
}
},
// 配置项
editorBind(params) {
let obj = JSON.parse(JSON.stringify(params)) || {}
let dataBind = {
ref: 'YxkEditor',
options: { // 富文本配置项
theme: 'snow',
placeholder: '请输入...',
modules: {
toolbar: {
container: this.defaultToolbar,
handlers: {
image: (val) => {
if (val) {
this.editorUpload()
} else {
this.quill.format("image", false)
}
}
}
}
}
}
}
if (obj.options) {
dataBind.options = Object.assign({}, obj.options, dataBind.options)
}
if (obj.modules) {
if (obj.modules.toolbar) {
Object.assign(dataBind.modules.toolbar, obj.modules.toolbar)
}
Object.assign(dataBind.modules, obj.modules)
delete obj.modules
}
Object.assign(dataBind, obj)
this.paramsSet(dataBind)
this.editorSet(dataBind)
return dataBind
},
// 初始化
initialSet() {
this.defaultToolbar = [ // 工具栏
['bold', 'italic', 'underline', 'strike'], //加粗,斜体,下划线,删除线
['blockquote'], //引用,代码块
[{
'list': 'ordered'
}, {
'list': 'bullet'
}], //列表
[{
'indent': '-1'
}, {
'indent': '+1'
}], // 缩进
[{
'size': ['small', false, 'large']
}], // 字体大小
[{
'color': ['#FFFFFF', '#333333', '#666666', '#999999']
}], // 字体颜色,字体背景颜色
[{
'align': []
}], //对齐方式
['clean'], //清除字体样式
['image', 'link'] //上传图片、上传视频
]
}
},
computed: {},
watch: {},
created() {
this.initialSet()
},
mounted() {}
}
</script>
<style lang='scss'>
.YxkEditor {
position: relative;
.YxkUpload {
width: 0;
height: 0;
overflow: hidden;
opacity: 0 !important;
}
.YxkEditor__size {
position: absolute;
right: 15px;
bottom: 5px;
color: #999;
}
.YxkEditor__noToolbar {
.ql-toolbar {
display: none;
}
}
.ql-picker.ql-size {
.ql-picker-label::before,
.ql-picker-item::before {
content: "14px";
}
.ql-picker-label[data-value="small"]::before,
.ql-picker-item[data-value="small"]::before {
content: "12px";
}
.ql-picker-label[data-value="large"]::before,
.ql-picker-item[data-value="large"]::before {
content: "16px";
}
}
.quill-editor {
.ql-container {
height: 300px;
border-top: #ccc solid 1px !important;
}
.ql-toolbar {
border-bottom: none;
button,
.ql-size,
.ql-color,
.ql-align {
position: relative;
&::after {
content: '';
position: absolute;
bottom: -20px;
left: 10%;
display: none;
width: 80px;
color: #000;
font-size: 12px;
line-height: 12px;
padding: 3px 2px;
text-align: center;
border: #999 solid 1px;
background: #fff;
transform: translateX(-50%);
}
&:hover {
&::after {
display: block;
}
}
}
.ql-bold {
&::after {
content: '加粗';
}
}
.ql-italic {
&::after {
content: '斜体';
}
}
.ql-underline {
&::after {
content: '下划线';
}
}
.ql-strike {
&::after {
content: '删除线';
}
}
.ql-blockquote {
&::after {
content: '引用';
}
}
.ql-list {
&:first-child {
&::after {
content: '有序列表';
}
}
&:last-child {
&::after {
content: '无序列表';
}
}
}
.ql-indent {
&:first-child {
&::after {
content: '向左缩进';
}
}
&:last-child {
&::after {
content: '向右缩进';
}
}
}
.ql-picker {
.ql-picker-label {
display: flex;
}
}
.ql-size {
width: 60px;
&::after {
content: '字体大小';
}
}
.ql-color {
&::after {
content: '字体颜色';
}
}
.ql-align {
&::after {
content: '对齐方式';
}
}
.ql-clean {
&::after {
content: '清除样式';
}
}
.ql-image {
&::after {
content: '图片/视频';
}
}
.ql-link {
&::after {
content: '添加链接';
}
}
}
}
.quill-editor {
box-shadow: none;
}
}
</style>
示例:

参数说明:



浙公网安备 33010602011771号