vue2实现wangEditor富文本便捷器的封装使用--真实项目

基于wangEditor 5实现一个简单的富文本编辑器组件,实现自定义上传图片。

官网地址:https://www.wangeditor.com/v5/for-frame.html#%E9%85%8D%E7%BD%AE

1. 安装依赖包:

npm i @wangeditor/editor --save
npm i @wangeditor/editor-for-vue --save

2. 封装组件代码:

<template>
    <div class="editor-wrapper">
        <toolbar
            :editor="editor"
            :default-config="toolbarConfig"
            :mode="mode"
        />
        <editor
            v-model="html"
            :style="{height: height + 'px'}"
            :default-config="editorConfig"
            :mode="mode"
            @onCreated="onCreated"
            @onChange="onChange"
        />
        <div v-if="maxlength" class="useful-num">
            {{ useLen }}/{{ maxlength }}
        </div>
    </div>
</template>

<script>
import fileApi from '@/api/file';
import '@wangeditor/editor/dist/css/style.css';
import {Editor, Toolbar} from '@wangeditor/editor-for-vue';

export default {
    name: 'customEditor',
    components: {
        Editor,
        Toolbar
    },
    model: {
        prop: 'value',
        event: 'change'
    },
    props: {
        value: {
            type: String,
            default: ''
        },
        maxlength: {
            type: Number,
            default: 0
        },
        height: {
            type: [String, Number],
            default: 300
        }
    },
    watch: {
        value(val) {
            this.html = val;
        }
    },
    data() {
        return {
            editor: null,
            html: '',
            toolbarConfig: { },
            editorConfig: {
                placeholder: '请输入内容',
                MENU_CONF: {
                    uploadImage: {
                        // 自定义图片上传功能
                        customUpload: (resultFile, insertImgFn) => {
                            const formData = new FormData();
                            formData.append('file', resultFile);
                            // 将文件上传至服务器,res.data返回服务器存放文件的url
                            fileApi.postFileUpload(formData).then(res => {
                                // 插入图片,三个参数分别对应,url alt href
                                insertImgFn(res.data, '', res.data);
                            });
                        }
                    },
                    uploadVideo: {
                        // 自定义视频上传功能
                        customUpload: (resultFile, insertImgFn) => {
                            const formData = new FormData();
                            formData.append('file', resultFile);
                            // 将文件上传至服务器,res.data返回服务器存放文件的url
                            fileApi.postFileUpload(formData).then(res => {
                                // 插入视频,三个参数分别对应,url alt href
                                insertImgFn(res.data, '', res.data);
                            });
                        }
                    }
                }
            },
            mode: 'default', // or 'simple'
            useLen: 0
        };
    },
    methods: {
        onCreated(editor) {
            this.editor = Object.seal(editor); // 一定要用 Object.seal() ,否则会报错
        },
        onChange() {
            const text = this.editor.getText();
            // 计算当前输入了多少文字
            this.useLen = (text || '').length;
            // 每次富文本内容改变,触发change事件
            this.$emit('change', this.html);
        }
    },
    beforeDestroy() {
        // editor销毁
        const editor = this.editor;
        if (editor == null) {
            return;
        }
        editor.destroy();
    }
};
</script>

<style lang="scss" scoped>
    .editor-wrapper{
        z-index: 3;
        position: relative;     
        /deep/.w-e-toolbar{
            z-index: 2!important;
            border: solid 1px #E6E9EC!important;
            border-top-left-radius: 6px;
            border-top-right-radius: 6px;
            .w-e-bar-item{
                padding: 1px;
            }
        }
        /deep/.w-e-text-container{
            z-index: 1!important;
            border: solid 1px #E6E9EC!important;
            border-top: none!important;
            border-bottom-left-radius: 6px;
            border-bottom-right-radius: 6px;
        }
    }
    .useful-num{
        position: absolute;
        right: 6px;
        bottom: 10px;
        z-index: 99999;
        font-size: 12px;
        color: $text-3;
        background: #fff;
        padding: 0 6px;
        height: 28px;
        line-height: 28px;
    }
