vue-quill-editor
注意: vue-quill-editor不兼容vue3版本
示例代码
<template>
<div>
<el-form :model="dynamicValidateForm" ref="dynamicValidateForm" label-width="100px" class="demo-dynamic">
<el-form-item
prop="from_official"
label="官网"
:rules="[
{ required: true, message: '请选择发布的官网', trigger: 'blur' },
]"
>
<el-select v-model="dynamicValidateForm.from_official" placeholder="请选择" width="50%">
<el-option
v-for="item in FROM_MAP"
:key="item"
:label="item"
:value="item">
</el-option>
</el-select>
</el-form-item>
<el-form-item
prop="language"
label="语言"
:rules="[
{ required: true, message: '请选择发布的语言', trigger: 'blur' },
]"
>
<el-select v-model="dynamicValidateForm.language" placeholder="请选择" width="50%">
<el-option
v-for="item in languageList"
:key="item"
:label="item"
:value="item">
</el-option>
</el-select>
</el-form-item>
<el-form-item
prop="title"
label="标题"
:rules="[
{ required: true, message: '请输入文章标题', trigger: 'blur' },
]"
>
<el-input v-model="dynamicValidateForm.title" placeholder="请输入文章标题"></el-input>
</el-form-item>
<el-form-item
prop="date"
label="日期"
:rules="[
{ required: true, message: '请输入文章发布日期', trigger: 'blur' },
]"
>
<el-input v-model="dynamicValidateForm.date" placeholder="请输入文章发布日期"></el-input>
</el-form-item>
<el-form-item
prop="picture"
label="封面"
:rules="[
{ required: true, message: '请输入封面图片url链接或者base64编码', trigger: 'blur' },
]"
>
<el-input v-model="dynamicValidateForm.picture" placeholder="请输入封面图片链接"></el-input>
<el-upload action="" :limit="1" :http-request="imgfileChange">上传</el-upload>
</el-form-item>
<el-form-item
prop="content"
label="正文"
:rules="[
{ required: true, message: '请编辑正文', trigger: 'blur' },
]"
>
<quill-editor
v-model="dynamicValidateForm.content"
:options="editorOption"
ref="myQuillEditor"
@change="onEditorChange($event)"
class="news-edit-util"></quill-editor>
<el-upload class="avatar-uploader" ref="imgUpload" action="" :limit="1" :http-request="fileChange"></el-upload>
</el-form-item>
<el-form-item>
<el-button @click="reviewEmail" icon="el-icon-message" style="margin-top: 20px;">预览</el-button>
<el-button type="primary" @click="submitForm('dynamicValidateForm')" :disabled="disabled">发布</el-button>
<el-button @click="resetForm('dynamicValidateForm')">重置</el-button>
<el-button type="primary" @click="backList">返回发布列表</el-button>
</el-form-item>
</el-form>
<el-drawer
title="正文预览"
size="50%"
:visible.sync="drawer"
:direction="direction"
>
<div v-html="dynamicValidateForm.content" class="previewContainer"></div>
</el-drawer>
<div class="linkDialog">
<el-input v-model="linkUrl.text" placeholder="请输入链接名称" style="width:200px"></el-input>
<el-input v-model="linkUrl.href" placeholder="请输入链接url" style="width:200px"></el-input>
<span slot="footer" class="dialog-footer">
<el-button @click="handleClose">取 消</el-button>
<el-button type="primary" @click="linkAdd">确 定</el-button>
</span>
</div>
</div>
</template>
<script>
import 'quill/dist/quill.core.css';
import 'quill/dist/quill.snow.css';
import 'quill/dist/quill.bubble.css';
import { quillEditor } from 'vue-quill-editor';
import Quill from 'quill'; //引入编辑器;
import { dashboardApi } from "@/api/index";
// 源码中是import直接倒入,这里要用Quill.import引入
const Link = Quill.import("formats/link");
// 自定义a链接
class FileBlot extends Link {
// 继承Link Blot
static create (value) {
let node = undefined;
if (value && !value.href) {
// 适应原本的Link Blot
node = super.create(value)
} else {
// 自定义Link Blot
node = super.create(value.href)
node.href = value.href
node.innerText = value.innerText
// node.setAttribute('download', value.innerText); // 左键点击即下载
}
return node;
}
}
FileBlot.blotName = "link" // 这里不用改,如果需要也可以保留原来的,这里用个新的blot
FileBlot.tagName = "A"
Quill.register(FileBlot) // 注册link
export default {
components: {
quillEditor
},
data() {
return {
content_id: this.$route.query.id,
type: this.$route.query.type,
FROM_MAP:['官网A','官网B','APP'],
languageList:['ZH','EN','FR'],
linkUrl:{
href:"",
text:""
},
dynamicValidateForm:{
from_official: '',
title:'',
date:'',
picture:'',
content:'',
language:'',
type:1,
},
dialogVisible:false,
drawer: false,
disabled:false,
direction: 'rtl',
editorOption: {
// 富文本编辑器选项
placeholder: '请输入文章正文内容,支持上传图片,视频',
theme: 'snow', //主题 snow/bubble
syntax: true, //语法检测
modules: {
toolbar: {
container:[ ['bold', 'italic', 'underline', 'strike'], // 加粗、斜体、下划线、删除线
['blockquote', 'code-block'], // 引用、代码块
[{ 'header': 1 }, { 'header': 2 }], // 标题
[{ 'list': 'ordered'}, { 'list': 'bullet' }], // 有序列表、无序列表
[{ 'script': 'sub'}, { 'script': 'super' }], // 下标、上标
[{ 'indent': '-1'}, { 'indent': '+1' }], // 缩进
[{ 'direction': 'rtl' }], // 文本方向
[{ 'size': ['small', false, 'large', 'huge'] }], // 字体大小
[{ 'header': [1, 2, 3, 4, 5, 6, false] }], // 标题大小
[{ 'color': [] }, { 'background': ['black'] }], // 文本颜色、背景颜色
[{ 'font': [] }], // 字体
[{ 'align': [] }], // 对齐方式
['clean'], // 清除格式
['link', 'image', 'video']// 链接、图片、视频
],
handlers: {
'image': function (value) {
if (value) {
// 触发input框选择图片文件
document.querySelector('.avatar-uploader input').click()
}
},
'link':function (value) {
if (value) {
document.querySelector('.linkDialog').style.display = 'block'
}
}
}
}
}
}
}
},
mounted() {
this.demand();
},
methods: {
// 值发生变化
onEditorChange(editor) {
console.log(editor.html);
},
fileChange(file) {
const reader = new FileReader();
reader.readAsDataURL(file.file)
reader.addEventListener('load', () => {
this.fileUpload(file.file.name, reader.result)
});
},
imgfileChange(file){
const reader = new FileReader();
reader.readAsDataURL(file.file)
reader.addEventListener('load', () => {
this.fileUpload(file.file.name, reader.result,'picture')
});
},
handleClose(){
document.querySelector('.linkDialog').style.display = 'none'
this.linkUrl = {}
},
linkAdd(){
const quill = this.$refs.myQuillEditor.quill;
// 获取光标所在位置
let length = quill.getSelection(true).index;
// 插入链接 res.info为服务器返回的图片地址
quill.insertEmbed(length, 'link',{ href: this.linkUrl.href, innerText: this.linkUrl.text }, "api" );
// 调整光标到最后
quill.setSelection(length + this.linkUrl.text.length);
this.handleClose()
},
async fileUpload(name, file,type) {
const params = {
upload_type: 0,
file: file,
filename: name
}
try {
let res = await dashboardApi.fileUpload(params)
if (res.code === 200) {
this.$message.success('上传成功!');
if(type&&type==='picture'){
this.dynamicValidateForm.picture = res.data.head_img
return
}
console.log(res.data)
const quill = this.$refs.myQuillEditor.quill;
// 获取光标所在位置
let length = quill.getSelection(true).index;
// 插入图片 res.info为服务器返回的图片地址
quill.insertEmbed(length, 'image', res.data.head_img);
// 调整光标到最后
quill.setSelection(length + 1)
} else {
this.$message.error(res.msg);
}
} catch (e) {
console.log(e)
this.$message.error('图片添加异常');
}
},
async demand() {
if(this.content_id && this.type === 2){
let res = await dashboardApi.getOfficialNewsList(
{id:this.content_id, current:1, size:1}
);
if (res.code === 200) {
const details = res.data.list[0]
this.dynamicValidateForm = {
from_official: details.from_official,
title:details.title,
date:details.date,
picture:details.picture,
content:details.content,
language:details.language,
}
} else {
this.$message.error(res.msg);
}
}
},
reviewEmail(){
this.drawer = true;
},
backList(){
this.$router.push({name: "websiteNewsList",});
},
submitForm(formName) {
this.$refs[formName].validate(async(valid) => {
if (valid) {
let params = this.dynamicValidateForm
if(this.content_id && this.type === 2){
params = {
...params,
id: this.content_id,
type: this.type
}
}
this.disabled = true
let res = await dashboardApi.getOfficialNewsData(params);
if (res.code === 200) {
this.$message.success('发布成功!');
}else{
this.$message.error(res.msg);
}
this.disabled = false
} else {
console.log('error submit!!');
return false;
}
});
},
resetForm(formName) {
this.$refs[formName].resetFields();
}
}
}
</script>
<style scoped>
.linkDialog{
width: fit-content;
position: fixed;
top:50%;
left:50%;
transform: translate(-50%,-50%);
background-color: #fff;
display: none;
}
</style>