TinyMCE是一款易用、且功能強大的所見即所得的富文本編輯器。同類程式有:UEditor、Kindeditor、Simditor、CKEditor、wangEditor、Suneditor、froala等等。 配置靈活,界面簡潔,支持自定義插件。 TinyMCE中文手冊:http://tinymc ...
TinyMCE是一款易用、且功能強大的所見即所得的富文本編輯器。同類程式有:UEditor、Kindeditor、Simditor、CKEditor、wangEditor、Suneditor、froala等等。
配置靈活,界面簡潔,支持自定義插件。
TinyMCE中文手冊:http://tinymce.ax-z.cn
一、安裝環境
1、安裝需要的包
我使用的是v5版本的,需要搭配tinymce-vue包來使用
npm install tinymce/[email protected]
和
npm install [email protected]
2、將安裝的tinymce包copy放在public下
cp ./node_modules/tinymce ./public/tinymce
3、下載語言包
打開鏈接 http://tinymce.ax-z.cn/static/tiny/langs/zh_CN.js ,將zh_CN.js 另存到 public/tinymce/langs下,沒有langs文件夾的可以手動創建一下
二、代碼引用
附上我封裝的組件,可以作為參考,上傳文件的邏輯需要結合業務邏輯自行實現
<template>
<Editor :id="editorId" v-if="reFresh" v-model="newData" :init="init" />
</template>
<script>
// 引入組件
import tinymce from "tinymce/tinymce";
import Editor from "@tinymce/tinymce-vue";
import 'tinymce/themes/silver/theme'
import "tinymce/skins/ui/oxide/skin.min.css";
// 引入富文本編輯器主題的js和css
export default {
name: "TinymceEditor",
components: { Editor },
data() {
return {
init: { // 配置文件
base_url: '/tinymce',
menubar: false,
external_plugins: { //引入需要的插件
anchor: "/tinymce/plugins/anchor/plugin.min.js",
code: "/tinymce/plugins/code/plugin.min.js",
print: "/tinymce/plugins/print/plugin.min.js",
preview: "/tinymce/plugins/preview/plugin.min.js",
searchreplace: "/tinymce/plugins/searchreplace/plugin.min.js",
autolink: "/tinymce/plugins/autolink/plugin.min.js",
directionality: "/tinymce/plugins/directionality/plugin.min.js",
visualblocks: "/tinymce/plugins/visualblocks/plugin.min.js",
visualchars: "/tinymce/plugins/visualchars/plugin.min.js",
fullscreen: "/tinymce/plugins/fullscreen/plugin.min.js",
image: "/tinymce/plugins/image/plugin.min.js",
link: "/tinymce/plugins/link/plugin.min.js",
media: "/tinymce/plugins/media/plugin.min.js",
template: "/tinymce/plugins/template/plugin.min.js",
codesample: "/tinymce/plugins/codesample/plugin.min.js",
table: "/tinymce/plugins/table/plugin.min.js",
charmap: "/tinymce/plugins/charmap/plugin.min.js",
pagebreak: "/tinymce/plugins/pagebreak/plugin.min.js",
nonbreaking: "/tinymce/plugins/nonbreaking/plugin.min.js",
insertdatetime: "/tinymce/plugins/insertdatetime/plugin.min.js",
advlist: "/tinymce/plugins/advlist/plugin.min.js",
lists: "/tinymce/plugins/lists/plugin.min.js",
wordcount: "/tinymce/plugins/wordcount/plugin.min.js",
imagetools: "/tinymce/plugins/imagetools/plugin.min.js",
textpattern: "/tinymce/plugins/textpattern/plugin.min.js",
help: "/tinymce/plugins/help/plugin.min.js",
emoticons: "/tinymce/plugins/emoticons/plugin.min.js",
autosave: "/tinymce/plugins/autosave/plugin.min.js",
iframe: "/tinymce/plugins/iframe/plugin.min.js",
hr: "/tinymce/plugins/hr/plugin.min.js",
// formatpainter: "/tinymce/plugins/formatpainter/plugin.min.js",
},
language_url:
"/tinymce/langs/zh_CN.js", //語言文件
language: "zh_CN",
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;",
toolbar: [
"template code undo redo restoredraft cut copy paste pastetext forecolor backcolor bold italic underline strikethrough link unlink anchor alignleft aligncenter alignright alignjustify outdent indent formatselect fontselect fontsizeselect bullist numlist blockquote subscript superscript removeformat table image media charmap emoticons pagebreak insertdatetime print preview fullscreen formatpainter iframe hr",
],
templates: [],
// content_css : ['/layui/css/layui.css','/css/public.css?v=1'],
content_css: [],
height: 800, //編輯器高度
min_height: 200,
max_height: 600,
branding: false,
paste_data_images: true, // 允許粘貼圖像
file_picker_types: "file image media",
images_upload_handler: (blobInfo, success) => {
var xhr, formData;
var file = blobInfo.blob();//轉化為易於理解的file對象
xhr = new XMLHttpRequest();
xhr.withCredentials = false;
xhr.open("POST",`${process.env.VUE_APP_API_URL}/file/upload`); //上傳文件的地址,需要替換成自己的
xhr.setRequestHeader("Authorization",window.localStorage.escourse_token);
xhr.onload = function () {
var json;
json = JSON.parse(xhr.responseText);
};
formData = new FormData();
formData.append("file", file, file.name);
formData.append("module", "post");
formData.append("file_source", "1");
// formData.append("token",window.localStorage.escourse_token)
xhr.send(formData);
xhr.onload = function () {
let json = JSON.parse(xhr.responseText);
if (json.code == 200) {
success(process.env.VUE_APP_API_URL + json.data.file.path)
return
}
};
},
media_url_resolver: function (data, resolve) {
try {
let videoUri = encodeURI(data.url);
let embedHtml = `<p>
<span
class="mce-object mce-object-video"
data-mce-selected="1"
data-mce-object="video"
data-mce-p-width="100%"
data-mce-p-height="auto"
data-mce-p-controls="controls"
data-mce-p-controlslist="nodownload"
data-mce-p-allowfullscreen="true"
data-mce-p-src=${videoUri} >
<video src=${data.url} width="100%" height="auto" controls="controls" controlslist="nodownload">
</video>
</span>
</p>
<p style="text-align: left;"></p>`;
resolve({ html: embedHtml });
} catch (e) {
resolve({ html: "" });
}
},
file_picker_callback(cb, value, meta) {
//當點擊meidia圖標上傳時,判斷meta.filetype == 'media'有必要,因為file_picker_callback是media(媒體)、image(圖片)、file(文件)的共同入口
console.log('meta', meta);
//創建一個隱藏的type=file的文件選擇input
let input = document.createElement("input");
input.setAttribute("type", "file");
input.onchange = function () {
var xhr, formData;
let file = this.files[0]; //只選取第一個文件。如果要選取全部,後面註意做修改
xhr = new XMLHttpRequest();
xhr.withCredentials = false;
xhr.open("POST",`${process.env.VUE_APP_API_URL}/file/upload`); //上傳文件的地址,需要替換成自己的
xhr.setRequestHeader("Authorization",window.localStorage.escourse_token);
xhr.onload = function () {
var json;
json = JSON.parse(xhr.responseText);
};
formData = new FormData();
formData.append("file", file, file.name);
formData.append("module", "post");
formData.append("file_source", "1");
// formData.append("token",window.localStorage.escourse_token)
xhr.send(formData);
xhr.upload.onprogress = function () {
// 進度(e.loaded / e.total * 100)
// progress(e.loaded / e.total * 100);
};
// xhr.onerror = function () {
// //根據自己的需要添加代碼
// console.log(xhr.status);
// return;
// };
xhr.onload = function () {
let json = JSON.parse(xhr.responseText);
if (json.code == 200) {
// if (meta.filetype == "media") {
cb(process.env.VUE_APP_API_URL + json.data.file.path, { text: json.data.file.name })
// }
// if (meta.filetype == "file") {
// cb(json.data.url, { text: json.data.name })
// }
return
}
};
};
//觸發點擊
input.click();
},
},
editorId: this.id,
newData: this.data,
reFresh:false,
laws:[]
};
},
created(){
this.getBandData();
},
mounted() {
tinymce.init({});
},
props: {
data: String,
onChange: Function // 回調函數,將新修改的內容做為第一個參數返回
},
watch: {
newData: 'updateData',
data: 'uptData',
"init.templates"(newValue) { // 如果配置發生改變,則刷新編輯器
this.reFresh = false;
this.$nextTick(() => {
this.reFresh = true;
});
},
},
methods: {
async getBandData() {
let urlResult = await getTemplates(); //這邊我是自己封裝了個插件,通過getTemplates介面,從後端讀取模板,再顯示到編輯器插件上,如果不需要可以刪掉
if (urlResult.code == 200) {
let array = urlResult.data;
let arr = [];
for (let index = 0; index < array.length; index++) {
const element = array[index];
let data = {
title: element.name,
content: element.html,
description: element.html,
// description: "<img src='"+this.urlConfig.adminUrl + element.thumbnail+"'/>",
};
arr.push(data);
}
this.laws = arr; //得到的數據賦值給laws
this.init.templates = this.laws;
}
},
addContent(html) {
console.log('html', html)
this.newData = this.newData + html
},
uptData() {
this.newData = JSON.parse(JSON.stringify(this.data))
},
updateData() {
this.onChange(this.newData)
},
clear() {
this.editorValue = "";
},
},
};
</script>
在頁面中引用
<template>
<Editor v-bind:data="data" :onChange="onchange"></Editor>
</template>
import Editor from "../../../components/tinymce/editor";
export default {
data() {
return {
data:''
};
},
components: {
Editor
},
methods: {
onchange(e){
this.data = e
}
}
}