</style>

3. 父组件使用:

<template>
    <editor
        v-model="html"
        :maxlength="8192"
        @change="change"
    />
</template>

<script>
import Editor from '@/components/Editor';
export default {
    name: 'EditorExample',
    components: {
        Editor
    },
    data() {
        return {
            html: ''
        };
    },
    methods: {
        change(val) {
            console.log(val);
        }
    }
};
</script>

4. 真实项目使用:

封装了wangEditor富文本组件,并且设置了数据回显;

TextRich/index.vue

<template>
  <div style="border: 1px solid #ccc; width: 100%">
    <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="handleCreated"
      @onChange="handleChange"
    />
  </div>
</template>
<script>
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
import { DomEditor } from '@wangeditor/editor'
import { set } from 'vue'
export default {
  components: {
    Editor,
    Toolbar
  },
  props: {
    value: {
      type: String,
      default: ''
    }
  },
  watch: {
    value(val) {
      setTimeout(()=>{
        this.html = val
      }, 1000)
    }
  },

  data() {
    return {
      editor: null,
      html: '',
      mode: 'default',
      editorConfig: {
        // placeholder: '请输入内容...',
        backColor: 'red', // 背景颜色
        MENU_CONF: {
          // 配置上传图片
          uploadImage: {
            customUpload: this.uploaadImg
          },
          uploadVideo: {
            customUpload: this.uploaadVideo
          }
        }
      },
      toolbarConfig: {}
    }
  },
  mounted() {
    // // 模拟 ajax 请求,异步渲染编辑器
    // setTimeout(() => {
    //   this.html =
    //     '<p>tupian </p><p>tupian</p><p><br></p><p><img src="https://img1.baidu.com/it/u=608404415,1639465523&fm=253&fmt=auto&app=120&f=JPEG?w=1280&h=800" alt="tupian" data-href="https://img1.baidu.com/it/u=608404415,1639465523&fm=253&fmt=auto&app=120&f=JPEG?w=1280&h=800" style=""/></p>'
    // }, 1500)
  },
  methods: {
    handleCreated(editor) {
      this.editor = Object.seal(editor) // 一定要用 Object.seal() ,否则会报错
      //   设置工具栏详情
      this.toolbarConfig = {
        excludeKeys: ['insertVideo', 'uploadVideo', 'group-video', 'fullScreen']
      }
    },
    handleChange(content) {
      const toolbar = DomEditor.getToolbar(content)
      //   查看工具栏列表toolbar.getConfig().toolbarKeys
      this.$emit('change', this.html)
    },
    uploaadImg(file, insertFn) {
      this.$emit('uploadImg', file, insertFn)
    },
    uploaadVideo(file, insertFn) {
      this.$emit('uploadVideo', file, insertFn)
    }
  },
  beforeDestroy() {
    const editor = this.editor
    if (editor == null) return
    editor.destroy() // 销毁编辑器
  }
}
</script>
<style src="@wangeditor/editor/dist/css/style.css"></style>

父组件使用:

父组件是在el-form表中使用的

<template>
  <div class="project-container">
    <el-form ref="form" :model="ruleForm" label-position="left" class="form">
      <el-form-item label="复现步骤" prop="reproduceStep" label-width="100px">
        <RichText v-model="ruleForm.reproduceStep" :readOnlys="readOnlys" @change="richTextChangeData" @uploadImg="richTextUploadImg"></RichText>
      </el-form-item>
    </el-form>
  </div>
</template>

<script lang="ts">
import Vue from 'vue'
import RichText from '@/components/RichText/index.vue'

