当前位置: 首页 > article >正文

vue3 tinymce6版本 完美适配基本需求(特殊需求外)

直接上代码 然后根据自己需求来调整代码内的toolbar功能设置
另外添加两个没有plugin的插件 首行缩进 以及调整段落大小 (目前没有太细看文档 不入门也不太好看懂~) 我这是从版本4升级到6的
已解决弹窗上使用问题
后面会出个相关配置文档的

代码

<template>
  <div class="tinymce-boxz">
    <Editor v-model="content" :api-key="apiKey" :init="init" />
  </div>
</template>

<script>
import Editor from '@tinymce/tinymce-vue';
import { reactive, ref, toRefs, watchEffect } from 'vue';
import axios from 'axios';
export default {
  name: 'Tinymce',
  components: {
    Editor,
  },
  props: {
    //默认值
    modelValue: {
      type: String,
      default: '',
    },
  },

  setup(props, context) {
    const content = ref(props.modelValue);
    // 监听 props.modelValue,确保父组件数据变化时同步到本地
    watch(
      () => props.modelValue,
      (newValue) => {
        content.value = newValue;
      }
    );
    // 监听本地 content 值的变化,向父组件发出更新事件
    watchEffect(() => {
      context.emit('update:modelValue', content.value);
    });

    const uploadUrl = ref(
      import.meta.env.VITE_APP_BASE_API + '/common/uploadOneFileToQiniu'
    );

    const tiny = reactive({
      apiKey: '9i8khq1jzwwj7hda35fpc0q1e14zsb4ev23vaif34nqif0fw', //https://github.com/tinymce/tinymce-vue/blob/main/src/demo/views/Iframe.vue
      init: {
        language: 'zh_CN', //语言类型
        placeholder: '在这里输入文字', //textarea中的提示信息
        min_width: 320,
        min_height: 220,
        height: 500, //注:引入autoresize插件时,此属性失效
        resize: 'both', //编辑器宽高是否可变,false-否,true-高可变,'both'-宽高均可,注意引号
        branding: false, //tiny技术支持信息是否显示
        // statusbar: false,  //最下方的元素路径和字数统计那一栏是否显示
        // elementpath: false, //元素路径是否显示
        // 自定义设置paragraphspacing的值

        fontsize_formats: '12px 14px 16px 18px 20px 22px 24px 28px 32px',
        font_formats:
          '微软雅黑=Microsoft YaHei,Helvetica Neue,PingFang SC,sans-serif;苹果苹方=PingFang SC,Microsoft YaHei,sans-serif;宋体=simsun,serif;仿宋体=FangSong,serif;黑体=SimHei,sans-serif;Arial=arial,helvetica,sans-serif;Arial Black=arial black,avant garde;Book Antiqua=book antiqua,palatino;', //字体样式
        plugins:
          'print preview searchreplace autolink directionality visualblocks visualchars fullscreen image link media template code codesample table charmap hr pagebreak nonbreaking anchor insertdatetime advlist lists wordcount textpattern autosave emoticons  paragraphspacing', //插件配置 axupimgs indent2em
        toolbar: [
          'fullscreen undo redo restoredraft | cut copy paste pastetext | forecolor backcolor bold italic underline strikethrough link anchor | alignleft aligncenter alignright alignjustify outdent indent | bullist numlist | blockquote subscript superscript removeformat ',
          'styleselect formatselect fontselect fontsizeselect |  table image axupimgs media emoticons charmap hr pagebreak insertdatetime  selectall visualblocks searchreplace | code print preview |  lineheight formatpainter | indent2em  | paragraphspacing ',
        ], //工具栏配置,设为false则隐藏
        setup: function (editor) {
          editor.ui.registry.addButton('indent2em', {
            text: '首行缩进',
            onAction: function () {
              editor.execCommand('Indent2Em');
            },
          });

          editor.addCommand('Indent2Em', function () {
            const content = editor.selection.getNode(); // 获取当前选中段落
            const style = content.style.textIndent; // 检查是否已有缩进
            if (style === '2em') {
              content.style.textIndent = ''; // 如果已有缩进,则清除
            } else {
              content.style.textIndent = '2em'; // 设置为 2em
            }
          });
          // 段落间距插件
          editor.ui.registry.addMenuButton('paragraphspacing', {
            text: '段落间距',
            tooltip: '设置段落间距',
            fetch: function (callback) {
              const paragraphspacing = [
                '4px',
                '6px',
                '8px',
                '10px',
                '12px',
                '14px',
                '16px',
                '18px',
                '22px',
                '24px',
                '26px',
                '28px',
              ];
              let selectedItem = '0px';
              const items = paragraphspacing.map(function (item) {
                return {
                  type: 'togglemenuitem',
                  text: item,
                  onAction: function () {
                    selectedItem = item;
                    editor.undoManager.transact(function () {
                      editor.focus();
                      editor.formatter.register({
                        paragraphspacing: {
                          block: 'p',
                          styles: { margin: `${item} 0` },
                        },
                      });
                      editor.formatter.apply('paragraphspacing', {
                        value: item,
                      });
                    });
                  },
                  onSetup: function (api) {
                    api.setActive(selectedItem === item);
                  },
                };
              });
              callback(items);
            },
          });
        },
        // menubar: "file edit my1", //菜单栏配置,设为false则隐藏,不配置则默认显示全部菜单,也可自定义配置--查看 http://tinymce.ax-z.cn/configure/editor-appearance.php --搜索“自定义菜单”

        // images_upload_url: '/apib/api-upload/uploadimg',  //后端处理程序的url,建议直接自定义上传函数image_upload_handler,这个就可以不用了
        // images_upload_base_path: '/demo',  //相对基本路径--关于图片上传建议查看--http://tinymce.ax-z.cn/general/upload-images.php
        paste_data_images: true, //图片是否可粘贴
        //此处为图片上传处理函数
        images_upload_handler: (blobInfo, success, failure) => {
          // 这里用base64的图片形式上传图片,
          let reader = new FileReader(); //本地预览
          reader.readAsDataURL(blobInfo.blob());
          reader.onloadend = function () {
            const imgbase64 = reader.result;
            success(imgbase64);
            console.log(imgbase64, '图片地址');
          };
        },

        file_picker_types: 'file image media', //file image media分别对应三个类型文件的上传:link插件,image和axupimgs插件,media插件。想屏蔽某个插件的上传就去掉对应的参数
        // 文件上传处理函数
        file_picker_callback: function (callback, value, meta) {
          // meta.filetype  //根据这个判断点击的是什么file image media
          let filetype; //限制文件的上传类型,需要什么就添加什么的后缀
          if (meta.filetype == 'image') {
            filetype = '.jpg, .jpeg, .png, .gif, .ico, .svg';
          } else if (meta.filetype == 'media') {
            filetype = '.mp3, .mp4, .avi, .mov';
          } else {
            filetype =
              '.pdf, .txt, .zip, .rar, .7z, .doc, .docx, .xls, .xlsx, .ppt, .pptx, .mp3, .mp4, .jpg, .jpeg, .png, .gif, .ico, .svg';
          }
          console.log(filetype, '类型', value, 'value');
          let inputElem = document.createElement('input'); //创建文件选择
          inputElem.setAttribute('type', 'file');
          inputElem.setAttribute('accept', filetype);
          inputElem.click();
          inputElem.onchange = () => {
            let file = inputElem.files[0]; // 获取文件对象
            if (!file) return; // 如果未选择文件,直接返回
            // 使用 FormData 上传文件
            let formData = new FormData();
            formData.append('file', file); // 假设服务端要求的字段名是 'file'

            // 上传到服务器
            axios
              .post(uploadUrl.value, formData, {
                headers: {
                  'Content-Type': 'multipart/form-data',
                },
              })
              .then((res) => {
                console.log(res, '上传成功返回的文件 URL');
                // 成功后回调,将文件 URL 插入编辑器
                callback(res.data.url, { title: res.data.fileName });
              });
          };
        },
      },
    });

    //内容有变化,就更新内容,将值返回给父组件
    watchEffect(() => {
      context.emit('update:value', content.value);
    });

    return {
      content,
      ...toRefs(tiny),
    };
  },
};
</script>

