Vue3引入使用富文本 tinymce 流程

安装命令:

这里版本一定要跟我一样,不然会出现不可思议的bug,切记。

npm install tinymce@6.0.3
npm install @tinymce/tinymce-vue@5.0.0

步骤:

1. 在public下创建 tinymce 文件夹。

2. 将 node_modules 中的 tinymce 里面的 skins 复制到 public 下的  tinymce 文件中。

3. 在 public 下的  tinymce 创建 langs 文件夹

4. 将 https://gitee.com/shuiche/tinymce-vue3/blob/master/langs/zh_CN.js#

 里面的语言包下载后放进  langs 文件夹中,如下图:

5. 封装富文本组件,在 components 下创建 TEditor,代码如下:

<template>
  <main>
    <editor
      v-model="myValue"
      :init="init"
      :disabled="disabled"
      :id="tinymceId"
    />
  </main>
</template>
<script setup>
import { reactive, ref, onMounted, watch } from "vue";

import tinymce from "tinymce/tinymce";
import "tinymce/skins/content/default/content.css";
import Editor from "@tinymce/tinymce-vue";
import "tinymce/themes/silver";
import "tinymce/themes/silver/theme";
import "tinymce/icons/default";
import "tinymce/models/dom";

import { min } from "lodash";
// 按需导入
import "tinymce/icons/default/icons";
import "tinymce/plugins/table";
import "tinymce/plugins/lists";
import "tinymce/plugins/wordcount";
import "tinymce/plugins/code";
//
import "tinymce/plugins/fullscreen";
import "tinymce/plugins/image";

const emits = defineEmits(["getContent"]);
const props = defineProps({
  value: {
    type: String,
    default: () => {
      return "";
    },
  },
  baseUrl: {
    type: String,
    default: "",
  },
  disabled: {
    type: Boolean,
    default: false,
  },
  plugins: {
    type: [String, Array],
    default: "lists fullscreen code image",
  }, //必填
  toolbar: {
    type: [String, Array],
    default:
      "fullscreen | code | codesample bold italic underline alignleft aligncenter alignright alignjustify | undo redo | formatselect | fontselect | fontsizeselect | forecolor backcolor | bullist numlist outdent indent | lists link table code | removeformat | undo redo | bold italic underline | image",
  }, //必填
});
//用于接收外部传递进来的富文本
const myValue = ref(props.value);
const tinymceId = ref(
  "vue-tinymce-" + +new Date() + ((Math.random() * 1000).toFixed(0) + "")
);
//定义一个对象 init初始化
const init = reactive({
  selector: "#" + tinymceId.value, //富文本编辑器的id,
  language_url: "/tinymce/langs/zh-cn.js", // 语言包的路径,具体路径看自己的项目,文档后面附上中文js文件
  language: "zh_CN", //语言
  skin_url: "/tinymce/skins/ui/oxide", // skin路径,具体路径看自己的项目
  height: 1000, //编辑器高度
  branding: false, //是否禁用“Powered by TinyMCE”
  menubar: true, //顶部菜单栏显示
  image_dimensions: false, //去除宽高属性
  plugins: props.plugins, //这里的数据是在props里面就定义好了的
  toolbar: props.toolbar, //这里的数据是在props里面就定义好了的
  font_formats:
    "Arial=arial,helvetica,sans-serif; 宋体=SimSun; 微软雅黑=Microsoft Yahei; Impact=impact,chicago;", //字体
  fontsize_formats: "11px 12px 14px 16px 18px 24px 36px 48px 64px 72px", //文字大小
  // paste_convert_word_fake_lists: false, // 插入word文档需要该属性
  paste_webkit_styles: "all",
  paste_merge_formats: true,
  nonbreaking_force_tab: false,
  paste_auto_cleanup_on_paste: false,
  file_picker_types: "file",
  content_css: "/tinymce/skins/content/default/content.min.css", //以css文件方式自定义可编辑区域的css样式,css文件需自己创建并引入
  //图片上传
  images_upload_handler: (blobInfo, progress) =>
    new Promise((resolve, reject) => {
      if (blobInfo.blob().size / 1024 / 1024 > 2) {
        reject({ message: "上传失败,图片大小请控制在 2M 以内", remove: true });
        return;
      } else {
        const ph =
          import.meta.env.VITE_BASE_PATH +
          ":" +
          import.meta.env.VITE_SERVER_PORT +
          "/";
        let params = new FormData();
        params.append("file", blobInfo.blob());

        let config = {
          headers: {
            "Content-Type": "multipart/form-data",
          },
        };
        axios
          .post("xxxx", params, config)
          .then((res) => {
            if (res.data.code == 200) {
              resolve(ph + res.data.msg); //上传成功,在成功函数里填入图片路径
            } else {
              reject("HTTP Error: 上传失败" + res.data.code);
              return;
            }
          })
          .catch(() => {
            reject("上传出错,服务器开小差了呢");
            return;
          });
      }
    }),
  // 文件上传
  file_picker_callback: (callback, value, meta) => {
    // Provide file and text for the link dialog
    if (meta.filetype == "file") {
      callback("mypage.html", { text: "My text" });
    }

    // Provide image and alt text for the image dialog
    if (meta.filetype == "image") {
      callback("myimage.jpg", { alt: "My alt text" });
    }

    // Provide alternative source and posted for the media dialog
    if (meta.filetype == "media") {
      callback("movie.mp4", { source2: "alt.ogg", poster: "image.jpg" });
    }
  },
});
//监听外部传递进来的的数据变化
watch(
  () => props.value,
  () => {
    console.log("部传递进来的的数据变化", props.value);
    myValue.value = props.value;
    emits("getContent", myValue.value);
  }
);
//监听富文本中的数据变化
watch(
  () => myValue.value,
  () => {
    console.log("监听富文本中的数据变化", myValue.value);
    emits("getContent", myValue.value);
  }
);
watchEffect(() => {
  console.log("???????????", props);
});
//在onMounted中初始化编辑器
onMounted(() => {
  console.log("props.value", props.value);
  tinymce.init({});
});
</script>
<style lang="scss" scoped>
main {
  width: 100%;
  textarea {
    display: none;
  }
}
</style>
<style>
/* 在el-dialog中tinymce z-index 被太小而被遮挡时要加这两句 */
.tox-tinymce-aux {
  z-index: 99999 !important;
}
.tinymce.ui.FloatPanel {
  z-index: 99;
}
.tox-promotion {
  display: none;
}
.tox-tinymce {
  height: 100% !important;
  min-height: 236px;
}
.tox-textarea-wrap {
  height: 100% !important;
}
textarea {
  height: 100% !important;
  cursor: default !important;
}
</style>

