news 2026/5/25 18:00:53

12.17 富文本编辑器wangEditor的使用

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
12.17 富文本编辑器wangEditor的使用

wangEditor5介绍

wangEditor5 —— 轻量级 web 富文本编辑器,配置方便,使用简单。支持 IE10+ 浏览器。

官网:www.wangEditor.com

下载

注意: wangeditor都是小写字母

// 下面两个依赖都需要安装 npm i @wangeditor/editor npm i @wangeditor/editor-for-vue@next

相关组件

Editor : 编辑器组件

Toolbar: 菜单栏组件

import '@wangeditor/editor/dist/css/style.css' // 引入 css import { Editor, Toolbar } from '@wangeditor/editor-for-vue' ... <template> <div style="border: 1px solid #ccc"> <Toolbar 属性/> <Editor 属性/> </div> </template>

了解vue3的shallowRef

Vue 的响应性系统默认是深度的。虽然这让状态管理变得更直观,但在数据量巨大时,深度响应性也会导致不小的性能负担,因为每个属性访问都将触发代理的依赖追踪。

Vue 确实也为此提供了一种解决方案,通过使用 shallowRef() 和 shallowReactive() 来绕开深度响应。浅层式 API 创建的状态只在其顶层是响应式的,对所有深层的对象不会做任何处理。

const shallowArray = shallowRef([ /* 巨大的列表,里面包含深层的对象 */ ]) // 这不会触发更新... shallowArray.value.push(newObject) // 这才会触发更新 shallowArray.value = [...shallowArray.value, newObject] // 这不会触发更新... shallowArray.value[0].foo = 1 // 这才会触发更新 shallowArray.value = [ { ...shallowArray.value[0], foo: 1 }, ...shallowArray.value.slice(1) ]

基础案例

<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' // mode: 'default' 默认模式 - 集成了 wangEditor 所有功能 // mode: 'simple' 简洁模式 - 仅有部分常见功能,但更加简洁易用 const mode = ref("simple") // const mode = ref("default") // 编辑器实例,必须用 shallowRef const editorRef = shallowRef() // 内容 HTML const valueHtml = ref('<p>hello</p>') // 模拟 ajax 异步获取内容 onMounted(() => { setTimeout(() => { valueHtml.value = '<p>模拟 Ajax 异步设置内容</p>' }, 1500) }) const toolbarConfig = {} const editorConfig = { placeholder: '请输入内容...' } // 组件销毁时,也及时销毁编辑器 onBeforeUnmount(() => { const editor = editorRef.value if (editor == null) return editor.destroy() }) const handleCreated = (editor) => { editorRef.value = editor // 记录 editor 实例,重要! } </script> <template> <div style="border: 1px solid #ccc"> <Toolbar style="border-bottom: 1px solid #ccc" :editor="editorRef" :defaultConfig="toolbarConfig" :mode="mode" /> <Editor style="height: 500px; overflow-y: hidden;" v-model="valueHtml" :defaultConfig="editorConfig" :mode="mode" @onCreated="handleCreated" /> </div> </template>

工具栏配置

查看所有默认工具栏配置

