tinymce富文本是一个轻量级插件,内置的功能比较齐全。
中文文档:tinymce.ax-z.cn/ 下面主要记录我根据项目需要在vue项目中封装富文本编辑器组件。
- 下载插件
npm install @tinymce/tinymce-vue
- 新建一个组件,封装tinymce作为通用组件
<template>
<div
class="tinymce-editor"
id="tinymce-editor"
>
<editor
:style="disabled === false ? 'min-height:70px' : 'min-height:0px'"
v-model="tempValue"
:init="init"
:disabled="disabled"
></editor>
</div>
</template>
<script>
import tinymce from "tinymce/tinymce";
import Editor from "@tinymce/tinymce-vue";
import "tinymce/themes/silver/theme"; // 引用主题文件
import "tinymce/icons/default"; // 引用图标文件
import "tinymce/plugins/quickbars"; //快捷菜单
import "tinymce/plugins/textcolor";
import "tinymce/plugins/paste"
import "tinymce/plugins/image"; //图片
import "tinymce/plugins/imagetools"; //图片工具
import "tinymce/plugins/importcss"; //图片工具
import "tinymce/plugins/fullscreen"; //全屏
import "tinymce/plugins/lists";//列表
import "tinymce/plugins/link";//链接
import { getToken } from "@/utils/auth";
import axios from 'axios'
export default {
components: {
Editor
},
props: {
//富文本框值
value: {
type: String,
default: null
},
//是否可编辑
disabled: {
type: Boolean,
default: false
},
},
data () {
return {
init: {
selector: `#tinymce-editor`,
//占位字符,此属性不知道为什么不起作用
placeholder: '请再次输入内容',
language_url: require('../../assets/tinymce/zh_CN'), //如果语言包不存在,指定一个语言包路径
language: "zh_CN", //语言
skin_url: require('tinymce/skins/ui/oxide/skin.css'), //如果主题不存在,指定一个主题路径,
menubar: false, // 隐藏菜单栏
height: '300px',
plugins:
"quickbars paste imagetools image fullscreen lists link", // 插件需要import进来
paste_as_text: 'false',
//复制图片
paste_data_images: true,
toolbar: [ //数组写法
'fontsizeselect h1 | bold backcolor italic strikethrough underline forecolor fullscreen bullist numlist'
],
fontsize_formats: '11px 12px 14px 16px 18px 24px 36px 48px',
quickbars_insert_toolbar: false,
custom_colors: false,
quickbars_selection_toolbar: 'bold | forecolor',
content_style: 'p {white-space:pre-line;margin: 5px 0; font-size: 14px;color:#303133}',
contextmenu: '',
branding: false,
visual: true,
elementpath: false,
resize: false, // 禁止改变大小
statusbar: false, // 隐藏底部状态栏
startContent: '',//初始内容
image_uploadtab: 'false',
//图片上传
images_upload_handler: (blobInfo, success, failure) => {
this.handleImgUpload(blobInfo, success, failure);
}
},
tempValue: this.value
};
},
mounted () {
tinymce.init({});
},
methods: {
//图片上传函数
handleImgUpload (blobInfo, success, failure) {
const formdate = new FormData();
formdate.append("file", blobInfo.blob()); //imageFile文件名和后端统一
axios({
url: process.env.NODE_ENV === 'development' ? '/api/common/upload' : '/common/upload',
method: "post",
data: formdate,
headers: {
"Content-Type": "multipart/form-data",
Authorization: "Bearer " + getToken(),
},
}).then(response => {
console.log("response", response.data);
if (response.data.code == 200) {
success(response.data.url); //回显url
} else {
failure(response.data.msg);
this.$message.error(response.data.msg);
}
});
}
},
watch: {
value (newValue) {
this.tempValue = newValue;
},
tempValue (newValue) {
this.$emit("input", newValue);
},
}
};
</script>
<style lang="scss" >
.tox-tinymce-aux {
z-index: 9999 !important;
}
.mce-content-body p img {
max-width: 80% !important;
width: auto !important;
height: auto !important;
}
</style>
- 在组件中调用
此处需要使用v-if控制是否显示,避免绑定的属性值不准确,使用在对话弹框中可以赋值v-if和控制弹框显示的值同步,保证每次打开获取到的都是最新赋值的数据
<Editor v-model:value="formData.errorInfo" v-if="visible" @input="inputContent"></Editor>