富文本编辑器Wangeditor & Quilleditor使用
总体使用起来个人还是更喜欢Wangeditor,官网写得十分清晰易懂,生命周期使用起来很方便,执行流畅度也有处理。WangEditor 和 Quill 都是流行的富文本编辑器,它们各自有不同的特点和适用场景。WangEditor更适合需要轻量级、快速集成的项目,功能简单且易用,适合一般的富文本编辑需求。Quill更适合功能复杂、需要高度定制化的项目,尤其适合开发者有一定开发需求,想要更多控制编辑器
·
Wangeditor的基本实现
附官网地址:主题 | wangEditor
代码实例:直接参考官网写得很清楚主题 | wangEditor
<template>
<div class="border">
<Toolbar
class="border"
:editor="editorRef"
:defaultConfig="toolbarConfig"
mode="default"
/>
<Editor
style="height: 300px;"
v-model="valueHtml"
:defaultConfig="editorConfig"
mode="default"
@onCreated="handleCreated"
@customAlert="customAlert"
@customPaste="customPaste"
/>
</div>
</template>
<script setup>
import '@wangeditor/editor/dist/css/style.css' // 引入 css
import { onBeforeUnmount, ref, shallowRef, onMounted } from 'vue'
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
// 编辑器实例,必须用 shallowRef
const editorRef = shallowRef()
// 内容 HTML
const valueHtml = ref('hello world')
const editorConfig = {
placeholder: "请输入...",
MENU_CONF: {
//文字颜色
color: {
colors: ["#000", "#333", "#fff"],
},
//背景颜色
bgColor: {
colors: ["#000", "#333", "#fff"],
},
//字号
//行高
//表情
//.....前往官网查看更多
},
};
// 修改 uploadImage 菜单配置
editorConfig.MENU_CONF['uploadImage'] = {
server: '/api',
// form-data fieldName ,默认值 'wangeditor-uploaded-image'
fieldName: 'fieldName',
// 单个文件的最大体积限制,默认为 2M
maxFileSize: 1 * 1024 * 1024, // 1M
// 最多可上传几个文件,默认为 100
maxNumberOfFiles: 10,
// 选择文件时的类型限制,默认为 ['image/*'] 。如不想限制,则设置为 []
allowedFileTypes: ['image/*'],
// ......
//【注意】不需要修改的不用写,wangEditor 会去 merge 当前其他配置
}
const toolbarConfig = {
// toolbar 配置
excludeKeys: [
// "headerSelect",// 排除菜单组,写菜单组 key 的值即可
"blockquote",
"bold",
"underline",
"italic",
"group-more-style",
"lineHeight",
"bgColor",
],
};
const handleCreated = (editor) => {
editorRef.value = editor;
};
const customAlert = (info, type) => {
alert(`【自定义提示】${type} - ${info}`)
}
const customPaste = (editor, event, callback) => {
console.log('ClipboardEvent 粘贴事件对象', event)
// const html = event.clipboardData.getData('text/html') // 获取粘贴的 html
const text = event.clipboardData.getData('text/plain') // 获取粘贴的纯文本
// const rtf = event.clipboardData.getData('text/rtf') // 获取 rtf 数据(如从 word wsp 复制粘贴)
// 自定义插入内容
editor.insertText(text)
// 返回 false ,阻止默认粘贴行为
event.preventDefault()
callback(false) // 返回值(注意,vue 事件的返回值,不能用 return)
// 返回 true ,继续默认的粘贴行为
// callback(true)
}
</script>
<style lang="less" scoped>
.border{
border: 1px solid #ccc;
}
</style>
Quilleditor的基本使用
附官网地址:Configuration - Quill Rich Text Editor
代码实例:
<template>
<div>
<!-- 图片上传组件辅助-->
<el-upload
id="upload"
class="editor-upload"
:action="uploadUrl"
:data="uploadData"
name="file"
:headers="headers"
:show-file-list="false"
:on-success="uploadSuccess"
:on-error="uploadError"
:before-upload="beforeUpload"
>
</el-upload>
<!-- 富文本编辑器 -->
<quill-editor
class="editor"
v-model="content"
ref="myQuillEditor"
:options="editorOption"
@blur="onEditorBlur($event)"
@focus="onEditorFocus($event)"
@change="onEditorChange($event)"
@ready="ready($event)"
>
</quill-editor>
</div>
</template>
<script>
//引入Qill插件
import Quill from "quill";
// 自定义字体
let fontFamily = ['宋体', '黑体', '微软雅黑', '楷体', '仿宋', 'Arial', '苹方'];
Quill.imports['attributors/style/font'].whitelist = fontFamily;
Quill.register(Quill.imports['attributors/style/font']);
// 自定义文字大小
let fontSize = ['10px', '12px', '14px', '16px', '20px', '24px', '36px']
Quill.imports['attributors/style/size'].whitelist = fontSize;
Quill.register(Quill.imports['attributors/style/size']);
// 新增行高
let Parchment = Quill.import("parchment");
let lingHeight = ['initial', '1', '1.5', '1.75', '2', '3', '4'];
class lineHeightAttributor extends Parchment.Attributor.Style {}
const lineHeightStyle = new lineHeightAttributor("lineHeight", "line-height", {
scope: Parchment.Scope.INLINE,
whitelist: lingHeight
});
Quill.register({ "formats/lineHeight": lineHeightStyle }, true);
// 对齐方式样式都改成style方式,而不是class
let Align = Quill.import('attributors/style/align');
Align.whitelist = ['right', 'center', 'justify'];
Quill.register(Align, true);
const toolbarOptions = [
[
"bold",
"italic",
"underline",
"strike",
"blockquote",
"code-block",
{ header: 1 },
{ header: 2 },
{ list: "ordered" },
{ list: "bullet" },
{ indent: "-1" },
{ indent: "+1" },
{ script: "sub" }, // 下标
{ script: "super" }, // 上标
{ align: [] },
{ color: [] },
{ background: [] },
"link",
"image",
],
[{ size: fontSize }], // 文字大小
[{ header: [1, 2, 3, 4, 5, 6, false] }], // 标题
[{ font: fontFamily }], // 字体
[{ lineheight: lingHeight }] // 行高
];
export default {
name: "Editor",
data() {
return {
content: null,
uploadUrl: 'http://', // 上传图片接口地址
headers: { Authorization: "Bearer " + "TOKEN" },
editorOption: {
modules: {
toolbar: {
container: toolbarOptions,
handlers: {
// 编辑器菜单点击图片上传事件
image: function (value) {
console.log(value)
if (value) {
// 调用element上传组件
document.querySelector("#upload input").click();
}
},
lineheight: function (value) {
if (value) {
this.quill.format('lineHeight', value);
} else {
console.log(value);
}
}
},
},
},
},
};
},
computed: {
// 图片上传额外的参数
uploadData() {
return { type: 1, id: '2' };
},
},
methods: {
// 失去焦点事件
onEditorBlur() {
this.$emit("on-blur", this.content);
},
onEditorFocus() {
//获得焦点事件
},
// 内容改变事件
onEditorChange() {
this.$emit("on-blur", this.content);
},
ready() {
Quill.register({ 'formats/lineHeight': lineHeightStyle }, true);
},
// 上传图片前
beforeUpload(file) {
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isLt2M) {
this.$message.error("上传图片不能大于 2M");
}
},
// 上传图片成功
uploadSuccess(res) {
if (res.code == 200) {
let img = `<img src="https:${res.data.url}" />`;
this.content = (this.content || "") + img;
}
},
// 上传图片失败
uploadError(res) {
console.log(res);
},
// 更新文本编辑器内容
upDateContent(v) {
this.content = v;
},
},
};
</script>
<style lang="scss" scoped>
::v-deep .quill-editor{
width: 1000px;
.ql-container {
height: 300px;
}
.editor-upload {
display: none;
}
/*
文字大小
*/
.ql-snow .ql-picker.ql-size{
width: 70px; // 菜单栏占比宽度
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value='10px']::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value='10px']::before {
content: '10px';
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value='12px']::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value='12px']::before {
content: '12px';
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value='14px']::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value='14px']::before {
content: '14px';
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value='16px']::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value='16px']::before {
content: '16px';
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value='20px']::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value='20px']::before {
content: '20px';
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value='24px']::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value='24px']::before {
content: '24px';
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value='36px']::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value='36px']::before {
content: '36px';
}
/*
字体
*/
.ql-snow .ql-picker.ql-font{
width: 80px; // 菜单栏占比宽度
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value='宋体']::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value='宋体']::before {
content: '宋体';
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value='黑体']::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value='黑体']::before {
content: '黑体';
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value='微软雅黑']::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value='微软雅黑']::before {
content: '微软雅黑';
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value='楷体']::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value='楷体']::before {
content: '楷体';
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value='仿宋']::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value='仿宋']::before {
content: '仿宋';
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value='Arial']::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value='Arial']::before {
content: 'Arial';
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value='苹方']::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value='苹方']::before {
content: '苹方';
}
/*
标题
*/
.ql-snow .ql-picker.ql-header{
width: 80px; // 菜单栏占比宽度
}
.ql-snow .ql-picker.ql-header .ql-picker-label::before,
.ql-snow .ql-picker.ql-header .ql-picker-item::before {
content: "文本" !important;
}
.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" !important;
}
.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" !important;
}
.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" !important;
}
.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" !important;
}
.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" !important;
}
.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" !important;
}
//配置编辑器行高
.ql-snow .ql-picker.ql-lineheight {
width: 70px; // 菜单栏占比宽度
}
.ql-snow .ql-picker.ql-lineheight .ql-picker-label::before {
content: '行高';
}
.ql-snow .ql-picker.ql-lineheight .ql-picker-item[data-value='initial']::before {
content: '默认';
}
.ql-snow .ql-picker.ql-lineheight .ql-picker-item[data-value='1']::before {
content: '1';
}
.ql-snow .ql-picker.ql-lineheight .ql-picker-item[data-value='1.5']::before {
content: '1.5';
}
.ql-snow .ql-picker.ql-lineheight .ql-picker-item[data-value='1.75']::before {
content: '1.75';
}
.ql-snow .ql-picker.ql-lineheight .ql-picker-item[data-value='2']::before {
content: '2';
}
.ql-snow .ql-picker.ql-lineheight .ql-picker-item[data-value='3']::before {
content: '3';
}
.ql-snow .ql-picker.ql-lineheight .ql-picker-item[data-value='4']::before {
content: '4';
}
.ql-snow .ql-picker.ql-lineheight .ql-picker-item[data-value='5']::before {
content: '5';
}
}
</style>
注意:Quill使用过程中有很多次碰壁,其中注册自定义菜单以及css的处理一度饱受折磨,我这边目前的实现依然存在一些交互和样式的问题,需注意一哈。参考了大神的文档链接放这里啦quill富文本编辑器自定义字体、文字大小(编辑器内含element上传组件)_quil编辑器 自定义字体-CSDN博客
总结:
总体使用起来个人还是更喜欢Wangeditor,官网写得十分清晰易懂,生命周期使用起来很方便,执行流畅度也有处理。
官方回答的差异如下【已C过来】:
WangEditor 和 Quill 都是流行的富文本编辑器,它们各自有不同的特点和适用场景。下面是它们的比较:
1. 易用性
- WangEditor: 是一款轻量级的富文本编辑器,界面简洁,安装和使用都非常简单。它的目标是提供一个易于集成的编辑器,适合需要快速搭建编辑功能的项目。WangEditor 支持简单的工具栏配置,易于定制化。
- Quill: 相比之下,Quill 更加强大和复杂,功能丰富。它的文档和 API 非常完善,适合需要高度定制和扩展的项目。Quill 的学习曲线略高,但提供了更强的灵活性。
2. 功能
- WangEditor:
- 提供常用的富文本功能,如加粗、斜体、标题、插入图片、链接、视频等。
- 支持 Markdown 语法导入和导出。
- 可以通过插件扩展一些额外功能。
- 支持上传图片、文件,支持自定义图片上传方式。
- Quill:
- 功能更强大,支持更细粒度的文本格式化。
- 内建对表格、代码块、无序列表、有序列表等更多功能的支持。
- 支持完整的模块化设计,可以扩展和自定义工具栏、内容格式、图片上传等。
- 丰富的 API 支持,允许开发者进行更复杂的编辑需求。
3. 性能
- WangEditor: 因为它比较轻量,所以性能表现较好,适用于要求不高但需要快速开发的场景。它适合对性能要求较高、用户量不大且功能需求较简单的应用。
- Quill: 性能方面较为稳健,但由于它的功能更复杂,因此在一些高频操作或大型文档的情况下,可能会出现性能问题。然而,Quill 依然可以处理较复杂的文档和富文本格式。
4. 定制化与扩展性
- WangEditor:
- 对于大多数常规的编辑需求,WangEditor 提供了很多现成的功能,可以快速集成到项目中。
- 但在一些高级自定义需求方面,可能需要自己开发一些插件。
- Quill:
- 提供了更强的定制化功能,几乎所有的内容和行为都可以通过 API 或自定义模块进行扩展。
- 由于其开放性和模块化设计,开发者可以非常灵活地实现复杂的需求。
5. 社区与文档
- WangEditor:
- 文档清晰易懂,社区活跃。提供了较为完善的中文文档,并且比较容易上手。
- 社区问题解答速度较快,但相对 Quill 来说规模较小。
- Quill:
- Quill 的社区相对更大,文档相对也更详细。社区支持广泛,开发者可以快速获取解决方案。
- 由于它是由专门的团队维护,文档和更新频繁,支持更为专业。
6. 集成与支持
- WangEditor:
- 集成非常简单,特别适合前端快速开发应用。
- 支持 Vue、React 等现代前端框架,且集成方式相对简便。
- Quill:
- Quill 也提供了对各大前端框架的支持,但集成过程可能比 WangEditor 更复杂一些,尤其是需要做高级定制时。
7. 浏览器兼容性
- WangEditor: 支持现代浏览器和 IE11+。
- Quill: 支持主流现代浏览器,并且提供了对移动端的支持。
总结:
- WangEditor 更适合需要轻量级、快速集成的项目,功能简单且易用,适合一般的富文本编辑需求。
- Quill 更适合功能复杂、需要高度定制化的项目,尤其适合开发者有一定开发需求,想要更多控制编辑器行为的场景。
选择哪个取决于你的项目需求。如果需要快速集成且功能不复杂,WangEditor 是一个不错的选择;如果你需要更强大的定制功能,或者你的项目中有复杂的富文本编辑需求,Quill 可能是更合适的选择。
更多推荐
所有评论(0)