富文本 tinymce.js(version: 5.4.0)的使用实践

	  <script src="https://****.com/tinymce/tinymce.min.js"></script>
	
	<template>
	<div style="display:flex;">
	  <div
	    :class="{ fullscreen: fullscreen }"
	    class="tinymce-container"
	    :style="{ width: containerWidth }"
	  >
	    <textarea :id="tinymceId" :class="tinymceId" class="tinymce-textarea" />
	  </div>
	  <!-- <componentMaterial
	    v-if="show"
	    @insertMaterial="insertMaterialAction"
	    style="margin-left:10%"
	  ></componentMaterial> -->
	</div>
	</template>
	
	<script>
	/**
	* docs:
	* https://panjiachen.github.io/vue-element-admin-site/feature/component/rich-editor.html#tinymce
	*/
	import componentMaterial from "../ComponentMaterial";
	import {
	_api_carcloud,
	} from "@/service/axios";
	import plugins from "./plugins";
	import toolbar from "./toolbar";
	import load from "./dynamicLoadScript";
	import { mp01, mp02, mp03 } from "./mp";
	// why use this cdn, detail see https://github.com/PanJiaChen/tinymce-all-in-one
	// const tinymceCDN ="https://unpkg.com/tinymce-all-in-one@4.9.3/tinymce.min.js";
	
	// 导入 tinymce
	// 
	// const tinymceCDN = 'https://.com/tinymce/tinymce.min.js'
	
	
	export default {
	name: "Tinymce",
	components: { componentMaterial },
	props: {
	  ifPreview: {
	    type: Boolean,
	    default: false,
	  },
	  tinymceId: {
	    type: String,
	    default: "tinymce",
	  },
	  value: {
	    type: String,
	    default: "",
	  },
	  toolbar: {
	    type: Array,
	    required: false,
	    default() {
	      return [];
	    },
	  },
	  menubar: {
	    type: String,
	    default: "file edit insert view  table",
	  },
	  height: {
	    type: [Number, String],
	    required: false,
	    default: 800,
	  },
	  width: {
	    type: [Number, String],
	    required: false,
	    default: 414,
	  },
	  show: {
	    type: Boolean,
	    default: true
	  }
	},
	data() {
	  return {
	    uploadImgsUrl: "/api/v1.0/backend/file/upload/image/9",
	    hasChange: false,
	    hasInit: false,
	    //tinymceId: "vuetinymce",
	    fullscreen: false,
	    languageTypeList: {
	      en: "en",
	      zh: "zh_CN",
	      es: "es_MX",
	      ja: "ja",
	    },
	  };
	},
	computed: {
	  containerWidth() {
	    if (this.ifPreview) {
	      return "414px";
	    }
	    const width = this.width;
	    if (/^[\d]+(\.[\d]+)?$/.test(width)) {
	      // matches `100`, `'100'`
	      return `${width}px`;
	    }
	    return width;
	  },
	},
	watch: {
	  value: {
	    handler(val) {
	      console.log("需返显内容++", val)
	      this.$emit("change", val);
	      if (!this.hasChange && this.hasInit) {
	         console.log("需返显内容___", val)
	          window.tinymce?.get(this.tinymceId).setContent(val || "")
	      }
	    },
	    immediate: true,
	    deep: true,
	  },
	},
	mounted() {
	  console.log("富文本生命周期");
	  this.initData();
	
	},
	activated() {
	  if (window.tinymce) {
	    this.initTinymce();
	  }
	},
	deactivated() {
	  this.destroyTinymce();
	},
	destroyed() {
	  this.destroyTinymce();
	},
	methods: {
	  createFocusDom() {
	    const foucsDom = document.createElement("div");
	    return foucsDom;
	  },
	  createNode(htmlStr) {
	    //console.log(htmlStr)
	    let div = document.createElement("div");
	    div.innerHTML = htmlStr ;
	    if (div.childNodes.length > 1) {
	      div.innerHTML = `<div>` + htmlStr + `</div>`;
	    }
	    return div.childNodes[0];
	  },
	  insertMaterialAction(DOM) {
	    //在富文本编辑器里插入组件动作
	    tinymce.activeEditor.selection
	      .getNode()
	      .appendChild(this.createNode(DOM));
	    tinymce.activeEditor.selection
	      .getNode()
	      .appendChild(this.createFocusDom());
	    this.setContent(this.getContent());
	   //const nowFoucsDom = document.getElementById(this.tinymceId+'_ifr');
	   //console.log(document.getElementsByTagName('iframe')[0].contentWindow)
	    // nowFoucsDom.focus();
	  },
	  initData() {
	         this.initTinymce();
	     return false;
	    // dynamic load tinymce from cdn
	    load(tinymceCDN, (err) => {
	      console.log("tinymceCDN err", err)
	      if (err) {
	        this.$Message.error(err.message);
	        return;
	      }
	
	      //  window.tinymce.baseURL = 'https://dbzj-imgs-1258960627.cos.ap-beijing.myqcloud.com/tinymce';
	    
	      this.initTinymce();
	      //const ifr = window.document.getElementById(this.tinymceId + "_ifr");
	      //   console.log(ifr.document);
	      //   let  ifrHead = ifr.document.getElementsByTagName("body")[0];
	      //   ifrHead = ifr.getElementsByTagName("body")[0];
	      //   console.log(ifrHead);
	      //   const scrollStyle = `
	      //     <style type="text/css">
	      //     body {
	      //     SCROLLBAR-FACE-COLOR: #e8e7e7;
	      //     SCROLLBAR-HIGHLIGHT-COLOR: #ffffff;
	      //     SCROLLBAR-SHADOW-COLOR: #ffffff;
	      //     SCROLLBAR-3DLIGHT-COLOR: #cccccc;
	      //     SCROLLBAR-ARROW-COLOR: #03B7EC;
	      //     SCROLLBAR-TRACK-COLOR: #EFEFEF;
	      //     SCROLLBAR-DARKSHADOW-COLOR: #b2b2b2;
	      //     SCROLLBAR-BASE-COLOR: #000000;
	      //     }
	      //     </style>
	      //  `;
	      //   ifrHead.appendChild(scrollStyle);
	    });
	  },
	  initTinymce() {
	    const _this = this;
	    window.tinymce.init({
	      baseURL: 'https://dbzj-imgs-1258960627.cos.ap-beijing.myqcloud.com/tinymce',
	      selector: `.${this.tinymceId}`,
	      body_class: "my-tinyMce-body",
	      schema: "html5",
	      fontsize_formats: "12px 14px 16px 18px 24px 36px 48px 56px 72px",
	      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;",
	
	      branding: false,
	      elementpath: false,
	      language: this.languageTypeList["zh"],
	      language_url: require("./zh_CN.js"),
	      height: this.height,
	      templates: [
	        {
	          title: "模板01",
	          description: "模板01",
	          content: mp01,
	        },
	        {
	          title: "模板02",
	          description: "模板02",
	          content: mp02,
	        },
	        {
	          title: "模板03",
	          description: "模板03",
	          content: mp03,
	        },
	      ],
	      body_class: "panel-body",
	      object_resizing: true, // 此选项允许您打开/关闭图像、表或媒体对象的大小调整句柄。默认情况下,此选项处于启用状态,允许您调整表和图像的大小。您还可以指定一个CSS3选择器来选择要在其上启用大小调整的对象。
	      toolbar: this.toolbar.length > 0 ? this.toolbar : toolbar,
	      menubar: this.menubar, // 菜单栏
	      plugins: plugins,
	      end_container_on_empty_block: true, // 如果在空的内部块元素中按enter键,则此选项允许您拆分当前容器块元素
	
	      powerpaste_word_import: "clean", // https://www.tiny.cloud/docs/plugins/powerpaste/#powerpaste_word_import 此设置控制如何筛选从Microsoft Word粘贴的内容。
	      // code_dialog_height: 450, // 此配置选项设置对话框的内部可编辑区域高度code。 请注意,实际模态的外部尺寸将略大于设置的值。
	      // code_dialog_width: 1000, // 此配置选项设置对话框的内部可编辑区域宽度code。 请注意,实际模态的外部尺寸将略大于设置的值。
	
	      advlist_bullet_styles: "square", // 此选项允许您在默认bullist工具栏控件中包含特定的无序列表项标记。此选项允许您在默认bullist工具栏控件中包含特定的无序列表项标记。https://www.tiny.cloud/docs-4x/plugins/advlist/#advlist_bullet_styles
	      advlist_number_styles: "default", // 此选项允许您在默认的numlist工具栏控件中包含特定的有序列表项标记。
	      /* https://www.tiny.cloud/docs-4x/plugins/imagetools/#imagetools_cors_hosts
	        由于浏览器对所谓的跨域HTTP请求施加了安全性措施,因此Image Tools无法使用来自其他域的图像。为了克服这些限制,必须在指定的域上显式启用跨域资源共享(CORS)(有关更多信息,请参阅HTTP访问控制)。
	可以通过imagetools_cors_hosts选件将一系列受支持的图像域(启用了CORS)提供给TinyMCE 。
	
	注意:数组中的每个字符串都必须采用的格式mydomain.com。http://, https://域中请勿包含协议()或任何斜杠。
	
	注: imagetools_cors_hosts在不使通过这个插件时,需要TinyMCE的云。
	类型: String[]
	        * */
	
	      imagetools_cors_hosts: ["https://image.baidu.com/", "codepen.io"], //
	      // 自定义上传逻辑
	      images_upload_handler: (blobInfo, success, failure) => {
	        // const img = 'data:image/jpeg;base64,' + blobInfo.base64()
	        // success(img)
	        const file = blobInfo.blob(); // 转化为易于理解的file对象
	        const formData = new FormData();
	        formData.append("file", file);
	        new Promise((resolve, reject) => {
	          _api_carcloud
	            .post(this.uploadImgsUrl, formData)
	            .then((res) => {
	              const result = res.data;
	              if (result.code === "000000") {
	                const data = result.data;
	                resolve(data.filePathUrl);
	              } else {
	                reject(res.data.description);
	              }
	            });
	        })
	          .then((data) => {
	            success(data);
	          })
	          .catch((data) => {
	            failure(data);
	          });
	      },
	
	      // default_link_target: "_blank", // 使用此选项,您可以在插入/编辑链接时为链接设置默认目标
	      link_title: false, // 此选项使您可以禁用对话框中的链接title输入字段link。
	      /*
	        * 使用此选项,您可以&nbsp;在用户按下键盘tab键时强制TinyMCE插入三个实体。
	
	请务必注意,这不会更改菜单和工具栏控件的行为,&nbsp当nonbreaking_force_tabvalue 为时,菜单和工具栏控件将继续插入单个实体true。
	但是,true条件确实捕获了Tab键并将其包含在可编辑区域中,而当设置为falseTab键的默认状态时,按下该键会将光标移动到下一个可编辑区域(例如,当前页面上的浏览器网址栏或表单字段) )。*/
	      nonbreaking_force_tab: true, // inserting nonbreaking space &nbsp; need Nonbreaking Space Plugin   插入非中断空间需要非中断空间插件
	      /* 使用init_instance_callback选项,您可以指定每次初始化编辑器实例时要执行的函数名称。该函数的格式为initInstance(editor)哪里editor是编辑器实例对象引用。
	       * */
	      init_instance_callback: (editor) => {
	        if (_this.value) {
	          editor.setContent(_this.value);
	        }
	        _this.hasInit = true;
	        console.log("初始化完成", _this.value)
	        setTimeout(()=>{
	          window.tinymce?.get(this.tinymceId).setContent(_this.value || "")
	
	        }, 800)
	        editor.on("NodeChange Change KeyUp SetContent", () => {
	          this.hasChange = true;
	          this.$emit("input", editor.getContent());
	        });
	      },
	      /*
	        * 此选项使您可以指定在渲染TinyMCE编辑器实例之前将执行的回调。
	
	要指定设置回调,请为该setup选项提供JavaScript函数。该函数应该有一个参数,该参数是对正在设置的编辑器的引用。
	
	此设置的常见用例是将编辑器事件新增到TinyMCE。例如,如果您想向TinyMCE新增点击事件,则可以通过设置配置设置来新增它。
	        * */
	      setup(editor) {
	        editor.on("FullscreenStateChanged", (e) => {
	          console.log(e);
	          _this.fullscreen = e.state;
	        });
	      },
	    });
	  },
	  destroyTinymce() {
	    const tinymce = window.tinymce?.get(this.tinymceId);
	    console.log("tinymce", tinymce)
	    if (this.fullscreen) {
	      tinymce.execCommand("mceFullScreen");
	    }
	
	    if (tinymce) {
	      tinymce.destroy();
	      tinymce.remove()
	      tinymce.execCommand('mceRemoveControl',true, "#"+this.tinymceId);
	    }
	  },
	  setContent(value) {
	    window.tinymce?.get(this.tinymceId).setContent(value);
	  },
	  getContent() {
	    return window.tinymce?.get(this.tinymceId).getContent();
	  },
	  imageSuccessCBK(arr) {
	    const _this = this;
	    arr.forEach((v) => {
	      window.tinymce?.get(_this.tinymceId)
	        .insertContent(`<img class="wscnph" src="${v.url}" >`);
	    });
	  },
	},
	};
	</script>
	
	<style lang="less" scoped>
	.img-class {
	width: 100% !important;
	}
	
	.tinymce-container {
	position: relative;
	line-height: normal;
	}
	
	.tinymce-container .mce-fullscreen {
	z-index: 10000;
	}
	#my-tinyMce-body {
	::-webkit-scrollbar {
	  height: 10px;
	  width: 10px;
	  background: transparent;
	  border-radius: 10px;
	}
	
	::-webkit-scrollbar-button {
	  display: none;
	}
	
	::-webkit-scrollbar-track {
	  background-color: transparent;
	}
	
	::-webkit-scrollbar-track-piece {
	  background: transparent;
	}
	
	::-webkit-scrollbar-thumb {
	  width: 8px;
	  min-height: 15px;
	  background: #c1c1c1;
	  border-radius: 4px;
	}
	
	::-webkit-scrollbar-thumb:active,
	::-webkit-scrollbar-thumb:hover {
	  background: #7d7d7d;
	}
	}
	.tinymce-textarea {
	visibility: hidden;
	z-index: -1;
	}
	
	.editor-custom-btn-container {
	position: absolute;
	right: 4px;
	top: 4px;
	/*z-index: 2005;*/
	}
	
	.fullscreen .editor-custom-btn-container {
	z-index: 10000;
	position: fixed;
	}
	
	.editor-upload-btn {
	display: inline-block;
	}
	</style>
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
我在vue2中通过tinymcetinymce-plugins 在plugins和toolbar中加入了importword 但是我的项目报错了 p is not a constructor TypeError: p is not a constructor at t (http://10.42.47.126:8080/tinymce/plugins/importword/plugin.min.js:751:178) at u (http://10.42.47.126:8080/tinymce/plugins/importword/plugin.min.js:752:145) at Object.onAction (http://10.42.47.126:8080/tinymce/plugins/importword/plugin.min.js:754:104) at eval (webpack-internal:///./node_modules/_tinymce@6.6.0@tinymce/themes/silver/theme.js:3:382090) at eval (webpack-internal:///./node_modules/_tinymce@6.6.0@tinymce/themes/silver/theme.js:3:255327) at eval (webpack-internal:///./node_modules/_tinymce@6.6.0@tinymce/themes/silver/theme.js:3:382010) at eval (webpack-internal:///./node_modules/_tinymce@6.6.0@tinymce/themes/silver/theme.js:3:51547) at each$1 (webpack-internal:///./node_modules/_tinymce@6.6.0@tinymce/themes/silver/theme.js:3:4119) at run (webpack-internal:///./node_modules/_tinymce@6.6.0@tinymce/themes/silver/theme.js:3:51509) at eval (webpack-internal:///./node_modules/_tinymce@6.6.0@tinymce/themes/silver/theme.js:3:64592) at eval (webpack-internal:///./node_modules/_tinymce@6.6.0@tinymce/themes/silver/theme.js:3:1678) at eval (webpack-internal:///./node_modules/_tinymce@6.6.0@tinymce/themes/silver/theme.js:3:313855) at Optional.fold (webpack-internal:///./node_modules/_tinymce@6.6.0@tinymce/themes/silver/theme.js:3:2068) at doTriggerHandler (webpack-internal:///./node_modules/_tinymce@6.6.0@tinymce/themes/silver/theme.js:3:313676) at doTriggerOnUntilStopped (webpack-internal:///./node_modules/_tinymce@6.6.0@tinymce/themes/silver/theme.js:3:314490) at triggerOnUntilStopped (webpack-internal:///./node_modules/_tinymce@6.6.0@tinymce/themes/silver/theme.js:3:315348) 这是什么原因
07-25

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值