近期后台项目有使用富文本编辑器的需求,本文记录一下封装细节
1.富文本组件库参考
- TinyMCE - 富文本编辑器里的 Word ,功能想不到的丰富
 - tiptap - 多人在线实时协同编辑
 - CKEditor 5 - 开源免费可商用,行内编辑
 - Quill - 易扩展、轻量级二开、代码高亮好用
 - Froala - 插件丰富,UI友好,编辑器里的苹果
 - summernote - 恰到好处的轻,可直接粘贴图片
 - Trumbowyg - 超轻量,体积小巧,仅 8KB
 
以上即是一些常见常用的富文本组件库,各组件库优缺点都有,具体就不详细踩坑分析。作者使用TinyMCE作为实例。
文档地址:TinyMCE中文文档 | TinyMCE官方文档
2.组件封装
- 安装相关依赖
 
pnpm add tinymce@^5 @tinymce/tinymce-vue
 
- 封装组件
 
<template>
  <div class="richtext-container">
    <Editor
      id="myedit" 
      v-model="content"
      :init="initProps"
      :disabled="readonly"
    />
  </div>
</template>
<script setup lang="ts">
import {reactive, ref, onMounted, watch, watchEffect} from 'vue'
import tinymce from 'tinymce/tinymce'
import Editor from '@tinymce/tinymce-vue'
import QiniuUpload from '@/utils/qnUpload'// 图片上传方法自行实现
// UI资源相关
import "tinymce/themes/silver"
import "tinymce/icons/default"
import "tinymce/icons/default/icons"
// 插件
import 'tinymce/plugins/image'
import 'tinymce/plugins/paste' //粘贴图片上传请务必引入此插件
const props = defineProps({
  modelValue:{
    type: String,
    default: ""
  },
  height:{
    type: Number,
    default: 278
  },
  readonly:{
    type: Boolean,
    default: true
  }
})
const emits = defineEmits(['update:modelValue'])
let content = ref()
const initProps = reactive({
  selector: '#myedit',
  readonly: props.readonly,
  height: props.height,
  resize: false,
  language_url: "/tinymce/langs/zh-Hans.js", //语言包路径
  language: "zh-Hans", //语言
  skin_url: "/tinymce/skins/ui/custom", // 定制样式资源路径
  content_css: '/tinymce/skins/ui/custom/content.min.css', // 定制样式资源路径
  branding: false,
  menubar: false,
  toolbar_sticky: true,
  toolbar_groups: false,
  elementpath: false,
  toolbar: `undo redo bold italic underline strikethrough
            removeformat subscript superscript | alignleft 
            aligncenter alignright alignjustify outdent indent |
            paste image`,
  plugins: 'image paste',
  paste_data_images: true,
  // 图片上传处理
  images_upload_handler: async(blobInfo:any, succFun:any, failFun:any)=>{
    let file = blobInfo.blob() 
    try {
      const data:any = await QiniuUpload(file,'image','xxx')
      succFun(data?.real_url)
    } catch (error) {
      failFun(error)
    }
  },
})
onMounted(() => {tinymce.init({})})
watchEffect(()=>{
  content.value = props.modelValue
})
watch(content,()=>{
  updateData()
})
const updateData = ()=>{
  emits('update:modelValue',content.value)
}
</script>
<style lang="less" scoped>
.richtext-container{
  :deep(.tox){
    .tox-statusbar{
      display: none;
    }
  }
}
</style>
 
- 组件使用
 
<template>
  <div>
    <my-richText v-model="richText" :readonly="false"></my-richText>
  </div>
</template>
<script setup lang="ts">
import { ref, watch } from 'vue'
let richText = ref('<p>哈哈哈哈呵呵呵呵</p>')
watch(richText,(val)=>{
  console.log(val)
})
</script>
 
- 效果展示

 
3.补充说明
- TinyMce富文本组件库因其丰富的配置及插件系统更受欢迎,init方法中的参数配置请详细阅读官方文档或中文文档。
 - 样式配置及汉化版教程请自行百度,因比较简单不做过多阐述。
 - 粘贴图片上传与工具栏中的图片上传有一些区别,粘贴图片上传请务必引入paste插件。
 - readonly属性作者配置不生效,在Editor上使用disabled可以实现同样的只读效果。
 


![[moeCTF 2023] pwn](https://img-blog.csdnimg.cn/4d8be170886d4b7e9aebc68d767c6ae6.png)
















