目前接触到的编辑器有三种
1、tinymce-editor
2、@wangeditor/editor-for-vue
3、vue-quill-editor
现在主要介绍一下这三种编辑器的用法
tinymce-editor
@wangeditor/editor-for-vue
编辑器样式,这个样式还是比较好看的,功能也比较好用
image.png
1、首先下载插件
yarn add @wangeditor/editor // 下载版本是^5.1.23
yarn add @wangeditor/editor-for-vue //下载版本是 1.0.2
yarn add @wangeditor/plugin-upload-attachment // 上传附件插件 ^1.1.0
2、封装使用
//封装富文本编辑器
<template>
<div :class="{ 'border-line': border }">
<Toolbar style="border-bottom: 1px solid #ccc" :editor="editor" :defaultConfig="toolbarConfig" :mode="mode" />
<Editor
:style="{ height }"
v-model="html"
:defaultConfig="editorConfig"
:mode="mode"
@onCreated="onCreated"
@onChange="onChange"
/>
</div>
</template>
<script>
import Vue from "vue";
import { Boot } from "@wangeditor/editor";
import attachmentModule from "@wangeditor/plugin-upload-attachment";
import { Editor, Toolbar } from "@wangeditor/editor-for-vue";
import "@wangeditor/editor/dist/css/style.css";
import axios from "axios ";
Boot.registerModule(attachmentModule);
export default {
components: { Editor, Toolbar },
props: {
//border
border: {
type: Boolean,
default: false,
},
/* 编辑器的内容 */
value: {
type: String,
default: "",
},
// 高度
height: {
type: String,
default: () => "500px",
},
},
data() {
return {
editor: null,
html: "",
toolbarConfig: {
excludeKeys: ["fullScreen"],
insertKeys: {
index: 24,
keys: ["uploadAttachment"],
},
},
editorConfig: {
placeholder: "请输入内容...",
scroll: false,
MENU_CONF: {
uploadImage: {
// 自定义上传图片 方法
customUpload: this.uploadImg,
// 上传接口设置文件名
fieldName: "file",
meta: {
token: localStorage.getItem("token"),
},
},
uploadVideo: {
customUpload: this.uploadVideo,
fieldName: "file",
meta: {
token: localStorage.getItem("token"),
},
},
uploadAttachment: {
customUpload: this.uploadFile,
fieldName: "file",
meta: {
token: localStorage.getItem("token"),
},
},
},
hoverbarKeys: {
attachment: {
menuKeys: ["downloadAttachment"],
},
},
},
mode: "default", //default or 'simple'
};
},
watch: {
value: {
handler(val) {
this.html = val;
},
immediate: true,
},
},
mounted() {
// 模拟 ajax 请求,异步渲染编辑器
},
beforeDestroy() {
const editor = this.editor;
if (editor == null) return;
editor.destroy(); // 组件销毁时,及时销毁编辑器
},
methods: {
onChange(editor) {
this.$emit("input", this.html);
},
onCreated(editor) {
this.editor = Object.seal(editor); // 一定要用 Object.seal() ,否则会报错
},
uploadImg(file, insertFn) {
let imgData = new FormData();
imgData.append("file", file);
commonAxios({
url: `/fileUpload`,
data: imgData,
method: "post",
headers: {
Authorization: localStorage.getItem("token"),
},
}).then((res) => {
if (res.success) {
insertFn(`图片url`);
} else {
this.$message.warning(res.errorMessage);
}
});
},
uploadVideo(file, insertFn) {
let imgData = new FormData();
imgData.append("file", file);
commonAxios({
url: `/fileUpload`,
data: imgData,
method: "post",
headers: {
Authorization: localStorage.getItem("token"),
},
}).then((res) => {
if (res.success) {
insertFn(`视频url`);
} else {
this.$message.warning(res.errorMessage);
}
});
},
uploadFile(file, insertFn) {
let imgData = new FormData();
imgData.append("file", file);
commonAxios({
url: `/fileUpload`,
data: imgData,
method: "post",
headers: {
Authorization: localStorage.getItem("token"),
},
}).then((res) => {
if (res.success) {
insertFn(
`附件:${res.resultData.elementName}`,`下载url`);
} else {
this.$message.warning(res.errorMessage);
}
});
},
},
};
</script>
<style lang="less" scoped>
.border-line {
border: 1px solid #d6d6d6;
}
/deep/.w-e-scroll > div:first-child {
height: 100%;
overflow-y: auto;
}
</style>
<template>
<editor v-model="content" height="300px" :border="true" />
</template>
<script>
import editor from "./components/editor.vue";
export default{
components: {
editor,
},
data(){
content:''
}
}
</script>
这样一个双向绑定的富文本编辑器就可以使用了!
vue-quill-editor
这个富文本内容没有上一个多,其中图片和视频也是要自己写上传逻辑
image.png
1、下载插件
yarn add vue-quill-editor
yarn add quill-image-resize-module //调整大小组件
yarn add quill-image-drop-module //拖动加载图片组件
2、封装
<template>
<w-spin :spinning="loading" tip="上传中...">
<quill-editor
ref="myQuillEditor"
v-model="editorContent"
:options="editorOption"
@change="onEditorChange($event)"
@click.native="handleEditAblequestion"
/>
</w-spin>
</template>
<script>
import "quill/dist/quill.core.css";
import "quill/dist/quill.snow.css";
import "quill/dist/quill.bubble.css";
import { quillEditor, Quill } from "vue-quill-editor";
// 富文本图片大小
import imageResize from "quill-image-resize-module"; // 调整大小组件。
import { ImageDrop } from "quill-image-drop-module"; // 拖动加载图片组件。
Quill.register("modules/imageResize", imageResize);
Quill.register("modules/imageDrop", ImageDrop);
export default {
props: {
value: {
type: String,
default: "",
},
},
components: {
quillEditor,
},
data() {
return {
loading: false,
editorContent: "",
editorOption: {
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: ["small", false, "large", "huge"] }], // 字体大小
// [{ header: [1, 2, 3, 4, 5, 6, false] }], //几级标题
[{ color: [] }, { background: [] }], // 字体颜色,字体背景颜色
// [{ font: [] }], //字体
[{ align: [] }], //对齐方式
// ["clean"], //清除字体样式
["image", "video"], //上传图片、上传视频
],
handlers: {
video: () => {
this.openFileDialog("video");
},
},
},
imageResize: {
displayStyles: {
backgroundColor: "black",
border: "none",
color: "white",
},
modules: ["Resize", "DisplaySize", "Toolbar"],
},
},
placeholder: "输入内容...",
},
};
},
watch: {
value: {
handler(newValue) {
this.editorContent = newValue === null ? "" : newValue;
},
deep: true,
immediate: true,
},
editorContent(newValue) {
this.$emit("input", newValue);
},
},
mounted() {
this.resetFocus();
},
methods: {
resetFocus() {
this.$refs.myQuillEditor?.quill?.enable(false);
// this.$nextTick(() => {
// document.querySelector(".content-b").scrollTop = 0;
// });
},
onEditorChange() {
// console.log(e);
},
handleEditAblequestion() {
this.$refs.myQuillEditor.quill.enable(true);
this.$refs.myQuillEditor.quill.focus();
},
openFileDialog(type) {
var input = document.createElement("input");
input.setAttribute("type", "file");
input.setAttribute("accept", type === "image" ? "image/*" : "video/*");
input.click();
let that = this;
input.onchange = async function () {
var file = input.files[0];
const formData = new FormData();
formData.append("file", file);
try {
that.loading = true;
let res = await that.$axios.post(`上传接口`, formData, {
headers: {
"content-type": "multipart/form-data",
},
});
let url = `返回的url`;
that.$refs.myQuillEditor.quill.insertEmbed(that.$refs.myQuillEditor.quill.getSelection().index, "video", url);
} catch (err) {
console.log(err);
} finally {
that.loading = false;
}
// // 这里可以添加上传逻辑,例如使用 FormData 上传到服务器
// // 但是请注意,直接上传到服务器的代码不在这里展示
// // 如果只是要在编辑器中插入视频,可以直接使用 file URL
// if (URL && URL.createObjectURL && type === "video") {
// console.log(URL.createObjectURL(file));
// console.log(that.$refs);
// that.$refs.myQuillEditor.quill.insertEmbed(
// that.$refs.myQuillEditor.quill.getSelection().index,
// "video",
// URL.createObjectURL(file)
// );
// }
};
},
},
};
</script>
<style lang="less" scoped>
/deep/.ql-editor {
height: 100px;
}
/deep/.ql-snow .ql-picker.ql-size .ql-picker-label::before,
/deep/.ql-snow .ql-picker.ql-size .ql-picker-item::before {
content: "14px";
}
/deep/.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="small"]::before,
/deep/.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="small"]::before {
content: "10px";
}
/deep/.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="large"]::before,
/deep/.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="large"]::before {
content: "18px";
}
/deep/.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="huge"]::before,
/deep/.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="huge"]::before {
content: "32px";
}
/deep/.ql-snow .ql-picker.ql-header .ql-picker-label::before,
/deep/.ql-snow .ql-picker.ql-header .ql-picker-item::before {
content: "文本";
}
/deep/.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="1"]::before,
/deep/.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"]::before {
content: "标题1";
}
/deep/.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="2"]::before,
/deep/.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"]::before {
content: "标题2";
}
/deep/.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="3"]::before,
/deep/.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"]::before {
content: "标题3";
}
/deep/.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="4"]::before,
/deep/.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"]::before {
content: "标题4";
}
/deep/.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="5"]::before,
/deep/.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"]::before {
content: "标题5";
}
/deep/.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="6"]::before,
/deep/.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before {
content: "标题6";
}
/deep/.ql-snow .ql-picker.ql-font .ql-picker-label::before,
/deep/.ql-snow .ql-picker.ql-font .ql-picker-item::before {
content: "标准字体";
}
/deep/.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="serif"]::before,
/deep/.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="serif"]::before {
content: "衬线字体";
}
/deep/.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="monospace"]::before,
/deep/.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="monospace"]::before {
content: "等宽字体";
}
</style>
3、使用
<template>
<Editor v-model="content" />
</template>
<script>
import Editor from "@/components/Editor";
export default {
components: { Editor },
data(){
content:''
}
}
</script>
参考文档
https://www.wangeditor.com/
https://blog.csdn.net/m0_57442975/article/details/134261247
https://www.jianshu.com/p/9d0aba0ff8ae
网友评论