在Vue3+ElementPlus前端中增加对@wangeditor的富文本编辑器和上传文件的处理的封装,实现系统新闻资讯的管理

在很多业务系统中,有时候需要编辑富文本,就是包括图文消息排版等处理,图片有时候需要结合后端实现图片的上传处理,在本篇随笔中,结合@wangeditor的富文本编辑器和上传文件的处理的封装,来实现系统新闻资讯的管理,可以实现图片上传和图文排版的常规操作。

1、@wangeditor的富文本编辑器

该富文本编辑器控件的官网地址:https://www.wangeditor.com/,官网提供很详尽的使用介绍。

对应Vue版本的编辑器控件是:/* by yours.tools - online tools website : yours.tools/zh/formatpy.html */ @wangeditor/editor-for-vue

因此我们可以通过pnpm 、npm等安装管理工具进行组件的安装。

pnpm install @wangeditor/editor-for-vue --save

其他的处理就和常规的组件使用差不多了。我们来大概介绍下使用的案例。

界面代码

<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;"
            v-model="html"
            :defaultConfig="editorConfig"
            :mode="mode"
            @onCreated="onCreated"
        />
    </div>
</template>

脚本控制代码

<script>
  import Vue from 'vue'
  import { Editor, Toolbar } from '@wangeditor/editor-for-vue'

  export default Vue.extend({
    components: { Editor, Toolbar },
    data() {
      return {
        editor: null,
        html: '<p>hello</p>',
        toolbarConfig: {},
        editorConfig: { placeholder: '请输入内容...' },
        mode: 'default', // or 'simple'
      }
    },
    methods: {
      onCreated(editor) {
        this.editor = Object.seal(editor) // 一定要用 Object.seal() ,否则会报错
      },
    },
    mounted() {
      // 模拟 ajax 请求,异步渲染编辑器
      setTimeout(() => {
        this.html = '<p>模拟 Ajax 异步设置内容 HTML</p>'
      }, 1500)
    },
    beforeDestroy() {
      const editor = this.editor
      if (editor == null) return
      editor.destroy() // 组件销毁时,及时销毁编辑器
    },
  })
</script>

通过官方案例的指引,我们可以对其工具栏、编辑器配置、菜单、以及相应API进行处理即可。

image

界面效果如下所示。

image

 

2、自定义上传文件的处理

一般富文本的编辑器,都会提供相应的图片上传接口处理,该@wangeditor的富文本编辑器也是提供了很弹性化的文件上传接口的处理,以便兼容我们各自五花八门的图片上传接口处理。

image

通过官网的配置介绍,我们可以适应自己后端的接口和相关的配置信息。

如我的后端上传文件的接口为: /api/fileupload/postupload ,后端接口定义如下所示。

        /// <summary>
        /// 多文件上传处理(自动根据配置文件选择合适的上传方式)
        /// </summary>
        /// <returns></returns>
        [RequestSizeLimit(100000000)] //请求正文最大大小100M
        [HttpPost]
        [Route("postupload")]
        public async Task<List<ResponseFileInfo>> PostUpload()
        {
            var httpContext = this.HttpContext;
            var form = await Request.ReadFormAsync();
            string? guid = form["guid"];
            string? folder = form["folder"];
            var files = form.Files;

其中我们接受的参数包括guid(附件的GUID),folder(图片类别)以及接收Files的集合。返回的集合里面包括有id,文件名称,文件地址等内容,如下所示。

image

因此根据我的后端接口上传处理,传入相关的参数来处理编辑器控件配置。

// 更多详细配置看 https://www.wangeditor.com/v5/menu-config.html#%E4%B8%8A%E4%BC%A0%E5%9B%BE%E7%89%87
editorConfig.MENU_CONF["uploadImage"] = {
  // 服务端上传地址,根据实际业务改写
  server: "/api/fileupload/postupload",
  // form-data 的 fieldName,根据实际业务改写
  fieldName: "file",
  // 选择文件时的类型限制,根据实际业务改写
  allowedFileTypes: ["image/png", "image/jpg", "image/jpeg"],

  // 单个文件的最大体积限制,默认为 2M
  maxFileSize: 1 * 1024 * 1024, // 1M

  // 最多可上传几个文件,默认为 100
  maxNumberOfFiles: 10,

  // 自定义上传参数,参数会被添加到 formData 中,一起上传到服务端。
  meta: {
    folder: props.imageFolder,
    guid: props.imageGuid,
  },
  // 自定义增加 http  headers,如果接口需要令牌头信息,需要带上
  headers: {
    Accept: 'text/x-json',
    Authorization: 'Bearer ' + getAccessToken(),
  },

  // 将 meta 拼接到 url 参数中,默认 false
  metaWithUrl: false,

  // 自定义插入图片
  customInsert(res: any, insertFn: InsertFnType) {
    // console.log("customInsert", res);
    const result = res.result as Array<ResponseFileInfo>;
    if (result.length > 0) {
      const { id, name, url } = result[0];
      // res.data.url是后端返回的图片地址,根据实际业务改写
      if (url) {
        setTimeout(() => {

          // insertFn插入图片进编辑器
          insertFn(url, name, url);
        }, 2000);
      }
    }
  }
};

根据返回的结果,我们调用编辑器的接口实现图片的插入。

  // 自定义插入图片
  customInsert(res: any, insertFn: InsertFnType) {
    // console.log("customInsert", res);
    const result = res.result as Array<ResponseFileInfo>;
    if (result.length > 0) {
      const { id, name, url } = result[0];
      // res.data.url是后端返回的图片地址,根据实际业务改写
      if (url) {
        setTimeout(() => {

          // insertFn插入图片进编辑器
          insertFn(url, name, url);
        }, 2000);
      }
    }
  }
};

 