const handleCreated = (editor) => { editorRef.value = editor // 记录 editor 实例,重要! //打印所有默认配置 console.log(editor.getConfig()["MENU_CONF"]) }

自定义工具栏

// 工具栏配置 const toolbarConfig = { toolbarKeys: [ "headerSelect", //正文 "blockquote", //引号 "|", //分隔线 "bold", //加粗 "underline", //下划线 ] } // 可以使用当前方法获取所有的工具栏配置选项 console.log(editor.getConfig()["MENU_CONF"]);

上传图片的菜单配置

工具栏配置决定了在工具栏显示哪些工具,菜单配置决定了该工具使用时的相关配置。

比如: 工具栏上显示上传图片工具,但上传后的接口地址,header中携带token等需要通过菜单配置

// 初始化默认配置 const editorConfig = { placeholder: '请输入内容...', MENU_CONF: {} } editorConfig.MENU_CONF['uploadImage'] = { server: '/api/upload', fieldName: 'file', headers: { Authorization: 'Bearer ' + sessionStorage.getItem("token"), }, // 上传之前触发 onBeforeUpload(file) { // TS 语法 // onBeforeUpload(file) { // JS 语法 // file 选中的文件,格式如 { key: file } return file // 可以 return // 1. return file 或者 new 一个 file ,接下来将上传 // 2. return false ,不上传这个 file }, // 上传进度的回调函数 onProgress(progress) { // TS 语法 // onProgress(progress) { // JS 语法 // progress 是 0-100 的数字 console.log('progress', progress) }, // 自定义插入图片 customInsert(res, insertFn) { // TS 语法 // customInsert(res, insertFn) { // JS 语法 // res 即服务端的返回结果 let { url } = res // 从 res 中找到 url alt href ,然后插入图片 insertFn(url) } }

后端处理

路由 routes/uploadRouter.js

const express = require("express") const router = express.Router() const upload = require("../tools/upload") //图片上传 // 这里的file名称,需要跟前端的name值保持一致 router.post("/uploadImg", upload.single("file"), (req, res) => { // console.log(req.file.filename) // // 需要返回图片的访问地址 域名+文件名 const url = "http://localhost:3000/uploads/" + req.file.filename // console.log(req.file.filename); res.json({ url }); }) module.exports = router

上传方法 tools/upload.js

const multer = require("multer") // nodejs用于上传文件的模块 const uuid = require("uuid") //uuid用来生成唯一标识符 /* multer是node的中间件, 处理表单数据 主要用于上传文件 multipart/form-data */ // 指定存储位置 const storage = multer.diskStorage({ // 存储位置 destination(req, file, callback) { // 参数一 错误信息 参数二 上传路径(此处指定upload文件夹) callback(null, "public/uploads") }, // 确定文件名 filename(req, file, cb) { //文件扩展名 let extName = file.originalname.slice(file.originalname.lastIndexOf('.')) //新文件名 let fileName = uuid.v1() cb(null, fileName + extName) } }) // 得到multer对象 传入storage对象 const upload = multer({ storage }) module.exports = upload;

编辑器封装

父组件

<script setup> import { ref } from 'vue'; import Editor from './editor.vue'; //向子组件传递的富文本编辑器的初始内容 const html = ref("<p>dddddd</p>") const submit = ()=>{ console.log('html',html.value); } </script> <template> <div class="rich-txt"> <h3>富文本编辑器</h3> <Editor v-model:html="html"></Editor> <button @click="submit">提交</button> </div> </template> <style lang="scss" scoped></style>

子组件

<script setup> import '@wangeditor/editor/dist/css/style.css' // 引入 css import { onBeforeUnmount, ref, shallowRef, onMounted,computed } from 'vue' import { Editor, Toolbar } from '@wangeditor/editor-for-vue' // 编辑器实例,必须用 shallowRef const editorRef = shallowRef() const props = defineProps({ html: String }) const emit = defineEmits() const mode = ref("simple") // const mode = ref("default") // 内容 HTML const valueHtml = computed({ get () { console.log(props.html); return props.html }, set (value) { emit('update:html', value) } }) // const toolbarConfig = {} // 工具栏配置 const toolbarConfig = { toolbarKeys: [ "headerSelect", //正文 "blockquote", //引号 "|", //分隔线 "bold", //加粗 "underline", //下划线 ] } // 初始化默认配置 const editorConfig = { placeholder: '请输入内容...', } // 组件销毁时,也及时销毁编辑器 onBeforeUnmount(() => { const editor = editorRef.value if (editor == null) return editor.destroy() }) const handleCreated = (editor) => { editorRef.value = editor // 记录 editor 实例,重要! console.log(editor.getConfig()["MENU_CONF"]) } </script> <template> <div style="border: 1px solid #ccc"> <Toolbar style="border-bottom: 1px solid #ccc" :editor="editorRef" :defaultConfig="toolbarConfig" :mode="mode" /> <Editor style="height: 500px; overflow-y: hidden;" v-model="valueHtml" :defaultConfig="editorConfig" :mode="mode" @onCreated="handleCreated" /> </div> </template>

注意:父组件调用子组件的时候,只需要添加相应式和组件

<script> import Editor from '../upload/Editor.vue'; const html = ref(''); </script> <Editor v-model:html="html"></Editor>
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/26 4:56:35

超越兼容:金仓数据库如何以三重革新,破解企业核心业务运维难题

兼容是对企业历史投资的尊重是确保业务平稳过渡的基石然而这仅仅是故事的起点在数字化转型的深水区&#xff0c;企业对数据库的需求早已超越“语法兼容”的基础诉求。无论是核心业务系统的稳定运行&#xff0c;还是敏感数据的安全防护&#xff0c;亦或是复杂场景下的性能优化&a…

作者头像 李华
网站建设 2026/5/26 6:16:38

Win11 查找并开启 IE 浏览器教程

Win11 正式发布后&#xff0c;不少用户第一时间升级了新系统&#xff0c;却发现找不到熟悉的IE浏览器。其实这是因为微软已在 Win11 中正式移除了的独立前端程序&#xff0c;但它的核心内核仍被系统保留。下面就为大家分享 Win11 开启 IE 浏览器的具体操作步骤&#xff1a; 右…

作者头像 李华
网站建设 2026/5/25 15:50:34

效率翻倍!盘点 15 款我离不开的“神仙软件”,不仅有 AI 神器

有粉丝问我&#xff1a; 你录动图软件用的是啥&#xff1f; 你录视频用啥软件啊&#xff1f; 你的视频剪辑用的什么软件&#xff1f; 你平时写作用啥软件&#xff1f; 我今天盘点一下我日常比较常用的、非常好用的几款软件。 截图 Xnip 传送门&#xff1a;https://zh.x…

作者头像 李华
网站建设 2026/5/26 5:06:49

半导体行业正迈入前所未有的“千兆周期”

本文由半导体产业纵横&#xff08;ID&#xff1a;ICVIEWS&#xff09;编译自tomshardware行业分析认为&#xff0c;人工智能时代正在同时重塑芯片市场的各个方面。人工智能的浪潮正以前所未有的深度和广度重塑全球半导体产业。来自行业巨头与研究机构的一致预测表明&#xff0c…

作者头像 李华
网站建设 2026/5/26 6:15:40

八股文学习日常(虚拟机篇)

1.介绍JVM的内存模型JVM的内存模型共分为五大部分&#xff0c;虚拟机栈&#xff0c;方法栈&#xff0c;堆&#xff0c;元空间和程序计数器&#xff1a;1&#xff09;程序计数器&#xff1a;可看作当前线程执行字节码的行号显示器。用于存储当前线程执行方法的JVM指令地址。当执…

作者头像 李华
网站建设 2026/5/25 21:25:27

EmotiVoice能否生成双语混合语音?中英文夹杂合成实测

EmotiVoice能否生成双语混合语音&#xff1f;中英文夹杂合成实测 在智能语音助手、虚拟偶像和国际化内容创作日益普及的今天&#xff0c;用户早已不满足于“能说话”的TTS系统。他们期待的是更自然、更具表现力的声音——比如在一句中文里流畅插入“Zoom会议”、“deadline”或…

作者头像 李华