vue-quill-editor富文本编辑器结合elementui的 el-upload组件实现自定义上传附件(word文档)
第一步:下载依赖
npm install vue-quill-editor --save
第二步:引入到项目中,全局挂载 和 在组件中挂载,根据自己的项目需求选择(我做的是在组件中挂载)
全局挂载:main.js
import VueQuillEditor from 'vue-quill-editor'
Vue.use(VueQuillEditor);
import 'quill/dist/quill.core.css'
import 'quill/dist/quill.snow.css'
组件中挂载:
import { quillEditor } from 'vue-quill-editor'
import * as Quill from 'quill' //引入编辑器
import { addQuillTitle } from './quill-title.js' // 根据实际路径引入
import 'quill/dist/quill.core.css'
import 'quill/dist/quill.snow.css'
import 'quill/dist/quill.bubble.css'
第三步:我做的是在组件中挂载,所以我把文件放到components文件夹下(index.vue和quill-title.js这两个文件的代码我放到文章最后)
第四步:vue页面中的使用
页面展示样式:
index.vue
<template>
<div>
<el-upload
action=""
:limit="1"
:before-upload="beforeUpload"
:on-exceed="handleExceed"
:on-remove="handleRemove"
:on-success="handleSuccess"
accept=".doc,.docx"
:file-list="fileList"
:http-request="uploadFileApi"
:show-file-list="false"
ref="uploadRef"
class="uploadFile"
style="display: none;"
>
<i class="el-icon-plus"></i>
</el-upload>
<quill-editor
ref="myQuillEditor"
v-model="content"
:options="editorOption"
class="editor"
@blur="onEditorBlur($event)"
@focus="onEditorFocus($event)"
@change="onEditorChange($event)" />
</div>
</template>
<script>
import { quillEditor } from 'vue-quill-editor'
import * as Quill from 'quill' //引入编辑器
import { addQuillTitle } from './quill-title.js'
import 'quill/dist/quill.core.css'
import 'quill/dist/quill.snow.css'
import 'quill/dist/quill.bubble.css'
// 自定义字体
let fontFamily = ['宋体', '黑体', '微软雅黑', '楷体', '仿宋', 'Arial'];
Quill.imports['attributors/style/font'].whitelist = fontFamily;
Quill.register(Quill.imports['attributors/style/font']);
// 自定义字号
let fontSize = ['12px', '14px', '16px', '18px','20px', '22px', '24px','28px','32px', '36px']
Quill.imports['attributors/style/size'].whitelist = fontSize;
Quill.register(Quill.imports['attributors/style/size'])
// 自定义文件上传
let Link = Quill.import('formats/link');
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.setAttribute('download', value.innerText); // 左键点击即下载
node.innerText = value.innerText;
node.download = value.innerText;
}
return node;
}
}
FileBlot.blotName = 'link';
FileBlot.tagName = 'A';
Quill.register(FileBlot);
export default {
name: 'quillEditorPage',
props: {
editorContent: {
type: String
},
},
components: { quillEditor },
data() {
return {
content: this.editorContent,
// content: '我是富文本内容',
info: null,
// 工具栏配置
editorOption: {
theme: 'snow',
// bounds: document.body,
modules: {
toolbar: {
container: [
["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" }], // 缩进
// [{'direction': 'rtl'}], // 文本方向
[{ size: fontSize }], // 字体大小
// [{ size: ["small", false, "large", "huge"] }],
// [{ header: [1, 2, 3, 4, 5, 6, false] }], // 标题
[{ color: [] }], // 字体颜色、
[{ background: [] }], // 字体背景颜色
// [{ color: [] }, { background: [] }], // 字体颜色、字体背景颜色
[{ font: fontFamily }], // 字体种类
[{ align: [] }], // 对齐方式
["clean"], // 清除文本格式
// ['link',"image",'upload'], // 链接、图片、视频
['upload'],
// ['link']
],
handlers: {
upload: (value) => {
if (value) {
document.querySelector('.uploadFile .el-icon-plus').click()
}
},
// link: (value) => {
// if (value) {
// document.querySelector('.uploadFile .el-icon-plus').click()
// }
// }
},
}
},
placeholder: '请输入', //提示
},
fileList: [],
}
},
created() {},
mounted() {
addQuillTitle()
// 上传附件的图标
this.$el.querySelector(
'.ql-upload'
).innerHTML = `<svg t="1693300673548" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5709" xmlns:xlink="http://www.w3.org/1999/xlink" width="20" height="200"><path d="M224 601.6v185.6a12.8 12.8 0 0 0 12.8 12.8h550.4a12.8 12.8 0 0 0 12.8-12.8V601.6a25.6 25.6 0 0 1 25.6-25.6h12.8a25.6 25.6 0 0 1 25.6 25.6v224a38.4 38.4 0 0 1-38.4 38.4H198.4a38.4 38.4 0 0 1-38.4-38.4v-224a25.6 25.6 0 0 1 25.6-25.6h12.8a25.6 25.6 0 0 1 25.6 25.6z m315.152-427.696l160 160a25.6 25.6 0 0 1 0 36.192l-9.056 9.056a25.6 25.6 0 0 1-36.192 0l-104.448-104.416a3.2 3.2 0 0 0-5.456 2.256V614.4a25.6 25.6 0 0 1-25.6 25.6h-12.8a25.6 25.6 0 0 1-25.6-25.6V276.992a3.2 3.2 0 0 0-5.456-2.256l-104.448 104.416a25.6 25.6 0 0 1-36.192 0l-9.056-9.056a25.6 25.6 0 0 1 0-36.192l160-160a38.4 38.4 0 0 1 54.304 0z" fill="#000000" p-id="5710"></path></svg>`
},
computed: {},
watch: {},
methods: {
// 失去焦点事件
onEditorBlur (quill) {
// console.log(quill,'失去焦点事件------');
},
// 获得焦点事件
onEditorFocus (quill) {
// console.log(quill,'获得焦点事件------');
},
// 内容改变事件
onEditorChange ({quill, html, text}) {
console.log(quill, html, text, '内容改变事件------');
this.info = html
this.$emit('change', this.info)
},
beforeUpload (file) {},
handleExceed () {
this.$message.warning('每次只能上传一个文件!')
},
// 移除文件
handleRemove() {
this.fileList = [];
},
handleSuccess (res,file) {
this.$refs.uploadRef.clearFiles(); // 上传成功之后清除历史记录
},
async uploadFileApi (file) {
console.log(file,'file---------');
let fromData = new FormData();
fromData.append('file', file.file);
await testApi.uploadLabel(fromData).then((res) => { // 根据实际需求请求接口
if (res.code === 200) {
this.$message.success(res.message);
let fileNameLength = res.file.name.length
// 插入链接 获取富文本组件实例
let quill = this.$refs.myQuillEditor.quill
let length = quill.getSelection().index;
quill.insertEmbed(length, 'link', { href: res.msg, innerText: res.file.name }, "api")
// quill.insertEmbed(length, 'link', { href: res.data, innerText: file.name })
quill.setSelection(length + fileNameLength)
this.fileList = []
}
}).catch((e) => {
this.$message.error(e.message);
})
},
},
}
</script>
<style lang="scss" scoped>
::v-deep .editor {
line-height: normal !important;
.ql-editor {
min-height: 100px !important;
height: auto;
}
}
</style>
quill-title.js (可根据实际需求修改)
const titleConfig = {
'ql-bold': '加粗',
'ql-color': '颜色',
'ql-font': '字体',
'ql-code': '插入代码',
'ql-italic': '斜体',
'ql-link': '添加链接',
'ql-color':'字体颜色',
'ql-background': '背景颜色',
'ql-size': '字体大小',
'ql-strike': '删除线',
'ql-script': '上标/下标',
'ql-underline': '下划线',
'ql-blockquote': '引用',
'ql-header': '标题',
'ql-indent': '缩进',
'ql-list': '列表',
'ql-align': '文本对齐',
'ql-direction': '文本方向',
'ql-code-block': '代码块',
'ql-formula': '公式',
'ql-image': '图片',
'ql-video': '视频',
'ql-clean': '清除字体样式',
'ql-upload': '文件上传',
}
export function addQuillTitle () {
const oToolBar = document.querySelector('.ql-toolbar'),
aButton = oToolBar.querySelectorAll('button'),
aSelect = oToolBar.querySelectorAll('select')
aButton.forEach(function (item) {
if (item.className === 'ql-script') {
item.value === 'sub' ? item.title = '下标' : item.title = '上标'
} else if (item.className === 'ql-indent') {
item.value === '+1' ? item.title = '向右缩进' : item.title = '向左缩进'
} else if (item.className === 'ql-header') {
item.value === '1' ? item.title = '标题1' : item.title = '标题2'
} else if (item.className === 'ql-list') {
item.value === 'ordered' ? item.title = '有序列表' : item.title = '无序列表'
} else {
item.title = titleConfig[item.classList[0]]
}
})
aSelect.forEach(function (item) {
item.parentNode.title = titleConfig[item.classList[0]]
})
}