【TinyMCE@5.x + Vue3 + Ts 使用】

TinyMCE@5.x + Vue3 + Ts 使用

  1. 安装依赖

    npm install tinymce -S
    npm install @tinymce/tinymce-vue -S
    
  2. 汉化

    官网 下载汉化包 选择zh_CN

  3. 皮肤汉化包放到项目public中(public里面文件引入时文件名称保持原文件名,不做改变)

    3.1 在项目public文件夹下新建tinymce文件夹,
    3.2 将下载的汉化包解压到此文件夹
    3.3 然后在node_modules/tinymce中找到skins文件夹,也复制到public/tinymce里

  4. 组件封装

     ```
     <template>
       <div w-full>
         <editor-dom v-model="myValue" :init="init" :disabled="disabled" />
         <input :id="id" type="file" :accept="imgAccept" hidden />
       </div>
     </template>
     
     <script lang="ts" setup>
     import { useStore } from '@/stores'
     import logo from '@/assets/image/logo.png'
     
     import type { Editor } from 'tinymce'
     import tinymce from 'tinymce/tinymce'
     import EditorDom from '@tinymce/tinymce-vue'
     
     import 'tinymce/themes/silver/theme'
     import 'tinymce/icons/default'
     import 'tinymce/models/dom'
     import 'tinymce/plugins/advlist'
     import 'tinymce/plugins/autolink'
     import 'tinymce/plugins/lists'
     import 'tinymce/plugins/link'
     import 'tinymce/plugins/image'
     import 'tinymce/plugins/charmap'
     import 'tinymce/plugins/preview'
     import 'tinymce/plugins/anchor'
     import 'tinymce/plugins/searchreplace'
     import 'tinymce/plugins/visualblocks'
     import 'tinymce/plugins/code'
     import 'tinymce/plugins/fullscreen'
     import 'tinymce/plugins/insertdatetime'
     import 'tinymce/plugins/media'
     import 'tinymce/plugins/table'
     import 'tinymce/plugins/template'
     // import 'tinymce/plugins/help'
     import 'tinymce/plugins/wordcount'
     import { ElMessage } from 'element-plus'
     
     const store = useStore()
     
     interface Props {
       id?: string
       modelValue?: string
       height?: string | number
       width?: string | number
       disabled?: boolean
       showDel?: boolean
     }
     
     const props = withDefaults(defineProps<Props>(), {
       modelValue: '',
       id: 'vue-tinymce-' + new Date() + ((Math.random() * 1000).toFixed(0) + ''),
       height: 200,
       width: 'auto',
       disabled: false,
       showDel: false
     })
     
     const emits = defineEmits<{
       (e: 'update:modelValue', value: string): void
     }>()
     
     const myValue = computed({
       get() {
         return props.modelValue
       },
       set(value) {
         emits('update:modelValue', value)
       }
     })
     
     const oldValue = ref<string>()
     const imgAccept = ref<string>(
       '.bmp,.jpg,.png,.tif,.gif,.pcx,.tga,.exif,.fpx,.svg,.psd,.cdr,.pcd,.dxf,.ufo,.eps,.ai,.raw,.WMF,.webp,.avif,.apng'
     )
     const exampleImageUploadHandler = (blobInfo: Record<string, unknown>): Promise<string> =>
       new Promise((resolve, reject) => {
         const formData = new FormData()
         formData.append('file', (blobInfo.blob as () => Blob)(), (blobInfo.filename as () => string)())
         store
           .upFile(formData)
           .then(res => {
             if (res.data) {
               resolve(res.data)
             } else {
               resolve('')
             }
           })
           .catch(err => reject(err))
       })
     
     const setup = (editor: typeof Editor): void => {
       editor.ui.registry.addButton('imageUpload', {
         tooltip: '图片',
         icon: 'image',
         onAction: () => {
           //点击按钮后执行
           oldValue.value = props.modelValue
           const input = document.getElementById(props.id) as HTMLInputElement | null
           if (!input) {
             ElMessage.warning('上传失败,请刷新当前页面。')
             return
           }
           input.click()
           input.onchange = function () {
             if (!input.files) {
               ElMessage.warning('请选择图片上传')
               input.value = ''
               return
             }
             const file = input.files[0]
             const formData = new FormData()
             formData.append('file', file)
             if (!imgAccept.value.includes(file.name.substring(file.name.indexOf('.')))) {
               ElMessage.warning('请选择图片上传')
               input.value = ''
               return
             }
             store.upFile(formData).then(res => {
               if (res.data) {
                 editor.insertContent("<img src='" + res.data.file + "' alt=''/>")
                 input.value = ''
               } else {
                 editor.setContent(oldValue.value as string)
               }
             })
           }
         }
       })
     }
     const init = reactive({
       selector: `#${props.id}`,
       content_style: 'p {margin: 0; border:0; padding: 0;}',
       content_css: '/tinymce/skins/content/default/content.css',
       language_url: '/tinymce/langs/zh-Hans.js', // https://www.tiny.cloud/get-tiny/language-packages/
       language: 'zh-Hans',
       skin_url: '/tinymce/skins/ui/oxide',
       height: props.height,
       promotion: false, //隐藏右上角upgrade按钮
       branding: false, //隐藏右下角由TINY驱动
       menubar: false, // 是否隐藏顶部菜单
       contextmenu_never_use_native: true, //防止浏览器上下文菜单出现在编辑器中
       elementpath: false, //隐藏底栏的元素路径(隐藏右下角元素显示)
       object_resizing: true, //是否允许调整图像大小.
       toolbar:
         'undo redo | blocks fontfamily | forecolor bold italic backcolor |' +
         'align bullist numlist | outdent indent | table | imageUpload |' +
         'removeformat | hr | template | preview fullscreen',
       plugins: [
         'advlist',
         'autolink',
         'lists',
         'link',
         'image',
         'charmap',
         'preview',
         'anchor',
         'searchreplace',
         'visualblocks',
         'code',
         'fullscreen',
         'insertdatetime',
         'media',
         'table',
         'wordcount',
         'template'
       ],
       // paste_data_images: false, //此选项指定是否应从粘贴的内容中删除图像
       paste_webkit_styles: 'all', //此选项允许您指定粘贴到 WebKit 中时要保留的样式 'none' 或者 'all'
       // paste_merge_formats: true, //此选项在粘贴内容时启用合并格式功能。这将合并相同的文本格式元素,以减少生成的 HTML 元素的数量
       advlist_bullet_styles: 'default,circle,disc,square',
       // advlist_number_styles: 'default,lower-alpha,lower-greek,lower-roman,upper-alpha,upper-roman',
       link_default_target: '_blank',
       link_title: false, //此选项允许您禁用对话框中的链接输入字段
       nonbreaking_force_tab: true, //tab键插入三个&nbsp;
       images_upload_handler: exampleImageUploadHandler,
       setup: setup,
       template_replace_values: {
         logoSrc: logo
       },
       template_preview_replace_values: {
         logoSrc: logo
       },
       templates: [
         {
           title: '制度',
           description: '用于插入制度相关内容。',
           content:
             '<p style="text-align: center;"><img style="float: left;" src="{$logoSrc}" alt="" width="120" height="37.5" />祝工作愉快,身体健康!</p>'
         },
         {
           title: '通报',
           description: '用于插入通报相关内容。',
           content:
             '<p style="text-align: center;"><img style="float: left;" src="{$logoSrc}" alt="" width="120" height="37.5">感谢大家的理解和支持!</p>\n<p>&nbsp;</p>\n<p style="text-align: left;">&nbsp;</p>\n<p style="text-align: right;">XXX科技有限公司</p>\n<p style="text-align: right;">2023 年 9 月 6日</p>'
         },
         {
           title: '通知',
           description: '用于插入通知相关内容。',
           content:
             '<p style="text-align: center;"><img style="float: left;" src="{$logoSrc}" alt="" width="120" height="37.5"></p>\n<p style="text-align: right; line-height: 1;">&nbsp;</p>'
         }
       ]
     })
     
     onMounted(() => {
       tinymce.init({})
     })
     </script>
     
     <style scoped></style>
     <style>
     .tox-tinymce-aux {
       z-index: 3035 !important;
     }
     
     .tox .tox-toolbar__group {
       padding: 0 3px 0 5px !important;
     }
     </style>
     
     ```
    
  5. TS 配置 (Vite)
    types文件夹下 新增文件 tinymce.d.ts

    // TinyMce 富文本
    
    declare module 'tinymce'
    declare module 'tinymce/tinymce'
    declare module '@tinymce/tinymce-vue'
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值