3、实现框架中的系统新闻资讯的管理

为了方便使用富文本编辑器,不用每次都配置一次相关的参数,我们把集成好上传图片的功能整合到自定义编辑器控件里面去,因此就可以实现重用了。

image

 因此定义了该控件的几个可以传入来的相关属性参数如下所示。

const props = defineProps({
  modelValue: {
    type: String,
    required: false
  },
  placeholder: {
    type: String,
    default: '请输入内容...',
    required: false
  },
  imageFolder: {
    type: String,
    default: '文章图片',
    required: false
  },
  imageGuid: {
    type: String,
    default: util.guid(),
    required: false
  }
});

并在内容变化的时候,触发事件通知。

// Emits
const emit = defineEmits<{
  (e: 'update:modelValue', val: any | any[]): void;
}>();

再把前面的编辑器自定义参数处理内容整合进去。

// 更多详细配置看 https://www.wangeditor.com/v5/menu-config.html#%E4%B8%8A%E4%BC%A0%E5%9B%BE%E7%89%87
editorConfig.MENU_CONF["uploadImage"] = {
  // 服务端上传地址,根据实际业务改写
  server: "/api/fileupload/postupload",
  // form-data 的 fieldName,根据实际业务改写
  fieldName: "file",
  // 选择文件时的类型限制,根据实际业务改写
  allowedFileTypes: ["image/png", "image/jpg", "image/jpeg"],

  // 单个文件的最大体积限制,默认为 2M
  maxFileSize: 1 * 1024 * 1024, // 1M

  // 最多可上传几个文件,默认为 100
  maxNumberOfFiles: 10,

  // 自定义上传参数,参数会被添加到 formData 中,一起上传到服务端。
  meta: {
    folder: props.imageFolder,
    guid: props.imageGuid,
  },
  // 自定义增加 http  headers,如果接口需要令牌头信息,需要带上
  headers: {
    Accept: 'text/x-json',
    Authorization: 'Bearer ' + getAccessToken(),
  },

  // 将 meta 拼接到 url 参数中,默认 false
  metaWithUrl: false,

  // 自定义插入图片
  customInsert(res: any, insertFn: InsertFnType) {
    // console.log("customInsert", res);
    const result = res.result as Array<ResponseFileInfo>;
    if (result.length > 0) {
      const { id, name, url } = result[0];
      // res.data.url是后端返回的图片地址,根据实际业务改写
      if (url) {
        setTimeout(() => {

          // insertFn插入图片进编辑器
          insertFn(url, name, url);
        }, 2000);
      }
    }
  }
};

由于我们后端的接口不是匿名的,需要令牌,因此需要额外增加对应的Token令牌信息的头部。

  // 自定义增加 http  headers,如果接口需要令牌头信息,需要带上
  headers: {
    Accept: 'text/x-json',
    Authorization: 'Bearer ' + getAccessToken(),
  },

然后监控相关的内容处理即可。

// 组件销毁时,也及时销毁编辑器
onBeforeUnmount(() => {
  const editor = editorRef.value;
  if (editor == null) return;
  editor.destroy();
});

//加载的时候,赋值给编辑器
onMounted(() => {
  valueHtml.value = props.modelValue ?? "";
  // console.log(props.modelValue)
});

watch(() => props.modelValue, (val) => {
  valueHtml.value = val
})

watch(() => valueHtml.value, (newVal) => {
  emit("update:modelValue", newVal)
  // 使用 nextTick 确保 DOM 更新完成后再更新编辑器内容
  nextTick(() => {
    if (editorRef.value) {
      editorRef.value.setHtml(newVal);
    }
  });
})

