富文本编辑器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://zhe94.com/978.html

