最终效果:
第一步:
tinymce官网下载地址:Self Hosted WYSIWYG HTML Editor | Trusted Rich Text Editor | TinyMCE
2.建立公共页面trnymce.vue
<template>
<div :class="{fullscreen:fullscreen}" class="tinymce-container" :style="{width:containerWidth}">
<textarea :id="tinymceId" class="tinymce-textarea" />
<div class="editor-custom-btn-container"></div>
</div>
</template>
<script>
const plugins = [
"advlist anchor autolink autosave colorpicker colorpicker contextmenu directionality fullscreen hr insertdatetime lists nonbreaking noneditable pagebreak paste preview save searchreplace spellchecker tabfocus template textcolor textpattern visualblocks visualchars",
];
const toolbar = [
"searchreplace bold italic underline strikethrough alignleft aligncenter alignright outdent indent blockquote undo redo removeformat numlist",
"hr bullist styleselect fontsizeselect fontselect charmap preview insertdatetime emoticons forecolor backcolor fullscreen",
];
const font_formats =
"微软雅黑='微软雅黑';宋体='宋体';黑体='黑体';仿宋='仿宋';楷体='楷体';Andale Mono=andale mono,times;Arial=arial,helvetica,sans-serif;Arial Black=arial black,avant garde;Book Antiqua=book antiqua,palatino;Comic Sans MS=comic sans ms,sans-serif;Courier New=courier new,courier;Georgia=georgia,palatino;Helvetica=helvetica;Impact=impact,chicago;";
export default {
name: "Tinymce",
props: {
id: {
type: String,
default: function () {
return (
"vue-tinymce-" +
+new Date() +
((Math.random() * 1000).toFixed(0) + "")
);
},
},
value: {
type: String,
default: "",
},
isTextNum:{
type: Boolean,
default: false,
},
toolbar: {
type: Array,
required: false,
default() {
return [];
},
},
menubar: {
type: String,
default: "",
},
height: {
type: [Number, String],
required: false,
default: 210,
},
width: {
type: [Number, String],
required: false,
default: "auto",
},
},
data() {
return {
hasChange: false,
hasInit: false,
tinymceId: this.id,
fullscreen: false,
languageTypeList: {
en: "en",
zh: "zh_CN",
es: "es_MX",
ja: "ja",
},
};
},
computed: {
containerWidth() {
const width = this.width;
if (/^[\d]+(\.[\d]+)?$/.test(width)) {
// matches `100`, `'100'`
return `${width}px`;
}
return width;
},
},
watch: {
value(val) {
if(this.hasChange){
tinymce.activeEditor.setContent(val || "");
}
this.hasChange = true;
if(this.isTextNum){
let str = tinymce.activeEditor.getContent();
let num = this.removeHTMLTag(str);
this.$emit('num', num.length)
}
},
},
mounted() {
this.initTinymce()
},
activated(){
if(tinymce){
this.initTinymce();
}
},
deactivated() {
this.destroyTinymce();
},
destroyed() {
this.destroyTinymce();
},
methods: {
removeHTMLTag: function (str) {
str = str.replace(/^(([^<>()\\[\]\\.,;:\s@"]+(\.[^<>()\\[\]\\.,;:\s@"]+)*)|(".+"))*>/g, '');
str = str.replace(/<\/?[^>]*>/g, '');
str = str.replace(/[ | ]*\n/g, '\n');
str = str.replace(/ /ig, '');
str = str.replace(/,/g, '');
str = str.replace(/。/g, '');
str = str.replace(/\s/g, '');
return str;
},
initTinymce() {
const _this = this;
tinymce.init({
selector: `#${this.tinymceId}`,
branding: false, //(隐藏右下角技术支持)
fontsize_formats: "10px 12px 14px 16px 24px 36px 48px",
lineheight_formats: "8pt 9pt 10pt 11pt 12pt 14pt 16pt 18pt 20pt 22pt 24pt 26pt 36pt",
language: this.languageTypeList["zh"],
height: this.height,
body_class: "panel-body ",
object_resizing: false,
toolbar: this.toolbar.length > 0 ? this.toolbar : toolbar,
menubar: false,
plugins: plugins,
end_container_on_empty_block: true,
powerpaste_word_import: "clean",
code_dialog_height: 600,
code_dialog_width: 1000,
advlist_bullet_styles: "square",
advlist_number_styles: "default",
imagetools_cors_hosts: ["www.tinymce.com", "codepen.io"],
default_link_target: "_blank",
link_title: false,
font_formats: font_formats,
style_formats: [
{
title: "行高",
items: [
{ title: "1", block: "p", styles: { "line-height": "1.0" } },
{ title: "1.5", block: "p", styles: { "line-height": "1.5" } },
{ title: "1.75", block: "p", styles: { "line-height": "1.75" } },
{ title: "2", block: "p", styles: { "line-height": "2" } },
{ title: "3", block: "p", styles: { "line-height": "3" } },
],
},
],
style_formats_merge: true,
style_formats_autohide: true,
nonbreaking_force_tab: true, // inserting nonbreaking space need Nonbreaking Space Plugin
setup: function(editor) {
editor.on('input undo redo execCommand', function(e) {
_this.hasChange = false;
_this.$emit("echo", editor.getContent());
})
},
init_instance_callback: (editor) => {
if (_this.value) {
editor.setContent(_this.value);
}
editor.on("NodeChange Change KeyUp SetContent", () => {
_this.hasChange = true;
_this.$emit("echo", editor.getContent());
});
},
convert_urls: false,
});
},
destroyTinymce() {
const tinymce1 = tinymce.get(this.tinymceId);
if (this.fullscreen) {
tinymce1.execCommand("mceFullScreen");
}
if (tinymce1) {
tinymce1.destroy();
}
},
setContent(value) {
tinymce.get(this.tinymceId).setContent(value);
},
getContent() {
tinymce.get(this.tinymceId).getContent();
},
},
};
</script>
<style lang="scss" scoped>
.tinymce-container {
position: relative;
line-height: normal;
padding: 0 3px 0 0;
}
.tinymce-container {
::v-deep {
.mce-fullscreen {
z-index: 10000;
}
}
}
.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>
3.页面引用
<quillEditor isTextNum="true" :value="form.cooking" @echo="echoCooking" @num="getNum"></quillEditor>