vue3 + tinymc 中文汉化、上传图片 && 限制图片上传大小、预览编写的内容

插件安装及版本说明

Node.js v18.19.0

"@tinymce/tinymce-vue": "^5.1.1"
"tinymce": "^6.8.3"

npm i @tinymce/tinymce-vue@5.1.1 tinymce@6.8.3

components

Editor.vue


<script setup>
import {onMounted} from "vue";
import tinymce from 'tinymce/tinymce'; //tinymce核心文件

import 'tinymce/models/dom'; // 引入dom模块。从 Tinymce6,开始必须有此模块导入
import 'tinymce/themes/silver'; //默认主题
import 'tinymce/icons/default'; //引入编辑器图标icon,不引入则不显示对应图标

// import 'tinymce/skins/ui/oxide/skin.css' // 我这里插件引入显示异常,改为本地引用
// 以下编辑器插件功能需要的自行引入,node_modules/tinymce/plugins下存在的插件都可以引用
import 'tinymce/plugins/advlist'; //高级列表
import 'tinymce/plugins/anchor'; //锚点
import 'tinymce/plugins/autolink'; //自动链接
import 'tinymce/plugins/autoresize'; //编辑器高度自适应,注:plugins里引入此插件时,Init里设置的height将失效
import 'tinymce/plugins/autosave'; //自动存稿
import 'tinymce/plugins/charmap'; //特殊字符
import 'tinymce/plugins/code'; //编辑源码
import 'tinymce/plugins/codesample'; //代码示例
import 'tinymce/plugins/directionality'; //文字方向
import 'tinymce/plugins/emoticons'; //表情
import 'tinymce/plugins/fullscreen'; //全屏
import 'tinymce/plugins/help'; //帮助
import 'tinymce/plugins/image'; //插入编辑图片
import 'tinymce/plugins/importcss'; //引入css
import 'tinymce/plugins/insertdatetime'; //插入日期时间
import 'tinymce/plugins/link'; //超链接
import 'tinymce/plugins/lists'; //列表插件
import 'tinymce/plugins/nonbreaking'; //插入不间断空格
import 'tinymce/plugins/pagebreak'; //插入分页符
import 'tinymce/plugins/preview'; //预览
import 'tinymce/plugins/quickbars'; //快速工具栏
import 'tinymce/plugins/save'; //保存
import 'tinymce/plugins/searchreplace'; //查找替换
import 'tinymce/plugins/table'; //表格
import 'tinymce/plugins/visualblocks'; //显示元素范围
import 'tinymce/plugins/visualchars'; //显示不可见字符
import 'tinymce/plugins/wordcount'; //字数统计

const emits = defineEmits(['changeContent'])
const props = defineProps({
  text: String,
})

const id = 'vue-tinymce-' + +new Date() // 这里是防止页面路由跳转tinymce会有空白异常显示
onMounted(() => {
  console.log("onMounted");
  tinymce.init({
    selector: `#${id}`,
    forced_root_block: '',
    // 路径引用自定义,只要能访问到资源即可
    language_url: `${import.meta.env.VITE_PUBLIC_PATH}langs/zh_CN.js`, // 本地引用langs语言文件,下面有下载地址
    language: 'zh_CN',
    draggable_modal: true,
    promotion:false, //Upgrade是否开启
    branding: false, //tiny技术支持信息是否显示
    // statusbar: false, // 是否显示输入框下面的工具栏
    // 路径引用自定义,只要能访问到资源即可
    skin_url: `${import.meta.env.VITE_PUBLIC_PATH}skins/ui/oxide`, // 复制node_modules/tinymce/skins放在本地
    content_style: "p {margin: 0px; border:0px ; padding: 0px;}",  // 设置行间距
    toolbar: 'undo redo  forecolor | styles elect | bold italic | link image | alignleft aligncenter alignright | preview',
    plugins: 'image code preview',
    images_upload_handler: (blobInfo, progress) => new Promise((resolve, reject) => {

      const formData = new FormData();
      const file = blobInfo.blob()
      if (file.size > 2 * 1024 * 1024) {
        // 限制图片大小
        reject('请上传小于2M的图片!');
        return
      }
      const xhr = new XMLHttpRequest();
      xhr.withCredentials = false;
      xhr.open('POST', 'https://xxx/file/uploadLocalFile');
      xhr.upload.onprogress = (e) => {
        progress(e.loaded / e.total * 100);
      };
      xhr.onload = () => {
        if (xhr.status === 403) {
          reject({ message: 'HTTP Error: ' + xhr.status, remove: true });
          return;
        }
        if (xhr.status < 200 || xhr.status >= 300) {
          reject('HTTP Error: ' + xhr.status);
          return;
        }
        const json = JSON.parse(xhr.responseText);
        if (!json || typeof json.data != 'string') {
          reject('Invalid JSON: ' + xhr.responseText);
          return;
        }
        resolve(json.data);
      };
      xhr.onerror = () => {
        reject('Image upload failed due to a XHR Transport error. Code: ' + xhr.status);
      };
      formData.append('file', file, blobInfo.filename());
      xhr.send(formData);
    }),
    images_reuse_filename: true, // 使用图片文件实际的文件名
    // style_formats: [
    //   {title: 'Bold text', inline: 'b'},
    //   {title: 'Red text', inline: 'span', styles: {color: '#ff0000'}},
    //   {title: 'Red header', block: 'h1', styles: {color: '#ff0000'}},
    //   {title: 'Example 1', inline: 'span', classes: 'example1'},
    //   {title: 'Example 2', inline: 'span', classes: 'example2'},
    //   {title: '首行缩进', block: 'p', styles: {'text-indent': '2em'}},
    //   {title: 'Table styles'},
    //   {title: 'Table row 1', selector: 'tr', classes: 'tablerow1'}
    // ],
    // style_formats_merge: true,
    // style_formats_autohide: true,
    setup(editor) {
      editor.on('init', function () {
        editor.setContent(props.text); // 数据回填显示,一定要在这个函数里,要不然会有数据空白显示
      });
      editor.on('change', function () {
        emits('changeContent', { text: editor.getContent() }) // 数据更改传递出去给父组件
      });
    },
  })
})
</script>

<template>
  <textarea :id="id" :key="id"></textarea>
</template>

语言文件下载

language-packages语言文件选择
zh_CN中文版本直接点击下载

使用组件

import Editor from '/@/components/Editor.vue'
import {ref} from 'vue'

const editorVal = ref('')

// ⚠️注意是否造成editorVal循环引用
<Editor :text="editorVal" @change-content="changeContent" />


function changeContent({text}) {
  console.log(text)
  editorVal.value = text
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Amodoro

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

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

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

打赏作者

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

抵扣说明:

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

余额充值