export default Vue.extend({
  name: 'Index',
  components: {
    RichText
  },
  data() {
    return {
      ruleForm: {
        reproduceStep: ''
      }
    }
  },
  mounted() {
    this.setFormData()
  },

  methods: {
    richTextChangeData(val: string) {
      // 获取最新的html数据
      // this.ruleForm.reproduceStep = val
    },
    richTextUploadImg(file: any, insertFn: any) {
      // 插入图片,调接口返回图片url,通过插入conteng
      let imgUrl = 'https://img1.baidu.com/it/u=608404415,1639465523&fm=253&fmt=auto&app=120&f=JPEG?w=1280&h=800'
      insertFn(imgUrl)
      // 设置只读
      this.readOnlys = true
    },
    setFormData() {
      this.ruleForm.reproduceStep =
        '<p>tupian </p><p>tupian</p><p><br></p><p><img src="https://img1.baidu.com/it/u=608404415,1639465523&fm=253&fmt=auto&app=120&f=JPEG?w=1280&h=800" alt="tupian" data-href="https://img1.baidu.com/it/u=608404415,1639465523&fm=253&fmt=auto&app=120&f=JPEG?w=1280&h=800" style=""/></p>'
    }
  }
})
</script>


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/531692.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

windows组播发不出去解决办法

由于开启了虚拟网卡&#xff0c;安装VMWare虚拟化软件&#xff0c;可能会通过虚拟网卡发送组播&#xff0c;需要禁用虚拟化网卡。

c++作业day4

头文件&#xff1a; #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QTimer> #include <QTime> #include <QTextToSpeech> #include <QMessageBox> QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACEclass…

通过Telnet访问网络设备

要通过 Telnet 访问网络设备&#xff0c;需要通过Console端口对网络设备进行基本配置&#xff0c;例如&#xff0c;IP地址、子网掩码、用户名和登录密码等。本实验以路由器为例&#xff0c;交换机远程管理只是接口名字不同而已&#xff0c;路由器用物理接口&#xff0c;交换机用…

自己写的组件中使用v-model双向绑定

这里的时间选择表单是我写的一个组件&#xff0c;我想用v-model获取到实时的ref值。 代码&#xff1a; //父组件<TimePickerModal v-model:value"time" label-text"计划客面时间" /> const time ref(2024-04-09 15:20:00);//子组件<template>…

虚拟化性能计数器需要至少一个可正常使用的计数器

VMware 虚拟机报错&#xff1a;虚拟化性能计数器需要至少一个可正常使用的计数器。 截图如下&#xff1a; 解决方式参考下图操作即可

飞桨Ai(一)基于训练后的模型进行信息提取

基准 本博客基于如下视频&#xff1a; 发票抬头信息抽取之环境搭建 - 基于飞浆开源项目发票抬头信息抽取之数据标准模型训练 - 基于飞浆开源项目 步骤 1、准备工作 下载python&#xff1a;【Python】Windows&#xff1a;Python 3.9.2 下载和安装&#xff08;建议3.9&#…

蓝桥杯真题 字串简写 前缀和

&#x1f468;‍&#x1f3eb; Acwing 字串简写 输入 4 abababdb a b输出 6&#x1f496; 前缀和 import java.util.Scanner;public class Main {static int N (int) 5e5 10;static int[] l new int[N];// l[i] 表示 i 以及 i 左边包含多少个字符 apublic static void …

CesiumJS内置三维数字地球,你都不知道效果有多炫酷。

CesiumJS是一个开源的JavaScript库&#xff0c;用于在Web浏览器中创建高性能的3D地球和地理空间应用程序。它提供了强大的工具和API&#xff0c;使开发者能够构建具有交互性、可视化和地理空间分析功能的应用。 以下是CesiumJS的一些主要特点和功能&#xff1a; 3D地球可视化&…

基于RF的时间序列预测模型matlab代码

整理了基于RF的时间序列预测模型matlab代码&#xff0c; 包含数据集。采用了四个评价指标R2、MAE、MBE、MAPE对模型.效果优异 训练集数据的R2为&#xff1a;0.99656 测试集数据的R2为&#xff1a;0.94944 训练集数据的MAE为&#xff1a;0.0042509 测试集数据的MAE为&#x…

HarmonyOS 开发-Worker子线程中解压文件

介绍 本示例介绍在Worker 子线程使用ohos.zlib 提供的zlib.decompressfile接口对沙箱目录中的压缩文件进行解压操作&#xff0c;解压成功后将解压路径返回主线程&#xff0c;获取解压文件列表。 效果图预览 使用说明 点击解压按钮&#xff0c;解压test.zip文件&#xff0c;显…