6. 页面中使用组件, 代码如下: 

<template>
  <div>
    <TEditor
      ref="editor"
      v-model:value="formState.contents"
      :disabled="disabled"
      @getContent="getContent"
    />
  </div>
</template>

<script setup lang="ts">
import TEditor from "@/components/TEditor/index.vue";

const formState = reactive({ contents: "" });
const getContent = (v: string) => {
  formState.contents = v;
};
</script>
<style lang="scss" scoped></style>

问题:

样式需要选择 content.min.css,假如content.css会有问题,样式不准确。

按需引入教程在官网有: importcss 引入css | TinyMCE中文文档中文手册

 示例: 

假如需要进入图片插件,步骤:

 官网图:

自定义工具栏的按钮:

  setup: function (editor) {
    // 在编辑器初始化时注册自定义按钮
    editor.ui.registry.addButton("customButton", {
      text: "image",
      icon: "image", // 自定义按钮的图标名称
      onAction: function () {
        appStore.changeShow(true);
      },
    });

效果如下图:

Vue.js 2.x 与 tinymce 富文本编辑器的集成相对简单。以下是一些步骤可以帮助你在 Vue.js 2.x 中使用 tinymce: 1. 安装 tinymce:你可以通过 npm 或 yarn 安装 tinymce,运行以下命令: ```bash npm install tinymce # 或 yarn add tinymce ``` 2. 在组件中引入 tinymce 并初始化: ```vue <template> <div> <textarea v-model="content" :id="editorId"></textarea> </div> </template> <script> import tinymce from 'tinymce/tinymce'; export default { data() { return { content: '', editorId: 'my-editor', // 指定一个唯一的 id }; }, mounted() { tinymce.init({ selector: `#${this.editorId}`, plugins: 'advlist autolink lists link image charmap print preview hr anchor', toolbar: 'undo redo | formatselect | bold italic backcolor | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | removeformat | image', height: 500, setup: (editor) => { editor.on('change', () => { this.content = editor.getContent(); }); }, }); }, beforeDestroy() { tinymce.get(this.editorId).destroy(); }, }; </script> ``` 在上述示例中,我们在 mounted 钩子中初始化了 tinymce 编辑器,并且使用 v-model 指令将编辑器的内容绑定到 Vue 实例上的 content 属性。在 beforeDestroy 钩子中,我们销毁了 tinymce 编辑器。 你可以根据需要调整 tinymce 的配置项以满足你的需求。可以在 tinymce 的官方文档中了解更多配置选项和插件的使用方法:[https://www.tiny.cloud/docs/](https://www.tiny.cloud/docs/) 希望这能帮到你!如果有任何问题,请随时提问。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值