<style scoped>
.tinymce-boxz > textarea {
  display: none;
}
</style>
<style>
/* 隐藏apikey没有绑定这个域名的提示 */
.tox-notifications-container .tox-notification--warning {
  display: none !important;
}

.tox.tox-tinymce {
  max-width: 100%;
}

/* 在el-dialog中tinymce z-index 被太小而被遮挡时要加这两句 */
.tox-tinymce-aux {
  z-index: 99999 !important;
}

.tinymce.ui.FloatPanel {
  z-index: 99;
}
</style>

依赖

在这里插入图片描述


http://www.kler.cn/a/413982.html

相关文章:

  • 【爬虫框架:feapder,管理系统 feaplat】
  • Vue+Elementui el-tree树只能选择子节点并且支持检索
  • [保姆式教程]使用labelimg2软件标注定向目标检测数据和格式转换
  • 电子应用设计方案-28:智能云饭锅系统方案设计
  • web博客系统的自动化测试
  • Python学习35天
  • Python绘画:玫瑰与代码的艺术之美
  • 百问FB显示开发图像处理 - BMP图像处理
  • 健康养生:开启活力生活的密码
  • gnome-terminal-server与bash的关系
  • node.js基础学习-http模块-JSONP跨域传值(四)
  • GPT相关的学术库——收藏更新自用
  • Spring Boot教程之十一:获取Request 请求 和 Put请求
  • MAC卸载Vmware Fusion后无法再安装解决方案
  • 酷!用豆包MarsCode 写了一个五子棋小游戏
  • 深入理解 JavaScript 中的 AbortController
  • CentOS 7安装mysql+JDK+Tomcat完成流程
  • IT人日常健康工作生活方案
  • Spring Boot英语知识平台:构建与实践
  • 1、Three.js开端准备环境
  • HarmonyOS4+NEXT星河版入门与项目实战(22)------动画(属性动画与显示动画)
  • Python语法基础(二)
  • GitLab的使用
  • #渗透测试#红蓝攻防#HW#漏洞挖掘#漏洞复现02-永恒之蓝漏洞
  • 【设计模式】【结构型模式(Structural Patterns)】之桥接模式(Bridge Pattern
  • 【GPT】为什么人需要睡觉?