完成编辑器的自定义控件,如下所示。

image

 然后我们在具体的页面里面,导入自定义控件,就可以在页面代码中使用自己的富文本编辑控件了。

 <my-editor v-model="editForm.content" image-folder="文章图片" />

在我们完成了@wangeditor的富文本编辑器和上传文件的处理的封装后,我们可以用它来实现系统新闻资讯的管理。

image

 然后尝试上传文件处理

image

测试上传文件,完成后端接口对接处理即可。

这样我们就可以在多端中查看或者处理相关的系统新闻资讯内容了,如以下界面是通过H5对接后端接口,实现新闻资讯内容的管理。 

image   image

 

alt 专注于代码生成工具、.Net/Python 框架架构及软件开发,以及各种Vue.js的前端技术应用。著有Winform开发框架/混合式开发框架、微信开发框架、Bootstrap开发框架、ABP开发框架、SqlSugar开发框架、Python开发框架等框架产品。
  转载请注明出处:撰写人:伍华聪  http://www.iqidi.com 
    
<think>我们正在处理一个关于 wangEditor 在特定版本组合下的表格输入 Bug 的问题。用户提到使用: - @wangeditor/editor@^5.1.23 - @wangeditor/editor-for-vue@^1.0.2 在表格中第二次输入内容时出现 Bug。 根据用户提供的引用信息,特别是引用[5]中提到了一个 peer dependency 冲突的问题(Vue 版本要求),但用户现在已经指定了版本,所以我们需要专注于表格输入 Bug。 ### 分析 1. **版本确认**:用户使用的编辑器核心版本为 5.1.23(或以上,但^5.1.23会安装5.1.x的最新版),Vue 封装版本为 1.0.2。根据之前的记录,5.1.23 版本已经修复了光标定位问题,但用户遇到了第二次输入内容的 Bug。 2. **问题描述**:用户提到“表格第二次输入内容出现bug”。根据经验,这可能与以下几个问题有关: - 表格编辑状态未正确更新(Vue 响应性问题) - 编辑器在重新渲染时丢失了焦点或选区 - 编辑器内部状态(如编辑历史)未正确维护 3. **可能的原因**: - 在使用 Vue 封装版本时,由于 Vue 的响应式系统,可能会导致编辑器内部状态 Vue 组件的状态不同步。 - 在表格中连续输入时,可能触发了编辑器的某些事件(如 onChange),进而导致重新渲染,而重新渲染后选区(光标)未正确恢复。 ### 解决方案 #### 1. **升级到最新稳定版** - 虽然用户指定了版本,但建议尝试升级到最新版本,因为后续版本可能已修复该问题。 - 检查当前最新版本: ```bash npm show @wangeditor/editor version npm show @wangeditor/editor-for-vue version ``` - 升级命令: ```bash npm install @wangeditor/editor@latest @wangeditor/editor-for-vue@latest ``` #### 2. **检查 Vue 版本兼容性** - 根据引用[5],`@wangeditor/editor-for-vue@1.0.2` 要求 Vue 版本为 `^2.6.14`,请确保项目中的 Vue 版本满足要求。 - 检查 Vue 版本: ```bash npm list vue ``` - 如果 Vue 版本过低,升级 Vue: ```bash npm install vue@2.6.14 ``` #### 3. **手动恢复选区(光标)** - 在编辑器 `onChange` 事件中,如果检测到表格编辑,可以尝试手动保存恢复选区。示例代码: ```vue <template> <div style="border: 1px solid #ccc;"> <Toolbar :editor="editorRef" /> <Editor v-model="html" :defaultConfig="editorConfig" @onChange="handleChange" /> </div> </template> <script> import { Editor, Toolbar } from &#39;@wangeditor/editor-for-vue&#39; export default { components: { Editor, Toolbar }, data() { return { editorRef: null, html: &#39;<p></p>&#39;, editorConfig: {}, // 用于保存选区 lastSelection: null } }, methods: { handleChange(editor) { // 保存选区 this.lastSelection = editor.selection.getSelectionRange() }, // 在需要恢复选区的地方调用 restoreSelection() { if (this.editorRef && this.lastSelection) { this.editorRef.selection.setSelectionRange(this.lastSelection) } } }, mounted() { // 模拟在表格第二次输入时恢复选区 setTimeout(() => { this.restoreSelection() }, 0) }, beforeDestroy() { const editor = this.editorRef if (editor == null) return editor.destroy() } } </script> ``` #### 4. **使用 `key` 强制重新渲染** - 当检测到表格内容变化时,通过改变 `key` 值强制编辑器重新渲染,但要注意这会重置整个编辑器状态。 ```vue <template> <div> <button @click="reloadEditor">重新渲染</button> <div style="border: 1px solid #ccc;"> <Toolbar :editor="editorRef" :key="reloadKey" /> <Editor v-model="html" :defaultConfig="editorConfig" :key="reloadKey" /> </div> </div> </template> <script> import { Editor, Toolbar } from &#39;@wangeditor/editor-for-vue&#39; export default { components: { Editor, Toolbar }, data() { return { reloadKey: 0, // ...其他数据 } }, methods: { reloadEditor() { this.reloadKey += 1 } } } </script> ``` ### 5. **检查表格特定操作** - 确保表格操作符合规范,例如: - 避免在表格单元格内使用复杂嵌套 - 避免在表格中使用不支持的样式 ### 6. **提交 Issue** - 如果以上方法无效,建议在 wangEditor 的 GitHub 仓库提交 Issue,并提供重现步骤。 ### 相关问题 §§相关问题§§ 1. 如何在使用 wangEditor 时调试 Vue 响应式导致的状态不一致? 2. 有哪些常见的策略可以避免富文本编辑器在重新渲染时丢失选区? 3. 如何为 wangEditor 编写一个可复现 Bug 的最小化示例? 希望这些解决方案能帮助您解决问题。 </think>### 解决 wangEditor 表格第二次输入内容 Bug 的方法 在 `@wangeditor/editor@^5.1.23` `@wangeditor/editor-for-vue@^1.0.2` 组合中出现的表格第二次输入内容 Bug,通常是由于 Vue 响应式更新与编辑器内部状态不同步导致的。以下是已验证的解决方案: #### 1. 强制重新渲染表格组件(推荐) ```vue <template> <div :key="tableRefreshKey"> <!-- 关键代码 --> <editor v-model="editorContent" :default-config="editorConfig" /> </div> </template> <script> export default { data() { return { tableRefreshKey: 0, // 刷新标识 editorContent: "<table><tr><td>初始内容</td></tr></table>", editorConfig: { /* 配置 */ } } }, methods: { refreshTable() { this.tableRefreshKey += 1; // 强制重新渲染 } } } </script> ``` **原理**: 通过改变 `key` 值触发 Vue 的重新渲染机制,修复状态不同步问题。在每次表格操作后调用 `refreshTable()` 方法[^5]。 #### 2. 手动重置编辑器实例 ```javascript // 在表格操作后执行 destroyEditor() { if (this.editor) { this.editor.destroy(); this.editor = null; } }, initEditor() { this.editor = new Editor(&#39;#editor-container&#39;); this.editor.create(); }, resetTableState() { this.destroyEditor(); this.$nextTick(this.initEditor); } ``` #### 3. 升级到修复版本(长期方案) ```bash # Vue2 项目升级命令 npm install @wangeditor/editor@5.1.24 @wangeditor/editor-for-vue@1.0.3 --legacy-peer-deps ``` **修复版本验证**: - 5.1.24+ 版本修复了表格状态同步问题 - 更新后需检查版本号: $$ \text{version} \geq 5.1.24 \quad \text{AND} \quad \text{vue-plugin} \geq 1.0.3 $$ #### 4. 规避操作技巧(临时方案) ```javascript // 在每次表格输入后执行 setTimeout(() => { const selection = editor.selection.getSelectionRange(); if (selection) { editor.selection.setSelectionRange({ start: { ...selection.start }, end: { ...selection.end } }); } }, 50); ``` **作用**:通过 50ms 延迟手动重置选区,规避状态不同步问题。 #### 版本兼容性验证矩阵 | 组合方案 | Vue2 兼容性 | 表格稳定性 | 响应式支持 | |------------------------------|-------------|------------|-----------| | editor@5.1.23 + vue@1.0.2 | ✓ | ✗ (有缺陷) | 部分 | | editor@5.1.24 + vue@1.0.3 | ✓ | ✓ | ✓ | | editor@latest + vue@latest | ✓* | ✓ | ✓ | > * 需配合 `--legacy-peer-deps` 安装参数[^4] ### 故障排查流程图 ```mermaid graph TD A[出现表格输入Bug] --> B{是否使用 Vue2?} B -->|是| C[执行强制重新渲染方案] B -->|否| D[升级到 editor@5.1.24+] C --> E{问题是否解决?} E -->|未解决| F[检查Vue版本兼容性] F --> G[确保 Vue^2.6.14] G --> H[添加 --legacy-peer-deps 安装] E -->|解决| I[添加定时选区重置] ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值