如何下载引入就不说了,自行百度。
这个默认上传图片是将图片转为了base64了,所以在上传图片后,将数据传给后端时,数据过大,导致各种报错问题, 还有它也可以直接粘贴图片进去也是base64, 这里将上传图片更改为上传到自己服务器上,返回的是一个地址,这就方便多了。
直接开始:
先说组件结构:
index.vue 就是组件 ,修改 粘贴图片上传在这个里面
quillConfig.js 是富文本的配置项 修改点击图片上传在这个里面
代码 :
index.vue
<template>
<quill-editor ref="myTextEditor" class="editorBox" :options='editorOption' v-model="data" :style="{'height':height+'px', marginBottom: marginB+'px'}" :disabled='disabled'></quill-editor>
</template>
<script>
import { Quill } from "vue-quill-editor";
import 'quill/dist/quill.core.css';
import 'quill/dist/quill.snow.css';
import 'quill/dist/quill.bubble.css';
import quillConfig from './quillConfig';
import { getToken } from "@/utils/auth";
export default {
components: {
},
props: {
value: String,//绑定的值,在组件上使用 v-model 绑定一个值
// 高度设置
height: {
type: [Number, String],
default: 240
},
// 下边距距离
marginB: {
type: [Number, String],
default: 10
},
disabled: {
type: Boolean,
default: false
}
},
model: {
prop: 'value',
event: 'change'
},
data() {
return {
data: '',//富文本绑定的值
editorOption: quillConfig
};
},
computed: {
},
created() {
},
watch: {
value: {
handler(newVal) {
if (newVal) {
this.data = newVal;
}
},
deep: true,
immediate: true
},
data(newVal) {
this.$emit('change', newVal)
},
disabled: {
handler(newVal) {
if (newVal) {
this.$nextTick(() => {
var father = document.getElementsByClassName('editorBox')[0];
var children = document.getElementsByClassName('ql-toolbar')[0];
father.removeChild(children)
})
}
},
deep: true,
immediate: true,
},
},
methods: {
// 自定义粘贴图片功能
init() {
let quill = this.$refs.myTextEditor.quill;
quill.root.addEventListener('paste', evt => {
if (evt.clipboardData && evt.clipboardData.files && evt.clipboardData.files.length) {
evt.preventDefault();
[].forEach.call(evt.clipboardData.files, file => {
if (!file.type.match(/^image\/(gif|jpe?g|a?png|bmp)/i)) {
return
}
this.uploadToServer(file)
})
}
}, false)
},
// 修改粘贴图片为上传到服务器
uploadToServer(file) {
const uploadConfig = {
action: process.env.VUE_APP_BASE_API + "/common/upload", // 必填参数 图片上传地址
methods: 'POST', // 必填参数 图片上传方式
token: "Bearer " + getToken(), // 可选参数 如果需要token验证,假设你的token有存放在sessionStorage
name: 'file', // 必填参数 文件的参数名
};
var xhr = new XMLHttpRequest()
var formData = new FormData()
formData.append(uploadConfig.name, file)
xhr.open(uploadConfig.methods, uploadConfig.action, true);
xhr.setRequestHeader("Authorization", uploadConfig.token); //设置请求头
xhr.send(formData)
let quill = this.$refs.myTextEditor.quill;
// 上传数据成功,会触发
xhr.onload = function (res) {
if (xhr.status === 200) {
var res = JSON.parse(xhr.responseText);
let length = quill.getSelection(true).index;
//这里很重要,你图片上传成功后,img的src需要在这里添加,res.path就是你服务器返回的图片链接。
quill.insertEmbed(length, 'image', res.data);
quill.setSelection(length + 1)
}
};
// 上传数据完成(成功或者失败)时会触发
xhr.upload.onerror = function (e) {
this.$message.error('图片上传失败');
};
},
},
mounted() {
this.init();
//修改富文本设置字体大小
let fontSizeStyle = Quill.import('attributors/style/size') //引入这个后会把样式写在style上
fontSizeStyle.whitelist = ['13px', '16px', '18px', '20px', '30px', '40px', '50px', '60px']
Quill.register(fontSizeStyle, true)
//设置字体样式
let Font = Quill.import('attributors/style/font') //引入这个后会把样式写在style上
let fonts = [false, 'Microsoft-YaHei', 'SimSun', 'SimHei', 'KaiTi', 'FangSong']
Font.whitelist = fonts //将字体加入到白名单
Quill.register(Font, true)
},
};
</script>
<style scoped lang="scss">
.editorBox {
width: 100%;
display: flex;
flex-direction: column;
/deep/.ql-container {
flex: 1 !important;
overflow: hidden;
}
}
/*
这里一定要写上,是用来把相关改变的配置在工具栏正常显示
如果不写,字体样式的下拉会重复显示Sans Serif,字体大小的下拉会重复显示Normal
*/
// .quill-editor /deep/ .ql-container {
// min-height: 150px;
// }
.quill-editor /deep/ .ql-picker-label {
line-height: 24px;
vertical-align: 4px;
}
.quill-editor /deep/ .ql-picker-options {
max-height: 200px;
overflow: auto;
&::-webkit-scrollbar {
width: 3px;
height: 5px;
}
&::-webkit-scrollbar-track {
background: transparent;
border-radius: 10px;
}
&::-webkit-scrollbar-thumb {
background: transparent;
border-radius: 10px;
}
&:hover {
&::-webkit-scrollbar-thumb {
background: rgb(68, 164, 202);
border-radius: 10px;
}
}
}
.quill-editor
/deep/
.ql-picker.ql-font
.ql-picker-label[data-value="SimSun"]::before,
.quill-editor
/deep/
.ql-picker.ql-font
.ql-picker-item[data-value="SimSun"]::before {
content: "宋体";
font-family: "SimSun" !important;
}
.quill-editor
/deep/
.ql-picker.ql-font
.ql-picker-label[data-value="SimHei"]::before,
.quill-editor
/deep/
.ql-picker.ql-font
.ql-picker-item[data-value="SimHei"]::before {
content: "黑体";
font-family: "SimHei";
}
.quill-editor
/deep/
.ql-picker.ql-font
.ql-picker-label[data-value="Microsoft-YaHei"]::before,
.quill-editor
/deep/
.ql-picker.ql-font
.ql-picker-item[data-value="Microsoft-YaHei"]::before {
content: "微软雅黑";
font-family: "Microsoft YaHei";
}
.quill-editor
/deep/
.ql-picker.ql-font
.ql-picker-label[data-value="KaiTi"]::before,
.quill-editor
/deep/
.ql-picker.ql-font
.ql-picker-item[data-value="KaiTi"]::before {
content: "楷体";
font-family: "KaiTi" !important;
}
.quill-editor
/deep/
.ql-picker.ql-font
.ql-picker-label[data-value="FangSong"]::before,
.quill-editor
/deep/
.ql-picker.ql-font
.ql-picker-item[data-value="FangSong"]::before {
content: "仿宋";
font-family: "FangSong";
}
.quill-editor
/deep/
.ql-snow
.ql-picker.ql-size
.ql-picker-label[data-value="60px"]::before,
.quill-editor
/deep/
.ql-snow
.ql-picker.ql-size
.ql-picker-item[data-value="60px"]::before {
content: "一号";
}
.quill-editor
/deep/
.ql-snow
.ql-picker.ql-size
.ql-picker-label[data-value="50px"]::before,
.quill-editor
/deep/
.ql-snow
.ql-picker.ql-size
.ql-picker-item[data-value="50px"]::before {
content: "二号";
}
.quill-editor
/deep/
.ql-snow
.ql-picker.ql-size
.ql-picker-label[data-value="40px"]::before,
.quill-editor
/deep/
.ql-snow
.ql-picker.ql-size
.ql-picker-item[data-value="40px"]::before {
content: "三号";
}
.quill-editor
/deep/
.ql-snow
.ql-picker.ql-size
.ql-picker-label[data-value="30px"]::before,
.quill-editor
/deep/
.ql-snow
.ql-picker.ql-size
.ql-picker-item[data-value="30px"]::before {
content: "四号";
}
.quill-editor
/deep/
.ql-snow
.ql-picker.ql-size
.ql-picker-label[data-value="20px"]::before,
.quill-editor
/deep/
.ql-snow
.ql-picker.ql-size
.ql-picker-item[data-value="20px"]::before {
content: "五号";
}
.quill-editor
/deep/
.ql-snow
.ql-picker.ql-size
.ql-picker-label[data-value="18px"]::before,
.quill-editor
/deep/
.ql-snow
.ql-picker.ql-size
.ql-picker-item[data-value="18px"]::before {
content: "六号";
}
.quill-editor
/deep/
.ql-snow
.ql-picker.ql-size
.ql-picker-label[data-value="16px"]::before,
.quill-editor
/deep/
.ql-snow
.ql-picker.ql-size
.ql-picker-item[data-value="16px"]::before {
content: "七号";
}
.quill-editor
/deep/
.ql-snow
.ql-picker.ql-size
.ql-picker-label[data-value="13px"]::before,
.quill-editor
/deep/
.ql-snow
.ql-picker.ql-size
.ql-picker-item[data-value="13px"]::before {
content: "默认";
}
</style>
quillConfig.js 文件
import { getToken } from "@/utils/auth";
import { Message } from 'element-ui';
/*富文本编辑图片上传配置*/
const uploadConfig = {
action: process.env.VUE_APP_BASE_API + "/common/upload", // 必填参数 图片上传地址
methods: 'POST', // 必填参数 图片上传方式
token: "Bearer " + getToken(), // 可选参数 如果需要token验证,假设你的token有存放在sessionStorage
name: 'file', // 必填参数 文件的参数名
size: 2000, // 可选参数 图片大小,单位为Kb, 1M = 1024Kb
accept: 'image/png, image/gif, image/jpeg, image/bmp, image/x-icon' // 可选 可上传的图片格式
};
// toolbar工具栏的工具选项
const toolOptions = [
['bold', 'italic', 'underline', 'strike'], // 加粗,斜体,下划线,删除线
[{ 'header': 1 }, { 'header': 2 }], // 几级标题
[{ 'list': 'ordered' }, { 'list': 'bullet' }], // 有序列表,无序列表
[{ 'script': 'sub' }, { 'script': 'super' }], // 下角标,上角标
[{ 'indent': '-1' }, { 'indent': '+1' }], // 缩进
[{ 'size': ['13px', '16px', '18px', '20px', '30px', '40px', '50px', '60px'] }], // 字体大小
[{ 'color': [] }, { 'background': [] }], // 颜色选择
[{ 'font': ['Microsoft-YaHei', 'SimSun', 'SimHei', 'KaiTi', 'FangSong'] }],// 字体
[{ 'align': [] }], // 居中
['clean'], // 清除样式
['link', 'image']
];
// 处理图片上传事件,更改为base64为上传到服务器
const handlers = {
image: function image() {
var self = this;
var fileInput = this.container.querySelector('input.ql-image[type=file]');
if (fileInput === null) {
fileInput = document.createElement('input');
fileInput.setAttribute('type', 'file');
// 设置图片参数名
if (uploadConfig.name) {
fileInput.setAttribute('name', uploadConfig.name);
}
// 可设置上传图片的格式
fileInput.setAttribute('accept', uploadConfig.accept);
fileInput.classList.add('ql-image');
// 监听选择文件
fileInput.addEventListener('change', function () {
// 创建formData
var formData = new FormData();
formData.append(uploadConfig.name, fileInput.files[0]);
// 图片上传
var xhr = new XMLHttpRequest();
xhr.open(uploadConfig.methods, uploadConfig.action, true);
xhr.setRequestHeader("Authorization",uploadConfig.token); //设置请求头
// 上传数据成功,会触发
xhr.onload = function (res) {
if (xhr.status === 200) {
var res = JSON.parse(xhr.responseText);
let length = self.quill.getSelection(true).index;
//这里很重要,你图片上传成功后,img的src需要在这里添加,res.path就是你服务器返回的图片链接。
self.quill.insertEmbed(length, 'image', res.data);
self.quill.setSelection(length + 1)
}
fileInput.value = '';
};
// 开始上传数据
xhr.upload.onloadstart = function (e) {
fileInput.value = ''
};
// 当发生网络异常的时候会触发,如果上传数据的过程还未结束
xhr.upload.onerror = function (e) {
Message.error({
message:'图片上传失败'
})
};
// 上传数据完成(成功或者失败)时会触发
xhr.upload.onloadend = function (e) {
// console.log('上传结束')
};
xhr.send(formData)
});
this.container.appendChild(fileInput);
}
fileInput.click();
}
};
export default {
placeholder: '请输入内容',
modules: {
toolbar: {
container: toolOptions, // 工具栏选项
handlers: handlers // 事件重写
}
}
};
这就完成了
使用 :
<text-editor v-model='formData.remark' :disabled='disabled' height='300'></text-editor>