vue3 +ts 项目 实现富文本编辑 获取数据,数据回显

需求:
描述栏 使用富文本编辑器 可以文本操作,可以图片,可以表格,超链接等
实现效果:
在这里插入图片描述
代码:

1. 新建文件夹 /components/ToastuiEditor/index.vue 文件

封装的富文本内容 组件。(代码见第四条)

2. 引入插件

npm install --save @toast-ui/editor
npm i process
// 强大的异步专家process.nextTick()
@toast-ui/editor-plugin-chart:图表插件 
@toast-ui/editor-plugin-code-syntax-highlight:高亮插件 
@toast-ui/editor-plugin-color-syntax:颜色选择插件
@toast-ui/editor-plugin-table-merged-cell:
表格合并行列插件 @toast-ui/editor-plugin-uml:uml插件

3.使用 :

<template>
  <div>
    <el-form :model="formDialogCommon" class="demo-form-top">
        <el-form-item label="描述:">
            <toastui-editor
                ref="refToastuiEditor"
                id="ToastuiEditor1"
                style="width: 100%"
            ></toastui-editor>
        </el-form-item>
    </el-form>
        <div class="dialog-from-button">
            <el-button size="small" type="info">取消</el-button>
            <el-button type="primary" size="small" @click="fromSubmit()"
            >确认</el-button>
        </div>
  </div>
</template>

<script lang="ts">
import {
  defineComponent,
  reactive,
  ref
} from 'vue'
//引入封装的组件
import ToastuiEditor from '@/components/ToastuiEditor/index.vue'

export default defineComponent({
  name: 'App',
  components: { ToastuiEditor },
  setup() {
    const formDialogCommon = reactive({
      richText: '',
    })
    const refToastuiEditor = ref()
    // 编辑
    const compileClick = async(v: any) => {
        if (v.showText) {
          refToastuiEditor.value.setHTML(v.showText)
          //用于数据回显 (v.showText表示需要回显的数据)
        }
    }
    // 确认
    const fromSubmit = () => {
        const richTextHtml: string = refToastuiEditor.value.getHTML()
        formDialogCommon.richText = richTextHtml
        // 获取到数据 formDialogCommon.richText 用于传递给接口
    }
    return {
      refToastuiEditor,
      fromSubmit,
      compileClick
    }
  }
})
</script>

4. 封装

//components/ToastuiEditor/index.vue 文件
<template>
  <div v-if="id" :id="id"></div>
</template>

<script lang="ts">
import '@toast-ui/editor/dist/i18n/zh-cn.js' // 工具栏显示中文
import '@toast-ui/editor/dist/toastui-editor.css'
import Editor, { EditorCore } from '@toast-ui/editor'
import { reactive } from '@vue/reactivity'
import { defineComponent, onMounted, ref } from 'vue'
import { nextTick } from 'process'
import { ElMessage } from 'element-plus'
export default defineComponent({
  name: 'ToastuiEditor',
  props: ['id', 'height', 'initialEditType'],
  setup(props) {
    const editorText = ref('This is initialValue.')
    const editorOptions = reactive({
      hideModeSwitch: true
    })
    // 压缩方法
    const dealImage = (base64: string, w: number, callback: { (arg2: any, e: any): void; (arg0: string): void }) => {
      const newImage = new Image()
      // 压缩系数0-1之间
      let quality = 0.6
      newImage.src = base64
      newImage.setAttribute('crossOrigin', 'Anonymous') // url为外域时需要
      let imgWidth, imgHeight
      newImage.onload = function() {
        imgWidth = window.innerWidth
        imgHeight = window.innerHeight
        const canvas = document.createElement('canvas')
        const ctx = canvas.getContext('2d')
        if (Math.max(imgWidth, imgHeight) > w) {
          if (imgWidth > imgHeight) {
            canvas.width = w
            canvas.height = (w * imgHeight) / imgWidth
          } else {
            canvas.height = w
            canvas.width = (w * imgWidth) / imgHeight
          }
        } else {
          canvas.width = imgWidth
          canvas.height = imgHeight
          quality = 0.6
        }
        ctx?.clearRect(0, 0, canvas.width, canvas.height)
        ctx?.drawImage(newImage, 0, 0, canvas.width, canvas.height)
        // ctx?.drawImage(this:GlobalEventHandlers, 0, 0, canvas.width, canvas.height)
        const ba = canvas.toDataURL('image/jpeg', quality) // 压缩语句
        // 如想确保图片压缩到自己想要的尺寸,如要求在50-150kb之间,请加以下语句,quality初始值根据情况自定
        while (base64.length / 1024 > 150) {
          quality -= 0.01
          base64 = canvas.toDataURL('image/jpeg', quality)
        }
        // 防止最后一次压缩低于最低尺寸,只要quality递减合理,无需考虑
        while (base64.length / 1024 < 50) {
          quality += 0.001
          base64 = canvas.toDataURL('image/jpeg', quality)
        }
        callback(ba) // 必须通过回调函数返回,否则无法及时拿到该值
      }
    }
    const fileOrBlobToDataURL = (obj: Blob, cb: { (dataurl: string, obj: { size: number }): void; (arg0: any, arg1: any): void }) => {
      const a: FileReader = new FileReader()

      a.readAsDataURL(obj)
      a.onload = (e: any) => {
        cb(e.target.result, obj)
      }
    }
    const blobToImage = (blob: any, callback: (arg0: string) => void) => {
      return fileOrBlobToDataURL(blob, function(dataurl: string, obj: { size: number }) {
        // const img = new Image();

        // 获取大小,大于2兆缩小操作
        // console.log((obj.size / 1048576).toFixed(2))
        if (Number((obj.size / 1048576).toFixed(2)) > 2) {
          dealImage(dataurl, 1200, (e: string) => {
            dataurl = e
            callback(dataurl)
          })
        } else {
          callback(dataurl)
        }
      })
    }
    let currentEditor: Editor = null as unknown as Editor
    const setHTML = (value: string) => {
      if (currentEditor) {
        currentEditor.setHTML(value)
      }
    }
    const getHTML = () => {
      if (currentEditor) {
        return currentEditor.getHTML()
      }
    }
    onMounted(() => {
      nextTick(() => {
        currentEditor = new Editor({
          language: 'zh-CN',
          el: document.querySelector('#' + props.id) as HTMLElement,
          height: props.height ? props.height : '400px',
          initialEditType: props.initialEditType
            ? props.initialEditType
            : 'wysiwyg',
          hooks: {
            addImageBlobHook: (blob: any, callback: (arg0: string) => void) => {
              // 查询有现有文本含有多少张图片
              const re = /<img[^>]+src="[^"]+"[^>]*>/gim // 创建正则表达式模式。; // 声明变量。
              const text = currentEditor!.getHTML()
              const r = text.match(re) || [] // 尝试去匹配搜索字符串。
              if (r.length >= 10) {
                ElMessage({
                  message: '最多十张',
                  type: 'warning'
                })
              } else {
                blobToImage(blob, callback)
              }
            }
          }
        }) as Editor
      })
    })
    return {
      editorText,
      editorOptions,
      currentEditor,
      setHTML,
      getHTML
    }
  }
})
</script>
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

王小王和他的小伙伴

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值