富文本使用补充
安装vue-quill-editor
npm install vue-quill-editor --save
注意:
1. 一定不要忘了 -save ,否则的话可能会导致富文本框加载失败
2. 安装完成之后,查看package.json文件中的dependencies里是否有安装好的vue-quill-editor这个插件,如果没有加--save,则dependencies中可能不会有这个插件,而是再devDependencies中,这个时候浏览器会报错,因为该功能已经开发很久了,报错信息暂时无法提供
在vue中如果需要对图片进行缩放,需要使用该插件,注意需要将该插件通过webpack注册到全局中,才能进行正常使用(vue3.0中的注册方法,vue2.0自行百度)
chainWebpack: (config) => { config.plugin('provide').use(webpack.ProvidePlugin, [{ 'window.Quill': 'quill' }]); }
vue-quill-editor使用方法:(注释包含在里面)
- npm安装vue-quill-editor(富文本编辑器)和quill-image-resize-module、quill-image-extend-module(图片缩放)
- 注意如果需要修改editor中的样式,那么一定不要在style上面写scoped,只有在全局状态下修改editor样式才会生效,当前组件内修改是不会生效的
<template>
<div class="editor">
<input type="file" style="display:none;" id="input" @change.prevent="upLoad()"/>
<quill-editor
v-model="contentValue"
// 有时候样式会出现问题,是因为少加了ql-editor这个class,需要加上
class="quill-editor ql-editor"
ref="myQuillEditor"
style="padding-top:0; display: flex; flex-direction: column;"
:content="contentValue"
:options="editorOption"
@blur="onEditorBlur($event)"
@focus="onEditorFocus($event)"
@change="onEditorChange($event)"
>
</quill-editor>
<span class="wordNumber">{{TiLength}}/4000</span>
</div>
</template>
<script>
import 'quill/dist/quill.snow.css' // 富文本编辑器外部引用样式 三种样式三选一引入即可
//import 'quill/dist/quill.core.css'
//import 'quill/dist/quill.bubble.css'
import { quillEditor, Quill } from 'vue-quill-editor' // 调用富文本编辑器
import { ImageExtend } from 'quill-image-extend-module'
// quill-image-resize-module该插件是用于控制上传的图片的大小
import ImageResize from 'quill-image-resize-module'
Quill.register('modules/imageResize', ImageExtend);
Quill.register('modules/imageResize', ImageResize);
export default {
props: {
content: {
type: String,
default: ''
},
disabled: {
type: Boolean,
default: false
}
},
watch: {
content: function(oldV, newV) {
this.contentValue = oldV
}
},
components: {
quillEditor
},
data() {
return {
contentValue: '',
flag: true, // 初始化富文本
TiLength: 0,
editorOption: {
placeholder: "",
modules: {
toolbar: { // 菜单栏(工具栏),手动配置自己需要的富文本功能
container: [
["bold", "italic", "underline", "strike"], //加粗,斜体,下划线,删除线
[{ indent: "-1" }, { indent: "+1" }], // 左右缩进
[{ color: [] }, { background: [] }], // 字体颜色,字体背景颜色
[{ header: 1 }, { header: 2 }], // 标题,键值对的形式;1、2表示字体大小
[{ align: [] }], //对齐方式
["image", /*"video"*/], //上传图片、上传视频
],
handlers: {
'image': function (value) { // 劫持图片上传,自定义图片上传
if (value) {
// 通过input的type=file唤醒选择弹框,选择之后自定义上传路径
document.querySelector('#input').click()
} else {
this.quill.format('image', false);
}
}
}
},
imageResize:{ // 图片缩放比例
displayStyles:{
backgroundColor:'black',
border:'none',
color:'white'
},
modules:['Resize','DisplaySize', 'Toolbar'] // Resize 允许缩放, DisplaySize 缩放时显示像素 Toolbar 显示工具栏
}
}
},
}
},
computed: {
editor() {
return this.$refs.myQuillEditor.quill;
}
},
created () {
this.contentValue = this.content
},
mounted() {
this.pastePic();
},
methods: {
onEditorReady(editor) {
// 准备编辑器
},
onEditorBlur() {}, // 失去焦点事件
// 获得焦点事件
onEditorFocus(e) {
e.enable(!this.disabled); // 禁用文本框
},
// 内容改变事件
onEditorChange(val) {
if (this.flag) {
this.flag = false
setTimeout(()=>{
this.$refs.myQuillEditor.quill.setSelection(val.html.length + 1)
this.TiLength = this.TiLength=val.quill.getLength()-1
},20)
}
this.$emit('editor-content', {value: val.html}) // 触发事件,将富文本框中的值传递出去
this.contentValue = val.html
val.quill.deleteText(4000,4);
if(this.contentValue==''){
this.TiLength=0
}else{
this.TiLength=val.quill.getLength()-1
}
},
upLoad() {
let files = window.event.target.files[0];
if (files.size / 1024 / 1024 > 2) { // 定义上传的图片的大小
// this.$message.warning('请上传小于5M的文件');
return;
}
let fileType = ['.jpg', '.png'];
let suffix = files.name.substring(
files.name.lastIndexOf('.'),
files.name.length
);
if (fileType.indexOf(suffix) === -1) {
this.$message.warning('请上传格式为png、jpg的文件');
return;
}
// 自定义上传路径,根据需求上传到对应的服务器,本公司使用的是上传到ali-oss
this.handleUpload(files);
},
// 上传到阿里云服务器
handleUpload(files) {
this.ossUpload(files)
.then((res) => { // 上传成功之后的回调
// 获取光标所在位置
let length = this.editor.getSelection().index;
// 插入图片 res.info为服务器返回的图片地址
this.editor.insertEmbed(length, 'image', res.url)
// 调整光标到最后
this.editor.setSelection(length + 1)
})
.catch((files) => {
this.$message.warning('上传失败');
});
},
// 截屏粘贴到富文本框
pastePic() {
// 页面加载之后就监听粘贴事件paste
this.editor.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.handleUpload(file);
});
}
}, false);
},
}
}
</script>
// 注意style不能加scoped。否则修改的.editor的样式是无法生效的
<style lang="scss">
.editor {
position: relative;
.ql-toolbar{
border: 1px solid #CDCFD4;
height: 40px;
background: #F0F2F5;
}
.ql-editor{
min-height:240px;
padding: 0;
padding-top: 15px;
box-sizing: border-box;
}
.ql-container {
img {
display: block;
}
}
.wordNumber {
position: absolute;
right: 13px;
bottom: 15px;
color: #666666;
font-size: 14px;
}
}
</style>
使用方法:
<editor
@editor-content="listenContent"
:content="quillEditor"
:disabled="isDisabled"
/>
// editor-content: 实时监听富文本框中输入的值
// content: 富文本框中的初始默认值
// disabled: 是否禁用富文本框输入
自己的实现
<template>
<div class="editor">
<input
type="file"
style="display: none"
id="input"
@change.prevent="upLoad()"
/>
<quill-editor
v-model="contentValue"
class="quill-editor ql-editor"
ref="myQuillEditor"
style="padding-top: 0; display: flex; flex-direction: column"
:content="contentValue"
:options="editorOption"
@blur="onEditorBlur($event)"
@focus="onEditorFocus($event)"
@change="onEditorChange($event)"
>
</quill-editor>
<span class="wordNumber">{{ TiLength }}/4000</span>
</div>
</template>
<script>
import "quill/dist/quill.snow.css"; // 富文本编辑器外部引用样式 三种样式三选一引入即可
//import 'quill/dist/quill.core.css'
//import 'quill/dist/quill.bubble.css'
import { quillEditor, Quill } from "vue-quill-editor"; // 调用富文本编辑器
import { ImageExtend } from "quill-image-extend-module";
// quill-image-resize-module该插件是用于控制上传的图片的大小
import ImageResize from "quill-image-resize-module";
Quill.register("modules/imageResize", ImageExtend);
Quill.register("modules/imageResize", ImageResize);
export default {
props: {
content: {
type: String,
default: "",
},
disabled: {
type: Boolean,
default: false,
},
},
watch: {
content: function (oldV, newV) {
this.contentValue = oldV;
},
},
components: {
quillEditor,
},
data() {
return {
contentValue: "",
flag: true, // 初始化富文本
TiLength: 0,
editorOption: {
placeholder: "",
modules: {
toolbar: {
// 菜单栏(工具栏),手动配置自己需要的富文本功能
container: [
["bold", "italic", "underline", "strike"], //加粗,斜体,下划线,删除线
[{ indent: "-1" }, { indent: "+1" }], // 左右缩进
[{ color: [] }, { background: [] }], // 字体颜色,字体背景颜色
[{ header: 1 }, { header: 2 }], // 标题,键值对的形式;1、2表示字体大小
[{ align: [] }], //对齐方式
["image" /*"video"*/], //上传图片、上传视频
],
handlers: {
image: function (value) {
// 劫持图片上传,自定义图片上传
if (value) {
// 通过input的type=file唤醒选择弹框,选择之后自定义上传路径
document.querySelector("#input").click();
} else {
this.quill.format("image", false);
}
},
},
},
imageResize: {
// 图片缩放比例
displayStyles: {
backgroundColor: "black",
border: "none",
color: "white",
},
modules: ["Resize", "DisplaySize", "Toolbar"], // Resize 允许缩放, DisplaySize 缩放时显示像素 Toolbar 显示工具栏
},
},
},
};
},
computed: {
editor() {
return this.$refs.myQuillEditor.quill;
},
},
created() {
this.contentValue = this.content;
},
mounted() {
this.pastePic();
},
methods: {
onEditorReady(editor) {
// 准备编辑器
},
onEditorBlur() {}, // 失去焦点事件
// 获得焦点事件
onEditorFocus(e) {
e.enable(!this.disabled); // 禁用文本框
},
// 内容改变事件
onEditorChange(val) {
if (this.flag) {
this.flag = false;
setTimeout(() => {
this.$refs.myQuillEditor.quill.setSelection(val.html.length + 1);
this.TiLength = this.TiLength = val.quill.getLength() - 1;
}, 20);
}
this.$emit("editor-content", { value: val.html }); // 触发事件,将富文本框中的值传递出去
this.contentValue = val.html;
val.quill.deleteText(4000, 4);
if (this.contentValue == "") {
this.TiLength = 0;
} else {
this.TiLength = val.quill.getLength() - 1;
}
},
upLoad() {
let files = window.event.target.files[0];
if (files.size / 1024 / 1024 > 2) {
// 定义上传的图片的大小
// this.$message.warning('请上传小于5M的文件');
return;
}
let fileType = [".jpg", ".png"];
let suffix = files.name.substring(
files.name.lastIndexOf("."),
files.name.length
);
if (fileType.indexOf(suffix) === -1) {
this.$message.warning("请上传格式为png、jpg的文件");
return;
}
// 自定义上传路径,根据需求上传到对应的服务器,本公司使用的是上传到ali-oss
this.handleUpload(files);
},
// 上传到阿里云服务器
handleUpload(files) {
//不走七牛的写法
var reader = new FileReader();
reader.onloadend = () => {
let length = this.editor.getSelection().index;
this.editor.insertEmbed(length, "image", reader.result);
// 调整光标到最后
this.editor.setSelection(length + 1);
};
reader.readAsDataURL(files);
//走起牛的写法
// this.ossUpload(files)
// .then((res) => {
// // 上传成功之后的回调
// // 获取光标所在位置
// let length = this.editor.getSelection().index;
// // 插入图片 res.info为服务器返回的图片地址
// this.editor.insertEmbed(length, "image", res.url);
// // 调整光标到最后
// this.editor.setSelection(length + 1);
// })
// .catch((files) => {
// this.$message.warning("上传失败");
// });
},
// 截屏粘贴到富文本框
pastePic() {
// 页面加载之后就监听粘贴事件paste
this.editor.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.handleUpload(file);
});
}
},
false
);
},
},
};
</script>
<style lang="scss">
.editor {
position: relative;
.ql-toolbar {
border: 1px solid #cdcfd4;
height: 40px;
background: #f0f2f5;
}
.ql-editor {
min-height: 240px;
padding: 0;
padding-top: 15px;
box-sizing: border-box;
}
.ql-container {
img {
display: block;
}
}
.wordNumber {
position: absolute;
right: 13px;
bottom: 15px;
color: #666666;
font-size: 14px;
}
}
</style>
七牛云上传的写法
<template>
<div class="editor">
<!-- 图片上传功能 -->
<el-upload
:on-change="upLoad"
:auto-upload="false"
:loading="true"
class="upload-btn"
ref="upload"
action
:show-file-list="false"
>
<el-button
style="display: none"
id="input"
slot="trigger"
icon="el-icon-upload"
size="small"
type="primary"
>上传图片</el-button
>
</el-upload>
<quill-editor
v-model="contentValue"
class="quill-editor ql-editor"
ref="myQuillEditor"
style="padding-top: 0; display: flex; flex-direction: column"
:content="contentValue"
:options="editorOption"
@blur="onEditorBlur($event)"
@focus="onEditorFocus($event)"
@change="onEditorChange($event)"
>
</quill-editor>
<span class="wordNumber">{{ TiLength }}/4000</span>
</div>
</template>
<script>
import { Message } from "element-ui";
import { message } from "ant-design-vue";
import CDNClient from "@frontend/cdn-uploader";
import "quill/dist/quill.snow.css"; // 富文本编辑器外部引用样式 三种样式三选一引入即可
//import 'quill/dist/quill.core.css'
//import 'quill/dist/quill.bubble.css'
import { getCdnToken, sendCdnPicture } from "../../../../../api/index";
import { quillEditor, Quill } from "vue-quill-editor"; // 调用富文本编辑器
import { ImageExtend } from "quill-image-extend-module";
// quill-image-resize-module该插件是用于控制上传的图片的大小
import ImageResize from "quill-image-resize-module";
Quill.register("modules/imageResize", ImageExtend);
Quill.register("modules/imageResize", ImageResize);
export default {
props: {
content: {
type: String,
default: "",
},
disabled: {
type: Boolean,
default: false,
},
},
watch: {
content: function (oldV, newV) {
this.contentValue = oldV;
},
},
components: {
quillEditor,
},
data() {
return {
picUrl: "",
uptoken: "",
contentValue: "",
flag: true, // 初始化富文本
TiLength: 0,
editorOption: {
placeholder: "",
modules: {
toolbar: {
// 菜单栏(工具栏),手动配置自己需要的富文本功能
container: [
["bold", "italic", "underline", "strike"], //加粗,斜体,下划线,删除线
[{ indent: "-1" }, { indent: "+1" }], // 左右缩进
[{ color: [] }, { background: [] }], // 字体颜色,字体背景颜色
[{ header: 1 }, { header: 2 }], // 标题,键值对的形式;1、2表示字体大小
[{ align: [] }], //对齐方式
["image" /*"video"*/], //上传图片、上传视频
],
handlers: {
image: function (value) {
// 劫持图片上传,自定义图片上传
if (value) {
console.log("点击上传按钮");
// 通过input的type=file唤醒选择弹框,选择之后自定义上传路径
document.querySelector("#input").click();
} else {
this.quill.format("image", false);
}
},
},
},
imageResize: {
// 图片缩放比例
displayStyles: {
backgroundColor: "black",
border: "none",
color: "white",
},
modules: ["Resize", "DisplaySize", "Toolbar"], // Resize 允许缩放, DisplaySize 缩放时显示像素 Toolbar 显示工具栏
},
},
},
};
},
computed: {
editor() {
return this.$refs.myQuillEditor.quill;
},
},
created() {
this.contentValue = this.content;
this.getToken();
},
mounted() {
this.pastePic();
},
methods: {
onEditorReady(editor) {
// 准备编辑器
},
onEditorBlur() {}, // 失去焦点事件
// 获得焦点事件
onEditorFocus(e) {
e.enable(!this.disabled); // 禁用文本框
},
// 内容改变事件
onEditorChange(val) {
if (this.flag) {
this.flag = false;
setTimeout(() => {
this.$refs.myQuillEditor.quill.setSelection(val.html.length + 1);
this.TiLength = this.TiLength = val.quill.getLength() - 1;
}, 20);
}
this.$emit("editor-content", { value: val.html }); // 触发事件,将富文本框中的值传递出去
this.contentValue = val.html;
val.quill.deleteText(4000, 4);
if (this.contentValue == "") {
this.TiLength = 0;
} else {
this.TiLength = val.quill.getLength() - 1;
}
},
upLoad(e) {
let files = e.raw;
if (files.size / 1024 / 1024 > 2) {
// 定义上传的图片的大小
Message({
type: "error",
message: "请上传小于5M的文件",
});
return;
}
let fileType = [".jpg", ".png"];
let suffix = files.name.substring(
files.name.lastIndexOf("."),
files.name.lengthquill
);
if (fileType.indexOf(suffix) === -1) {
Message({
type: "error",
message: "请上传格式为png、jpg的文件",
});
return;
}
// 自定义上传路径
this.handleUpload(e.raw);
},
// 上传起牛云写法
handleUpload(files) {
this.uploadFile(files);
},
// 截屏粘贴到富文本框
pastePic() {
// 页面加载之后就监听粘贴事件paste
this.editor.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.handleUpload(file);
});
}
},
false
);
},
//持久化图片
async sendCdnPicture(e) {
const { response } = await sendCdnPicture(e);
this.picUrl = response.urlimage;
message.success("上传成功", 4);
let length = this.editor.getSelection().index;
// 插入图片 res.info为服务器返回的图片地址
this.editor.insertEmbed(length, "image", this.picUrl);
// 调整光标到最后
this.editor.setSelection(length + 1);
},
async uploadFile(file) {
// 实例化七牛云的上传实例
const uploadClient = new CDNClient({
env: "test",
projectName: "xxx_ai_xxxx",
});
//创建上传对象
const uploader = await uploadClient.create(file, {
authToken: this.uptoken,
filename: Date.now().toString() + ".jpg",
onprogress: (ev) => {
// console.log("event is", ev);
},
onsuccess: (res) => {
this.sendCdnPicture({
picturename: res.filename.toString(),
urlimage: res.url.toString(),
});
},
});
// 上传开始
uploader.start();
},
async getToken() {
// 获取身份的token
const { response } = await getCdnToken();
if (response.status == 1000) {
this.uptoken = response.results.token;
}
},
},
};
</script>
<style lang="scss">
.editor {
position: relative;
.ql-toolbar {
border: 1px solid #cdcfd4;
height: 40px;
background: #f0f2f5;
}
.ql-editor {
min-height: 240px;
padding: 0;
padding-top: 15px;
box-sizing: border-box;
}
.ql-container {
img {
display: block;
}
}
.wordNumber {
position: absolute;
right: 13px;
bottom: 15px;
color: #666666;
font-size: 14px;
}
}
</style>