tinymce-vue——在Vue项目中应用及实现自定义功能(插入自定义卡片、修改元素支持属性等)

背景:vue-cli3 + ant-design-vue 搭建的后台管理系统,wangEditor3做为其中的富文本编辑器
需求:在富文本中插入自定义样式的卡片

最终效果 :tinymce-vue——在Vue项目中应用及实现自定义功能(插入自定义卡片、修改元素支持属性等)_第1张图片
tinymce-vue——在Vue项目中应用及实现自定义功能(插入自定义卡片、修改元素支持属性等)_第2张图片
接下来开始了解我是如何实现这个功能的吧~
step1:安装与引用(参考①)

npm install @tinymce/tinymce-vue -S
npm install tinymce -S

在editor.vue中使用

<template>
  <div class="editor-wrapper">
    <Editor
      api-key="............" // 经过实践直接引入插件失败报错后,找了一个key插入,然后就可正常使用了
      v-model="content"
      @onChange="onChange"
      ref="editor"
      :init="init"
    ></Editor>
  </div>
</template>
<script>
import Editor from "@tinymce/tinymce-vue";
export default {
  props: {
    h5Content: {
      type: String,
      initialValue: ``
    }
  },
  components: {
    Editor
  },
  data() {
    return {
      content: "",
      init: {},
      editor: null
    };
  },
  methods: {
    onChange(e) {
      this.$emit('changeContent', this.content)
    }
  },
  created() {
    const that = this;
    const uploadUrl = this.$api.upload
    this.init = {
      content_css: "https://xxxxx.css", // 内容样式
      language_url: "https://xxxxx.com/zh_CN.js", // 中文包地址
      language: "zh_CN",
      height: 800, // 高度
      branding: false,
      menu: {
        favs: {
          title: "My Favorites",
          items: "code visualaid | searchreplace | spellchecker | emoticons"
        }
      },
      menubar: "favs file edit view insert format tools table help",
      plugins: [
        "advlist autolink lists link image charmap print preview anchor",
        "searchreplace visualblocks code fullscreen",
        "insertdatetime media table paste code help wordcount"
      ],
      toolbar:
        "CardBtn | undo redo | formatselect | bold italic backcolor | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | image removeformat",
      setup: function(editor) {
        // 注册一个icon
        editor.ui.registry.addIcon(
          "shopping-cart",
          ``
        );
        // 注册一个自定义的按钮
        editor.ui.registry.addButton("CardBtn", {
          icon: `shopping-cart`,
          onAction: function(_) {
            that.isShowCard = true;
            that.editor = editor;
          }
        });
      },
      images_upload_handler: function(blobInfo, success, failure) {
        // 自定义图片上传
        let xhr, formData;
        xhr = new XMLHttpRequest();
        xhr.withCredentials = false;
        xhr.open(
          "POST",
          uploadUrl
        );
        xhr.onload = function() {
          let json;
          if (xhr.status != 200) {
            failure("HTTP Error: " + xhr.status);
            return;
          }
          json = JSON.parse(xhr.responseText);
          if (!json || typeof json.data[0] != "string") {
            failure("Invalid JSON: " + xhr.responseText);
            return;
          }
          success(json.data[0]);
        };
        formData = new FormData();
        formData.append("file", blobInfo.blob(), blobInfo.filename());
        xhr.send(formData);
      }
    };
  }
};
</script>

step2:撰写自定义的标签
创建一个addCard.vue(我使用弹窗的方式,采用了antd的UI组件)
此处可根据业务需求撰写

step3:在editor.vue中引入addCard组件

<template>
  <div>
    ...
    <AddCard @cancel="isShowCard = false" @create="createCard" ref="addCard" :visible="isShowCard" />
  </div>
</template>

<script>
import AddCard from "./add-card"; // 引入组件
export default {
  components: {
    Editor,
    AddCard
  },
  data() {
    return {
      content: "",
      init: {}, // editor初始化
      isShowCard: false, // 是否显示插件
      editor: null
    };
  },
   methods: {
    createCard() {
      const form = this.$refs.addCard.form;
      const editor = this.editor;
      const _this = this;
      this.isShowCard = false;
      form.validateFields((err, values) => {
        if (err) return;
        let goods = [...values.goods];
        goods.forEach(e => {
          _this.$api.content
            .goodsSkuList({
              page: 1,
              limit: 1,
              id: e.key
            })
            .then(res => {
              if (res.data) {
                let data = res.data[0];
                let info = {
                  id: data.id,
                  title: data.name,
                  price: data.price,
                  mainImage: data.mainImageUrl
                };
                info.price = _this.toDecimal2(info.price);
                // 采用editor.insertContent方法插入卡片结构
                editor.insertContent(
                  `
${info.title}${info.price}
查看详情
 `
); } }); }); this.$emit("checkGoods", goods); form.resetFields(); }); } }, }; </script>

至此,咱们的自定义卡片功能就完成…90%,哈哈哈~为啥还有10%咧,这就是我踩得坑了o(╥﹏╥)o
在完成上面步骤后,我尝试添加了卡片,结果发现出来的卡片中“查看详情”的div缺少了onclick…我的onclick被“吞掉”了!
踩坑①:通过查询资料后发现标签中支持的属性还需要去配置

// 该配置添加在Init中
extended_valid_elements:'a[class|target|href|onclick],div[class|onclick|id|style],link[rel|href]',

同时,在实践中发现另一个坑
踩坑②:加粗效果是给内容包裹了 标签(但在某些页面上无法正常展示这个效果)
查询资料后发现可以通过以下方式修改加粗功能为使用标签包裹

// 同样在init中配置
formats:{
        bold: { inline: 'span', styles: {'font-weight': 'bold'} }
      },

参考资料:
①TinyMCE中文手册——基本使用上的问题都能够解决
②TinyMCE英文文档(用于搜索API)——API很全面,还有例子,很不错
③在Vue项目中引入tinymce——博文作者写得很详细在项目中使用该编辑器踩的一些坑,给我启发很大

希望我的实践过程能给你带来一些帮助哦~٩(๑>◡<๑)۶ 欢迎很多很多的赞嚯~

你可能感兴趣的:(vue)