富文本编辑器wangEdiotr作为vue组件使用时,上传图片后,再打开报错Error in callback for watcher "value": "Error: Cannot find a descendant at path [0,2] in node
原因是组件不显示时,没有及时把组件销毁,导致了冲突。
解决方法:
在引用组件时加上v-if="open",只要每次打开都重新渲染MyEditor组件就好了
<my-editor v-model="form.content" v-if="open" />
完整的MyEditor封装组件代码如下:
<!-- * __----~~~~~~~~~~~------___ * . . ~~//====...... __--~ ~~ * -. \_|// |||\\ ~~~~~~::::... /~ * ___-==_ _-~o~ \/ ||| \\ _/~~- * __---~~~.==~||\=_ -_--~/_-~|- |\\ \\ _/~ * _-~~ .=~ | \\-_ '-~7 /- / || \ / * .~ .~ | \\ -_ / /- / || \ / * / ____ / | \\ ~-_/ /|- _/ .|| \ / * |~~ ~~|--~~~~--_ \ ~==-/ | \~--===~~ .\ * ' ~-| /| |-~\~~ __--~~ * |-~~-_/ | | ~\_ _-~ /\ * / \ \__ \/~ \__ * _--~ _/ | .-~~____--~-/ ~~==. * ((->/~ '.|||' -_| ~~-/ , . _|| * -_ ~\ ~~---l__i__i__i--~~_/ * _-~-__ ~) \--______________--~~ * //.-~~~-~_--~- |-------~~~~~~~~ * //.-~~~--\ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * 神兽保佑 永无BUG * * @Description: * @Author: 小超越 * @AuthorBlog: www.zhe94.com * @Date: 2024-08-07 12:09:33 * @LastEditors: 小超越 516761948@qq.com * @LastEditTime: 2024-08-14 11:47:22 --> <template> <div style="border: 1px solid #ccc;"> <Toolbar style="border-bottom: 1px solid #ccc" :editor="editor" :defaultConfig="toolbarConfig" :mode="mode" /> <Editor style="height: 500px; overflow-y: hidden;z-index:100;" v-model="html" :defaultConfig="editorConfig" :mode="mode" @onCreated="onCreated" @onChange="onChange" /> </div> </template> <script> import Vue from 'vue' import { Editor, Toolbar } from '@wangeditor/editor-for-vue' import { Boot } from '@wangeditor/editor' import { getToken } from '@/utils/auth' // class MyButtonMenu implements IButtonMenu { // TS 语法 class MyButtonMenu { // JS 语法 constructor() { this.title = '标题样式' // 自定义菜单标题 // this.iconSvg = '<svg>...</svg>' // 可选 // this.tag = 'button' this.tag = 'select' this.width = 80 } // 下拉框的选项 getOptions(editor) { let text = editor.getSelectionText() //选中文本 const options = [ { value: '', text: '标题样式', selected: true }, { value: "<h3><span style='background-color: rgb(115, 209, 61);'>"+text+"</span></h3>", text: '绿色' }, { value: "<h3><span style='background-color: rgb(235, 144, 58);'>"+text+"</span></h3>", text: '橙色' }, { value: "<h3><span style='background-color: rgb(9, 109, 217);'>"+text+"</span></h3>", text: '蓝色' }, { value: "<h3><span style='background-color: rgb(135, 56, 0);'>"+text+"</span></h3>", text: '咖啡色' }, ] return options } // 获取菜单执行时的 value ,用不到则返回空 字符串或 false // getValue(editor: IDomEditor): string | boolean { // TS 语法 getValue(editor) { // JS 语法 // console.log(editor.getSelectionText()) // let text = editor.getSelectionText() // text = "<h2 style='width: 60%;color: #ffffff;display: block;text-align: center;margin: 30rpx auto 40rpx auto;border-radius: 50rpx;background: #636d36;font-size: 32rpx;padding: 15rpx 0;'>" + text + "</h2>" return '' } // 菜单是否需要激活(如选中加粗文本,“加粗”菜单会激活),用不到则返回 false // isActive(editor: IDomEditor): boolean { // TS 语法 isActive(editor) { // JS 语法 return false } // 菜单是否需要禁用(如选中 H1 ,“引用”菜单被禁用),用不到则返回 false // isDisabled(editor: IDomEditor): boolean { // TS 语法 isDisabled(editor) { // JS 语法 return false } // 点击菜单时触发的函数 // exec(editor: IDomEditor, value: string | boolean) { // TS 语法 exec(editor, value) { // JS 语法 if (this.isDisabled(editor)) return // editor.insertText(value) // value 即 this.value(editor) 的返回值 // editor.dangerouslyInsertHtml('<div classname="title"">sjdlkfjsld</div>') console.log(value) editor.dangerouslyInsertHtml(value) } } const menu1Conf = { key: 'menu1', // 定义 menu key :要保证唯一、不重复(重要) factory() { return new MyButtonMenu() // 把 `YourMenuClass` 替换为你菜单的 class }, } const models = { menus: [menu1Conf] } Boot.registerModule(models) export default Vue.extend({ name: 'MyEditor', props:{ value:{ type:String } }, components: { Editor, Toolbar }, data() { return { mode: 'default', // or 'simple' editor: null, html: this.value, toolbarConfig: { insertKeys: { index: 1, // 插入的位置,基于当前的 toolbarKeys keys: ['menu1'] } }, editorConfig: { placeholder: '请输入内容...', MENU_CONF: { // 配置上传图片 uploadImage: { server: process.env.VUE_APP_BASE_API + '/file/upload', // 上传的图片服务器地址 // form-data fieldName,后端接口参数名称,默认值wangeditor-uploaded-image fieldName: "file", // 自定义增加 http header headers: { Authorization: 'Bearer ' + getToken() }, //上传回调 customInsert: this.customInsert } } } } }, watch: { value: { handler(val) { console.log("拦截",val) if (val !== this.html && val !==null) { this.html = val === '' ? '' : val if (this.editor) { // if(!this.editor.isFocused()){ // console.log("不聚焦编辑器") // this.editor.focus() // } // console.log("进入设置内容") //重置内容 // this.editor.setHtml(this.html) this.editor.clear() this.editor.dangerouslyInsertHtml(this.html); } } if(val===null){ if(this.editor){ console.log("进入清除") this.editor.clear() } } }, immediate: true } }, methods: { //创建 onCreated(editor) { // console.log("获取html",this.html) // console.log('editor created!', editor.getHtml()) console.log("创建") this.editor = Object.seal(editor) // 一定要用 Object.seal() ,否则会报错 }, //内容回调 onChange(editor) { // console.log(editor.getHtml()) this.$emit("input", editor.getHtml()); }, //上传图片 customInsert(res, insertFn) { // JS 语法 // res 即服务端的返回结果 let url = res.data.url // 图片 src ,必须 let alt = res.data.name //图片描述文字,非必须 let href = res.data.url // 图片的链接,非必须 // 从 res 中找到 url alt href ,然后插入图片 insertFn(url, alt, href) } }, mounted() { this.html = this.value; // this.$nextTick(()=>{ // this.html=this.value // }) }, beforeDestroy() { const editor = this.editor if (editor == null) return editor.destroy() // 组件销毁时,及时销毁编辑器 } }) </script> <style src="@wangeditor/editor/dist/css/style.css"></style>
如需转载请保留本文出处: https://www.zhe94.com/978.html