基于Web的农产品销售管理系统

1 课题简介 1.1 选题背景 自宇宙出现盘古开天依赖&#xff0c;万事万物就在不断的进步更新淘汰弱者&#xff0c;现在到了如今人们进入了互联网上帝世纪&#xff0c;越来越多的事物和工作都可以在网上用数据流代替和执行&#xff0c;不必再像以前一样亲自出面和出门做事&#…

第9章 文件和内容管理

思维导图 9.1 引言 文件和内容管理是指针对存储在关系型数据库之外的数据和信息的采集、存储、访问和使用过程的管理。它的重点在于保持文件和其他非结构化或半结构化信息的完整性&#xff0c;并使这些信息能够被访问。文件和非结构化内容也应是安全且高质量的。 确保文件和内容…

0基础入门Playwright框架,赶紧上车!

自从2023年底playwright框架火起来之后&#xff0c;很多小伙伴都会来咨询我们这个框架相关内容&#xff0c;甚至问我们什么时候出这个课程。 这不&#xff0c;新课程终于在大家的千呼万唤中出来啦&#xff01;具体的课程大纲和试听视频&#xff01; Web自动化测试项目实战(Pyte…

【JavaWeb】JSP实现数据传递与保存

目录 JSP内置对象requestrequest对象的常用方法get与post区别 问题解决表单提交时中文乱码的问题 responseresponse对象的常用方法 思考请求的转发示例 转发与重定向的区别会话session对象常用方法session与窗口的关系示例&#xff1a;使用session实现访问控制 思考小结思考JSP…

AI大模型日报#0409:Llama 3下周发布、特斯联20亿融资、Karpathy新项目

导读&#xff1a; 欢迎阅读《AI大模型日报》&#xff0c;内容基于Python爬虫和LLM自动生成。目前采用“文心一言”生成了每条资讯的摘要。标题: 120亿Stable LM 2上线即开源&#xff01;2万亿token训练&#xff0c;碾压Llama 2 70B 摘要: Stable LM 2 12B参数版本发布&#x…

第一次在Vue里使用Swiper插件轮播先看这里,报错!!!(不同swiper在页面引入时方式不同,步步扫雷ing)

现在用新插件前有了个概念&#xff0c;一定要看它官方文档&#xff0c;因为不你项目版本与你想用的插件版本间是有规定的&#xff0c;不应该直接看别人已经实现就跟着哐哐下载然后不停报错。。。 比如Swiper版本问题的大小写问题&#xff1a; 3.x 版本的 ---- 引入模块时使用小…

爬虫 selenium

爬虫 selenium 【一】介绍 【1】说明 Selenium是一款广泛应用于Web应用程序测试的自动化测试框架 它可以模拟用户再浏览器上的行为对Web应用进行自动化测试 主要作用&#xff1a; 浏览器控制&#xff1a;启动、切换、关闭不同浏览器元素定位于操作&#xff1a;通过CSS选择器…

C++笔记(函数重载)

目录 引入&#xff1a; 定义&#xff1a; 易错案例&#xff1a; 引入&#xff1a; 对于实现相似功能的函数&#xff0c;在命名时&#xff0c;我们常会出现命名重复的问题。对于C语言&#xff0c;编译器遇到这种命名重复的情况&#xff0c;会进行报错。而我们的C为了更方便程…

mineadmin 设置时区

由于不同环境下&#xff0c;会造成时区不一致问题 在/bin/hyperf.php 文件里&#xff0c;设置 date_default_timezone_set(Asia/Shanghai);

【AIGC】训练数据入库(Milvus)

之前的文章有写如何获取数据、如何补充数据&#xff0c;也有说如何对数据进行清洗、如何使用结构化数据进行训练。但好像没有说如何将训练数据“入库”。这里说的入库不是指 MySQL 数据库&#xff0c;而是指向量检索库 Milvus。 众所周知&#xff0c;人工智能多用向量数据进行…