记录一下最近工作遇到的问题,需求就是在vue-quil-editor富文本自定义撤销和还原功能:undo、redo。
安装
npm install vue-quill-editor -S
当然,也可以使用CDN的方式引入,我们这里讲NPM安装
组件中挂载
import 'quill/dist/quill.core.css'
import 'quill/dist/quill.snow.css'
import 'quill/dist/quill.bubble.css'
import { quillEditor } from 'vue-quill-editor'
export default {
components: {
quillEditor
}
}
options具体配置
editorOption: {
placeholder: "请输入溯源内容,溯源内容不会被收录进入数据库",
modules: {
toolbar: {
container: [
//自定义工具栏选项
//工具栏设置
["bold", "italic", "underline", "strike"], //加粗,斜体,下划线,删除线
["blockquote", "code-block"], //引用,代码块
// [{ 'header': 1 }, { 'header': 2 }], // 标题,键值对的形式;1、2表示字体大小
[{ list: "ordered" }, { list: "bullet" }], //列表
[{ align: [] }], //对齐方式
[{ script: "sub" }, { script: "super" }], // 上下标
["clean"], //清除字体样式
//[{ 'indent': '-1'}, { 'indent': '+1' }], // 缩进
// [{ 'direction': 'rtl' }], // 文本方向
[{ color: [] }, { background: [] }], // 字体颜色,字体背景颜色
[{ size: ["small", false, "large", "huge"] }], // 字体大小
[{ header: [1, 2, 3, 4, 5, 6, false] }], //几级标题
[{ font: [] }], //字体
["image"], //上传图片、上传视频
["revoke", "redo"], //添加的按钮
],
handlers: {
//给自定义按钮添加的事件
revoke: () => {
//撤销
this.btnundo();
},
redo: () => {
//恢复
this.btnRedo();
},
},
},
},
},
自定义按钮的样式
在data里面定义一个方法 initButton,然后mounted里面调用这个方法
initButton: function () {
//在使用的页面中初始化按钮样式
let revoke = document.querySelector(".ql-revoke"); //获取元素
let redo = document.querySelector(".ql-redo");
let Front = document.createElement("i"); //创建元素
let after = document.createElement("i");
Front.className = "el-icon-refresh-left"; //新增class属性
after.className = "el-icon-refresh-right";
Front.style.cssText = "font-size:18px";
after.style.cssText = "font-size:18px";
revoke.appendChild(Front); //追加到元素中
redo.appendChild(after);
},
实现undo redo
我这里实现undo redo的思路是,自己定义一个空的数组changeText,去记录富文本字符发生的变化,富文本绑定@change事件,每次富文本发生改变,changeText数组就记录一次,然后点击undo 和 redo去获取相应的数据就好了。 定义的方法写在methods里就好了,editorOption配置里面去调用methods里面的方法。
// 撤销
btnundo() {
for (let i = 0; i < this.changeText.length; i++) {
if (this.content == this.changeText[i]) {
this.content = this.changeText[i - 1];
}
}
},
// 恢复
btnRedo() {
for (let i = 0; i < this.changeText.length; i++) {
if (this.content == this.changeText[i]) {
this.content = this.changeText[i + 1];
return;
}
}
},
// 富文本监听事件
EditorChange() {
if (this.changeText.length >= 50) {
//限制数组长度
this.changeText.shift(); //清除第一条数据
this.changeText.push(this.content);
} else {
this.changeText.push(this.content); //追加数据
}
},
汉化富文本
样式直接写入style里面
<style>
/* 富文本汉化 */
p {
margin: 10px;
}
.edit_container,
.quill-editor {
height: 300px;
}
.ql-snow .ql-picker.ql-size .ql-picker-label::before,
.ql-snow .ql-picker.ql-size .ql-picker-item::before {
content: "14px";
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="small"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="small"]::before {
content: "10px";
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="large"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="large"]::before {
content: "18px";
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="huge"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="huge"]::before {
content: "32px";
}
.ql-snow .ql-picker.ql-header .ql-picker-label::before,
.ql-snow .ql-picker.ql-header .ql-picker-item::before {
content: "文本";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="1"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"]::before {
content: "标题1";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="2"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"]::before {
content: "标题2";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="3"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"]::before {
content: "标题3";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="4"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"]::before {
content: "标题4";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="5"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"]::before {
content: "标题5";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="6"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before {
content: "标题6";
}
.ql-snow .ql-picker.ql-font .ql-picker-label::before,
.ql-snow .ql-picker.ql-font .ql-picker-item::before {
content: "标准字体";
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="serif"]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="serif"]::before {
content: "衬线字体";
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="monospace"]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="monospace"]::before {
content: "等宽字体";
}
</style>
存在问题
到这里已经基本实现undo和redo了,但是undo redo是有bug的,因为项目已经够用了,所以就没有继续深挖,说一下bug:
1.undo 因为是@change事件 去记录富文本变化的,但是数组是空的时候是没有记录的,所以一直撤销到数组为空的时候,不会清空,这个问题应该可以写个判断去判断数组是不是为空而去改变双向绑定的值。
2.redo 一样是@change事件去记录富文本的变化,所以撤销后也会触发change事件记录富文本的变化,所以数组里面会出现相同的值,我这里是给了return停止代码的运行,但是一直恢复到数组最后一条的时候,也是会有点问题。
如果有大佬懂得undo redo的可以具体讲讲,我这里就是怎么简单怎么来,也没考虑那么多,不对的地方请指出