天天看點

地表最強富文本編譯器——Tinymce使用指南TinyMCE相容性一、安裝環境二、複制靜态檔案到public目錄三、頁面使用四、tinymce的三種模式五、頁面多個編輯器的配置六、編輯器配置說明七、業務上一些常用的API

Vue項目中tinymce富文本的安裝以及配置

對于目前網上存在的許多富文本插件中,個人還是覺得tinymce相對比較強大一些。在使用配置的過程中,可能會出現配置不完全,導緻使用不了的情況,下面把我個人使用的經驗分享給大家,希望對你們有所幫助。

TinyMCE相容性

PC浏覽器相容性

TinyMCE使用JS封裝行為來規範各個浏覽器之間的渲染行為,以確定統一的使用者體驗。我們主要關注的浏覽器包括Chrome、Firefox、IE和Safari。

未列出的浏覽器可能意味着TinyMCE未在該浏覽器上進行過全面測試,可以試試首頁的示例DEMO,用以确定是否相容。(國産浏覽器大都用的是Chrome的核,相容完全沒問題)

浏覽器 Windows Mac GNU/Linux
Chrome Yes Yes Yes
Firefox Yes Yes Yes
Safari - Yes -
Edge Yes - -
IE 11 Yes - -
IE 8-10 No - -

因為TinyMCE v5用到了很多現代浏覽器才支援的标準,是以IE10及以下全部陣亡。TinyMCE作為一個商業性的開源編輯器,更新頻率是可以保證的,是以完全支援以上浏覽器的最新版本。

移動端浏覽器相容性

系統 浏覽器 裝置
Android 6,7,8 Chrome 手機
iOS 10,11 Safari iPhone/iPad

一、安裝環境

安裝tinymce插件指令

vue-cli版本:3.x+

安裝tinymce

npm install [email protected] -S

安裝tinymce-vue

npm install @tinymce/[email protected] -S

我這邊用的版本是:

tinymce-vue:3.2.8

tinymce:5.10.3

注:vue2中不能使用@tinymce/tinymce-vue為4以上的版本

vue-cli版本:2.x的安裝

安裝tinymce

npm install tinymce -S

安裝tinymce-vue

npm install @tinymce/[email protected] -S

二、複制靜态檔案到public目錄

先在public建立tinymce目錄,然後到node_modules目錄下找到一個tinymce檔案夾,複制到public的tinymce目錄下;

地表最強富文本編譯器——Tinymce使用指南TinyMCE相容性一、安裝環境二、複制靜态檔案到public目錄三、頁面使用四、tinymce的三種模式五、頁面多個編輯器的配置六、編輯器配置說明七、業務上一些常用的API

tinymce 預設是英文界面,是以還需要下載下傳一個中文語言包。

在public目錄下建立langs檔案夾,在裡面建立zh_CN.js檔案進行中文,(可以到官網下載下傳中文語言包 zh_CN.js)代碼如下

tinymce.addI18n('zh_CN',{
    "Redo": "恢複",
    "Undo": "撤銷",
    "Cut": "剪切",
    "Copy": "複制",
    "Paste": "粘貼",
    "Select all": "全選",
    "New document": "建立文檔",
    "Ok": "确定",
    "Cancel": "取消",
    "Visual aids": "網格線",
    "Bold": "粗體",
    "Italic": "斜體",
    "Underline": "下劃線",
    "Strikethrough": "删除線",
    "Superscript": "上标",
    "Subscript": "下标",
    "Clear formatting": "清除格式",
    "Align left": "左對齊",
    "Align center": "居中",
    "Align right": "右對齊",
    "Justify": "兩端對齊",
    "Bullet list": "符号清單",
    "Numbered list": "數字清單",
    "Decrease indent": "減少縮進",
    "Increase indent": "增加縮進",
    "Close": "關閉",
    "Formats": "格式",
    "Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "目前浏覽器不支援通路剪貼闆,請使用快捷鍵Ctrl+X/C/V複制粘貼",
    "Headers": "标題",
    "Header 1": "标題1",
    "Header 2": "标題2",
    "Header 3": "标題3",
    "Header 4": "标題4",
    "Header 5": "标題5",
    "Header 6": "标題6",
    "Headings": "标題",
    "Heading 1": "标題1",
    "Heading 2": "标題2",
    "Heading 3": "标題3",
    "Heading 4": "标題4",
    "Heading 5": "标題5",
    "Heading 6": "标題6",
    "Preformatted": "預格式化",
    "Div": "Div區塊",
    "Pre": "預格式文本",
    "Code": "代碼",
    "Paragraph": "段落",
    "Blockquote": "引用",
    "Inline": "文本",
    "Blocks": "區塊",
    "Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "目前為純文字粘貼模式,再次點選可以回到普通粘貼模式。",
    "Fonts": "字型",
    "Font Sizes": "字号",
    "Class": "Class",
    "Browse for an image": "浏覽圖像",
    "OR": "或",
    "Drop an image here": "拖放一張圖檔檔案至此",
    "Upload": "上傳",
    "Block": "塊",
    "Align": "對齊",
    "Default": "預設",
    "Circle": "空心圓",
    "Disc": "實心圓",
    "Square": "方塊",
    "Lower Alpha": "小寫英文字母",
    "Lower Greek": "小寫希臘字母",
    "Lower Roman": "小寫羅馬字母",
    "Upper Alpha": "大寫英文字母",
    "Upper Roman": "大寫羅馬字母",
    "Anchor...": "錨點...",
    "Name": "名稱",
    "Id": "id",
    "Id should start with a letter, followed only by letters, numbers, dashes, dots, colons or underscores.": "id應該以字母開頭,後跟字母、數字、橫線、點、冒号或下劃線。",
    "You have unsaved changes are you sure you want to navigate away?": "你對文檔的修改尚未儲存,确定離開嗎?",
    "Restore last draft": "恢複上次的草稿",
    "Special characters...": "特殊字元...",
    "Source code": "HTML源碼",
    "Insert\/Edit code sample": "插入/編輯代碼示例",
    "Language": "語言",
    "Code sample...": "代碼示例...",
    "Color Picker": "選取顔色",
    "R": "R",
    "G": "G",
    "B": "B",
    "Left to right": "從左到右",
    "Right to left": "從右到左",
    "Emoticons...": "表情符号...",
    "Metadata and Document Properties": "中繼資料和文檔屬性",
    "Title": "标題",
    "Keywords": "關鍵詞",
    "Description": "描述",
    "Robots": "機器人",
    "Author": "作者",
    "Encoding": "編碼",
    "Fullscreen": "全屏",
    "Action": "操作",
    "Shortcut": "快捷鍵",
    "Help": "幫助",
    "Address": "位址",
    "Focus to menubar": "移動焦點到菜單欄",
    "Focus to toolbar": "移動焦點到工具欄",
    "Focus to element path": "移動焦點到元素路徑",
    "Focus to contextual toolbar": "移動焦點到上下文菜單",
    "Insert link (if link plugin activated)": "插傳入連結接 (如果連結插件已激活)",
    "Save (if save plugin activated)": "儲存(如果儲存插件已激活)",
    "Find (if searchreplace plugin activated)": "查找(如果查找替換插件已激活)",
    "Plugins installed ({0}):": "已安裝插件 ({0}):",
    "Premium plugins:": "優秀插件:",
    "Learn more...": "了解更多...",
    "You are using {0}": "你正在使用 {0}",
    "Plugins": "插件",
    "Handy Shortcuts": "快捷鍵",
    "Horizontal line": "水準分割線",
    "Insert\/edit image": "插入/編輯圖檔",
    "Image description": "圖檔描述",
    "Source": "位址",
    "Dimensions": "大小",
    "Constrain proportions": "保持寬高比",
    "General": "正常",
    "Advanced": "進階",
    "Style": "樣式",
    "Vertical space": "垂直邊距",
    "Horizontal space": "水準邊距",
    "Border": "邊框",
    "Insert image": "插入圖檔",
    "Image...": "圖檔...",
    "Image list": "圖檔清單",
    "Rotate counterclockwise": "逆時針旋轉",
    "Rotate clockwise": "順時針旋轉",
    "Flip vertically": "垂直翻轉",
    "Flip horizontally": "水準翻轉",
    "Edit image": "編輯圖檔",
    "Image options": "圖檔選項",
    "Zoom in": "放大",
    "Zoom out": "縮小",
    "Crop": "裁剪",
    "Resize": "調整大小",
    "Orientation": "方向",
    "Brightness": "亮度",
    "Sharpen": "銳化",
    "Contrast": "對比度",
    "Color levels": "色階",
    "Gamma": "伽馬值",
    "Invert": "反轉",
    "Apply": "應用",
    "Back": "後退",
    "Insert date\/time": "插入日期/時間",
    "Date\/time": "日期/時間",
    "Insert\/Edit Link": "插入/編輯連結",
    "Insert\/edit link": "插入/編輯連結",
    "Text to display": "顯示文字",
    "Url": "位址",
    "Open link in...": "連結打開方式...",
    "Current window": "目前視窗打開",
    "None": "在目前視窗/架構打開",
    "New window": "在新視窗打開",
    "Remove link": "删除連結",
    "Anchors": "錨點",
    "Link...": "連結...",
    "Paste or type a link": "粘貼或輸傳入連結接",
    "The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?": "你所填寫的URL位址為郵件位址,需要加上mailto:字首嗎?",
    "The URL you entered seems to be an external link. Do you want to add the required http:\/\/ prefix?": "你所填寫的URL位址屬于外部連結,需要加上http://:字首嗎?",
    "Link list": "連結清單",
    "Insert video": "插入視訊",
    "Insert\/edit video": "插入/編輯視訊",
    "Insert\/edit media": "插入/編輯媒體",
    "Alternative source": "替代資源",
    "Alternative image URL": "資源備用位址",
    "Media poster (Image URL)": "封面(圖檔位址)",
    "Paste your embed code below:": "将内嵌代碼粘貼在下面:",
    "Embed": "内嵌",
    "Media...": "多媒體...",
    "Nonbreaking space": "不間斷空格",
    "Page break": "分頁符",
    "Paste as text": "粘貼為文本",
    "Preview": "預覽",
    "Print...": "列印...",
    "Save": "儲存",
    "Find": "查找",
    "Replace with": "替換為",
    "Replace": "替換",
    "Replace all": "替換全部",
    "Previous": "上一個",
    "Next": "下一個",
    "Find and replace...": "查找并替換...",
    "Could not find the specified string.": "未找到搜尋内容。",
    "Match case": "區分大小寫",
    "Find whole words only": "全單詞比對",
    "Spell check": "拼寫檢查",
    "Ignore": "忽略",
    "Ignore all": "忽略全部",
    "Finish": "完成",
    "Add to Dictionary": "添加到字典",
    "Insert table": "插入表格",
    "Table properties": "表格屬性",
    "Delete table": "删除表格",
    "Cell": "單元格",
    "Row": "行",
    "Column": "列",
    "Cell properties": "單元格屬性",
    "Merge cells": "合并單元格",
    "Split cell": "拆分單元格",
    "Insert row before": "在上方插入",
    "Insert row after": "在下方插入",
    "Delete row": "删除行",
    "Row properties": "行屬性",
    "Cut row": "剪切行",
    "Copy row": "複制行",
    "Paste row before": "粘貼到上方",
    "Paste row after": "粘貼到下方",
    "Insert column before": "在左側插入",
    "Insert column after": "在右側插入",
    "Delete column": "删除列",
    "Cols": "列",
    "Rows": "行",
    "Width": "寬",
    "Height": "高",
    "Cell spacing": "單元格外間距",
    "Cell padding": "單元格内邊距",
    "Show caption": "顯示标題",
    "Left": "左對齊",
    "Center": "居中",
    "Right": "右對齊",
    "Cell type": "單元格類型",
    "Scope": "範圍",
    "Alignment": "對齊方式",
    "H Align": "水準對齊",
    "V Align": "垂直對齊",
    "Top": "頂部對齊",
    "Middle": "垂直居中",
    "Bottom": "底部對齊",
    "Header cell": "表頭單元格",
    "Row group": "行組",
    "Column group": "列組",
    "Row type": "行類型",
    "Header": "表頭",
    "Body": "表體",
    "Footer": "表尾",
    "Border color": "邊框顔色",
    "Insert template...": "插入模闆...",
    "Templates": "模闆",
    "Template": "模闆",
    "Text color": "文字顔色",
    "Background color": "背景色",
    "Custom...": "自定義...",
    "Custom color": "自定義顔色",
    "No color": "無",
    "Remove color": "删除顔色",
    "Table of Contents": "目錄",
    "Show blocks": "顯示區塊邊框",
    "Show invisible characters": "顯示不可見字元",
    "Word count": "字數統計",
    "Words: {0}": "字數:{0}",
    "{0} words": "{0} 個字",
    "File": "檔案",
    "Edit": "編輯",
    "Insert": "插入",
    "View": "檢視",
    "Format": "格式",
    "Table": "表格",
    "Tools": "工具",
    "Powered by {0}": "Powered by {0}",
    "Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "在編輯區按ALT+F9打開菜單,按ALT+F10打開工具欄,按ALT+0檢視幫助",
    "Image title": "圖檔标題",
    "Border width": "邊框寬度",
    "Border style": "邊框樣式",
    "Error": "錯誤",
    "Warn": "警告",
    "Valid": "有效",
    "To open the popup, press Shift+Enter": "此快捷為軟回車(插入<br>)",
    "Rich Text Area. Press ALT-0 for help.": "編輯區. 按Alt+0鍵打開幫助",
    "System Font": "預設字型",
    "Failed to upload image: {0}": "圖檔上傳失敗: {0}",
    "Failed to load plugin: {0} from url {1}": "插件加載失敗: {0} - {1}",
    "Failed to load plugin url: {0}": "插件加載失敗: {0}",
    "Failed to initialize plugin: {0}": "插件初始化失敗: {0}",
    "example": "示例",
    "Search": "查找",
    "All": "全部",
    "Currency": "貨币",
    "Text": "文本",
    "Quotations": "引用",
    "Mathematical": "數學運算符",
    "Extended Latin": "拉丁語擴充",
    "Symbols": "符号",
    "Arrows": "箭頭",
    "User Defined": "自定義",
    "dollar sign": "美元",
    "currency sign": "貨币",
    "euro-currency sign": "歐元",
    "colon sign": "冒号",
    "cruzeiro sign": "克魯賽羅币",
    "french franc sign": "法郎",
    "lira sign": "裡拉",
    "mill sign": "密爾",
    "naira sign": "奈拉",
    "peseta sign": "比塞塔",
    "rupee sign": "盧比",
    "won sign": "韓元",
    "new sheqel sign": "新謝克爾",
    "dong sign": "越南盾",
    "kip sign": "寮國基普",
    "tugrik sign": "圖格裡克",
    "drachma sign": "德拉克馬",
    "german penny symbol": "德國便士",
    "peso sign": "比索",
    "guarani sign": "瓜拉尼",
    "austral sign": "澳元",
    "hryvnia sign": "格裡夫尼亞",
    "cedi sign": "塞地",
    "livre tournois sign": "裡弗弗爾",
    "spesmilo sign": "一千spesoj的貨币符号,該貨币未使用",
    "tenge sign": "堅戈",
    "indian rupee sign": "印度盧比",
    "turkish lira sign": "土耳其裡拉",
    "nordic mark sign": "北歐馬克",
    "manat sign": "馬納特",
    "ruble sign": "盧布",
    "yen character": "日元",
    "yuan character": "人民币元",
    "yuan character, in hong kong and taiwan": "元的繁體字",
    "yen\/yuan character variant one": "元(大寫)",
    "Loading emoticons...": "正在加載表情文字...",
    "Could not load emoticons": "不能加載表情文字",
    "People": "人類",
    "Animals and Nature": "動物和自然",
    "Food and Drink": "食物和飲品",
    "Activity": "活動",
    "Travel and Places": "旅遊和地點",
    "Objects": "物件",
    "Flags": "旗幟",
    "Characters": "字數",
    "Characters (no spaces)": "字數(不含空格)",
    "Error: Form submit field collision.": "錯誤: 表單送出字段沖突.",
    "Error: No form element found.": "錯誤: 未找到可用的form.",
    "Update": "更新",
    "Color swatch": "顔色樣本",
    "Turquoise": "青綠",
    "Green": "綠色",
    "Blue": "藍色",
    "Purple": "紫色",
    "Navy Blue": "海軍藍",
    "Dark Turquoise": "深藍綠色",
    "Dark Green": "暗綠",
    "Medium Blue": "中藍",
    "Medium Purple": "中紫",
    "Midnight Blue": "深藍",
    "Yellow": "黃色",
    "Orange": "橙色",
    "Red": "紅色",
    "Light Gray": "淺灰",
    "Gray": "灰色",
    "Dark Yellow": "暗黃",
    "Dark Orange": "暗橙",
    "Dark Red": "暗紅",
    "Medium Gray": "中灰",
    "Dark Gray": "深灰",
    "Black": "黑色",
    "White": "白色",
    "Switch to or from fullscreen mode": "切換全屏模式",
    "Open help dialog": "打開幫助對話框",
    "history": "曆史",
    "styles": "樣式",
    "formatting": "格式化",
    "alignment": "對齊",
    "indentation": "縮進",
    "permanent pen": "記号筆",
    "comments": "注釋",
    "Anchor": "錨點",
    "Special character": "特殊字元",
    "Code sample": "代碼示例",
    "Color": "顔色",
    "Emoticons": "表情",
    "Document properties": "文檔屬性",
    "Image": "圖檔",
    "Insert link": "插傳入連結接",
    "Target": "目标",
    "Link": "連結",
    "Poster": "封面",
    "Media": "音視訊",
    "Print": "列印",
    "Prev": "上一個",
    "Find and replace": "查找并替換",
    "Whole words": "全字比對",
    "Spellcheck": "拼寫檢查",
    "Caption": "标題",
    "Insert template": "插入模闆",
    //以下為補充漢化内容 by 莫若卿
    "Code view": "代碼區域",
    "Select...": "選擇...",
    "Format Painter": "格式刷",
    "No templates defined.": "無内置模闆",
    "Special character...": "特殊字元...",
    "Open link": "打開連結",
    "None": "無",
    "Count": "統計",
    "Document": "整個文檔",
    "Selection": "選取部分",
    "Words": "字詞數",
    "{0} characters": "{0} 個字元",
    "Alternative source URL": "替代資源位址",
    "Alternative description": "替代說明文字",
    "Accessibility": "可通路性",
    "Image is decorative": "僅用于裝飾",
    //5.6新增
    "Line height": "行高",
    "Cut column": "剪切列",
    "Copy column": "複制列",
    "Paste column before": "粘貼到前方",
    "Paste column after": "粘貼到後方",
    "Copy column": "複制列",
    //幫助視窗内的文字
    "Version": "版本",
    "Keyboard Navigation": "鍵盤導航",
    "Open popup menu for split buttons": "該組合鍵的作用是軟回車(插入br)",
    });
           

找到public目錄下index.html檔案,在body中添加

<script src="/tinymce/tinymce.min.js"></script>
           

三、頁面使用

在頁面的使用有兩種方式

方式1:純淨版元件:

<template>
  <!-- 富文本 -->
  <div>
    <editor v-model="content" :init="init" :disabled="disabled"></editor>
  </div>
</template>
 
 
<script>
import tinymce from "tinymce/tinymce";
import Editor from "@tinymce/tinymce-vue";
import "tinymce/icons/default/icons";
import "tinymce/themes/silver";
import "tinymce/plugins/image";
import "tinymce/plugins/media";
import "tinymce/plugins/table";
import "tinymce/plugins/lists";
import "tinymce/plugins/contextmenu";
import "tinymce/plugins/wordcount";
import "tinymce/plugins/colorpicker";
import "tinymce/plugins/textcolor";
import "tinymce/plugins/preview";
import "tinymce/plugins/code";
import "tinymce/plugins/link";
import "tinymce/plugins/advlist";
import "tinymce/plugins/codesample";
import "tinymce/plugins/hr";
import "tinymce/plugins/fullscreen";
import "tinymce/plugins/textpattern";
import "tinymce/plugins/searchreplace";
import "tinymce/plugins/autolink";
import "tinymce/plugins/directionality";
import "tinymce/plugins/visualblocks";
import "tinymce/plugins/visualchars";
import "tinymce/plugins/template";
import "tinymce/plugins/charmap";
import "tinymce/plugins/nonbreaking";
import "tinymce/plugins/insertdatetime";
import "tinymce/plugins/imagetools";
import "tinymce/plugins/autosave";
import "tinymce/plugins/autoresize"; 
 
export default {
  components: {
    Editor
  },
  props: {
    value: {
      type: String,
      default: ""
    },
    disabled: {
      type: Boolean,
      default: false
    },
    plugins: {
      type: [String, Array],
      default:
        "preview searchreplace autolink directionality visualblocks visualchars fullscreen image link media template code codesample table charmap hr nonbreaking insertdatetime advlist lists wordcount imagetools textpattern autosave autoresize"
    },
    toolbar: {
      type: [String, Array],
      default:
        "code undo redo restoredraft | cut copy paste pastetext | forecolor backcolor bold italic underline strikethrough link codesample | alignleft aligncenter alignright alignjustify outdent indent formatpainter | \
    styleselect formatselect fontselect fontsizeselect | bullist numlist | blockquote subscript superscript removeformat | \
    table image media charmap hr pagebreak insertdatetime | fullscreen preview"
    }
  },
  data() {
    return {
      //初始化配置
      init: {
        //menubar: true, // 菜單欄顯隐
        language_url: "/static/tinymce/langs/zh_CN.js",
        //language_url: '../../static/tinymce/langs/zh_CN.js', // vue-cli2.x
        language: "zh_CN",
        skin_url: "/static/tinymce/skins/ui/oxide",
        //skin_url: '../../static/tinymce/skins/ui/oxide', // vue-cli2.x
        //content_css: '../../static/tinymce/skins/content/default/content.css',// vue-cli2.x
        height: 770,
        min_height: 770,
        max_height: 770,
        toolbar_mode: "wrap",
        plugins: this.plugins,
        toolbar: this.toolbar,
        content_style: "p {margin: 5px 0;}",
        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,
        // 圖檔上傳
        images_upload_handler: (blobInfo, success, failure) => {
          // const img = 'data:image/jpeg;base64,' + blobInfo.base64()
          // success(img)
 
          const formData = new FormData()
          formData.append('file', blobInfo.blob())
          reserveTableFoodDescribe(formData).then(res => {
            if (res.code === '10000') {
              const file = res.data
              success(file.url)
              return
            }
            failure('上傳失敗')
          }).catch(() => {
            failure('上傳出錯')
          })
        }
      },
      content: this.value
    };
  },
  mounted() {
    tinymce.init({});
  },
  methods: {
    
  },
  watch: {
    value(newValue) {
      this.content = newValue;
    },
    content(newValue) {
      this.$emit("input", newValue);
    }
  }
};
</script>
           

元件使用

import Editor from "@/components/imcoder-tinymce";
components: { Editor },
<editor v-model="yourContent"></editor>
           

方式2:二次封裝版:

直接建立一個PEditor元件,代碼如下:

處理了tab切換的緩存問題(适用于jeecg-boot項目)

<template>
  <div class="tinymce-editor">
    <editor v-if="!reloading" v-model="myValue" :init="init" :disabled="disabled" @onClick="onClick"></editor>
  </div>
</template>

<script>
  import tinymce from 'tinymce/tinymce'
  import Editor from '@tinymce/tinymce-vue'
  import 'tinymce/themes/silver/theme'
  import 'tinymce/plugins/print'
  import 'tinymce/plugins/preview'
  import 'tinymce/plugins/searchreplace'
  import 'tinymce/plugins/autolink'
  import 'tinymce/plugins/directionality'
  import 'tinymce/plugins/visualblocks'
  import 'tinymce/plugins/visualchars'
  import 'tinymce/plugins/fullscreen'
  import 'tinymce/plugins/template'
  import 'tinymce/plugins/codesample'
  import 'tinymce/plugins/charmap'
  import 'tinymce/plugins/autoresize'
  import 'tinymce/plugins/hr'
  import 'tinymce/plugins/pagebreak'
  import 'tinymce/plugins/nonbreaking'
  import 'tinymce/plugins/anchor'
  import 'tinymce/plugins/insertdatetime'
  import 'tinymce/plugins/advlist'
  import 'tinymce/plugins/imagetools'
  import 'tinymce/plugins/textpattern'
  import 'tinymce/plugins/help'
  import 'tinymce/plugins/autosave'
  import 'tinymce/plugins/code'

  import '../../../public/tinymce/plugins/searchreplace/plugin.min'
  import '../../../public/tinymce/plugins/layout/plugin.min'
  import '../../../public/tinymce/plugins/letterspacing/plugin.min'
  import '../../../public/tinymce/plugins/indent2em/plugin.min'
  import '../../../public/tinymce/plugins/formatpainter/plugin.min'

  import 'tinymce/plugins/image'
  import 'tinymce/plugins/link'
  import 'tinymce/plugins/media'
  import 'tinymce/plugins/table'
  import 'tinymce/plugins/lists'
  import 'tinymce/plugins/contextmenu'
  import 'tinymce/plugins/wordcount'
  import 'tinymce/plugins/colorpicker'
  import 'tinymce/plugins/textcolor'
  import 'tinymce/plugins/fullscreen'
  import 'tinymce/icons/default'
  import { uploadAction, getFileAccessHttpUrl } from '@/api/manage'
  import { getVmParentByName } from '@/utils/util'

  export default {
    components: {
      Editor
    },
    props: {
      value: {
        type: String,
        required: false
      },
      triggerChange: {
        type: Boolean,
        default: false,
        required: false
      },
      disabled: {
        type: Boolean,
        default: false
      },
      plugins: {
        type: [String, Array],
        default:
          'print preview searchreplace autolink directionality visualblocks visualchars fullscreen image link media template codesample table charmap hr pagebreak nonbreaking anchor insertdatetime advlist lists wordcount imagetools textpattern help autosave indent2em autoresize formatpainter letterspacing layout searchreplace code'
      },
      toolbar: {
        type: [String, Array],
        default:
          'code undo redo restoredraft | cut copy paste pastetext | forecolor backcolor| bold italic underline strikethrough | link anchor | alignleft aligncenter alignright alignjustify | outdent indent |indent2em lineheight  letterspacing|' +
          '                     formatselect | fontselect | fontsizeselect | bullist numlist | blockquote subscript superscript|' +
          '                     table |image media |hr pagebreak | charmap |insertdatetime |print |preview fullscreen code|layout|searchreplace| formatpainter removeformat',
        branding: false
      },
      maxHeight: {
        type: Number,
        default:0,
        required: false
      }
    },
    data() {
      return {
        //初始化配置
        init: {
          language_url: '/tinymce/langs/zh_CN.js',
          language: 'zh_CN',
          skin_url: '/tinymce/skins/lightgray',
          height: 300,
          plugins: this.plugins,
          toolbar: this.toolbar,
          max_height: this.maxHeight,
          branding: false,
          menubar: false,
          toolbar_drawer: false,
          lineheight_formats: '1 1.1 1.2 1.3 1.4 1.5 2 28pt 30pt 31pt 32pt',
          fontsize_formats: '12px 14px 16px 18px 20px 21px 24px 36px 48px 56px 72px',
          font_formats:
            '仿宋_GB2312=仿宋_GB2312;楷體_GB2312=楷體_GB2312;黑體=SimHei;隸書=隸書;幼圓=幼圓;仿宋體=FangSong;宋體=simsun,serif;微軟雅黑=Microsoft YaHei,Helvetica Neue,PingFang SC;蘋果蘋方=PingFang SC,Microsoft YaHei;',
          images_upload_handler: (blobInfo, success) => {
            let formData = new FormData()
            formData.append('file', blobInfo.blob(), blobInfo.filename())
            formData.append('biz', 'jeditor')
            formData.append('jeditor', '1')
            uploadAction(window._CONFIG['domianURL'] + '/sys/common/upload', formData).then((res) => {
              if (res.success) {
                if (res.message == 'local') {
                  const img = 'data:image/jpeg;base64,' + blobInfo.base64()
                  success(img)
                } else {
                  let img = getFileAccessHttpUrl(res.message)
                  success(img)
                }
              }
            })
          }
        },
        myValue: this.value,
        reloading: false
      }
    },
    mounted() {
      this.initATabsChangeAutoReload()
    },
    methods: {
      reload() {
        this.reloading = true
        this.$nextTick(() => (this.reloading = false))
      },

      onClick(e) {
        this.$emit('onClick', e, tinymce)
      },
      //可以添加一些自己的自定義事件,如清空内容
      clear() {
        this.myValue = ''
      },

      /**
       * 自動判斷父級是否是 <a-tabs/> 元件,然後添加事件監聽,自動觸發reload()
       *
       * 由于 tabs 元件切換會導緻 tinymce 無法輸入,
       * 隻有重新加載才能使用(無論是vue版的還是jQuery版tinymce都有這個通病)
       */
      initATabsChangeAutoReload() {
        // 擷取父級
        let tabs = getVmParentByName(this, 'ATabs')
        let tabPane = getVmParentByName(this, 'ATabPane')
        if (tabs && tabPane) {
          // 使用者自定義的 key
          let currentKey = tabPane.$vnode.key
          // 添加事件監聽
          tabs.$on('change', (key) => {
            // 切換到自己時執行reload
            if (currentKey === key) {
              this.reload()
            }
          })
        } else {
          //update--begin--autor:wangshuai-----date:20200724------for:富文本編輯器切換tab無法修改------
          let tabLayout = getVmParentByName(this, 'TabLayout')
          tabLayout.excuteCallback(() => {
            this.reload()
          })
          //update--begin--autor:wangshuai-----date:20200724------for:文本編輯器切換tab無法修改------
        }
      }
    },
    watch: {
      value(newValue) {
        this.myValue = newValue == null ? '' : newValue
      },
      myValue(newValue) {
        if (this.triggerChange) {
          this.$emit('change', newValue)
        } else {
          this.$emit('input', newValue)
        }
      }
    }
  }
</script>
<style scoped>
</style>
           

最後送上配置完成之後的效果圖:

地表最強富文本編譯器——Tinymce使用指南TinyMCE相容性一、安裝環境二、複制靜态檔案到public目錄三、頁面使用四、tinymce的三種模式五、頁面多個編輯器的配置六、編輯器配置說明七、業務上一些常用的API

四、tinymce的三種模式

tinymce 有三種模式可選:經典模式(classic,預設)、内聯模式(inline)、沉浸模式(Distraction-free)。

經典模式

經典模式是最常見的,也就是工具欄搭配輸入區域,通過工具欄的按鈕插入、修改、格式化内容,我們也選用這種模式作為業務的主要模式,代碼就是上面封裝的元件案例,這裡不過多贅述。

再介紹一下其他兩種模式:内聯模式和沉浸模式

内聯模式

js如下:

tinymce.init({
    selector: '#tinydemo', //容器,可使用css選擇器
    language:'zh_CN', //調用放在langs檔案夾内的語言包
    toolbar: false, //隐藏工具欄
    menubar: false, //隐藏菜單欄
    inline: true, //開啟内聯模式
    plugins: [ 'quickbars','link','table' ], //選擇需加載的插件
    //選中時出現的快捷工具,與插件有依賴關系
    quickbars_selection_toolbar: 'bold italic forecolor | link blockquote quickimage',
});
           

内聯模式最大的好處,是内容完全繼承自外層定義的樣式,真正實作了"所見即所得"。但要注意,請小心使用殺傷力比較大的自定義CSS,因為這樣可能會覆寫TinyMCE控件的CSS,導緻編輯器顯示異常。上面的代碼高亮框本來是黑色主題,被TinyMCE的插件CSS污染成了白色主題……😂

沉浸模式

在該模式下,編輯器以輕巧的方式呈現。此模式提供了将常用的連結、圖像、表格等以快速插入的方式。有關該模式的例子,請參考本文檔首頁。

此模式最簡代碼:

tinymce.init({

selector: 'div.tinymce',

plugins: [ 'quickbars' ],

toolbar: false,

menubar: false,

inline: true

});

所謂‘沉浸模式’感覺就是TinyMCE強行将inline模式解釋成了另一種風格。我們也不要揭穿它,假裝不知道就好了。

後兩種模式也各有特點,但是與我們實際的應用場景不太比對,故不做介紹。有興趣可以自行了解。

五、頁面多個編輯器的配置

如果一個頁面中需要多個編輯器,有兩種方法:

一個是結合className選擇器,使用一次 tinymce 的 init 方法,生成多個執行個體,多個執行個體會共用一套配置;

示例代碼:

<template>
	<div class="default-tinymce">
        <h2>編輯器1</h2>
		<textarea class="editor"></textarea>
        <h2>編輯器2</h2>
		<textarea class="editor"></textarea>
	</div>
</template>
<script>
import Tinymce from 'tinymce'
export default {
  mounted () {
    Tinymce.init({
      selector: '.editor'
    })
  }
}
</script>
           

另一種是,需要幾個編輯器,便使用tinymce 的 init 方法生成幾種執行個體,生成的執行個體彼此無關

示例代碼:

<template>
	<div class="default-tinymce">
        <h2>編輯器1</h2>
		<textarea class="editor1"></textarea>
        <h2>編輯器2</h2>
		<textarea class="editor2"></textarea>
	</div>
</template>
<script>
import Tinymce from 'tinymce'
export default {
  mounted () {
    Tinymce.init({
      selector: '.editor1'
    })
    Tinymce.init({
      selector: '.editor2'
    })
  }
}
</script>
           

六、編輯器配置說明

1.自定義編輯器UI

theme 和 skin 我們直接使用預設的即可,無需折騰。

從上面的示例中,我們也知道基本上所有東西我們都可以去自定義的,比如隐藏不使用的menubar、調整按鈕在toolbar中的位置等。

tinymce.init({
  selector: '#editor',
  // 隐藏menubar
  menubar: false,
  // 隐藏 statusbar
  statusbar: false,
  // 隐藏品牌辨別
  branding: false,
  // 設定最大寬高
  max_height: 500,
  max_width: 500,
  // 設定最小寬高
  min_height: 100,
  min_width: 400
})
           

最後對于tinymce富文本插件的配置,下面有它的中文開發文檔位址,大家可以根據自己的需求進行相應的配置。

相關連結:

TinyMCE菜單配置詳解。

官方文檔

2.如何使用自定義的圖檔上傳?

官方有提供一個上傳的url配置,但是需要背景配合傳回指定的資料格式。

這裡我們還是希望可以自定義參數,這樣才不對背景産生影響,實作images_upload_handler函數即可,如果沒有實作的話,預設是使用base64格式的圖檔。

images_upload_handler: function(blobInfo, success, failure) {
    const maxSize = 2
    const blob = blobInfo.blob()

    // 判斷圖檔大小
    if (blob.size / 1024 / 1024 > maxSize) {
        failure('圖檔大小不能超過' + maxSize + 'MB')
        return
    }

    // 組裝圖檔資訊
    const formData = new FormData()
    formData.append('file', blob, blobInfo.fileName)

    // 調用上傳圖檔接口
    upload(formData).then(res => {
        // 将傳回的全路徑指派給success回調函數即可
        success(res.data.fileUrl)
    }).catch(() => {
        failure('檔案上傳失敗,請重試')
    })
}
           

圖檔太大,如何在編輯器内的限制圖檔大小?

tiny自帶配置可設定編輯區内的css,使用content_style及content_css皆可,本例使用content_style示範如何限制圖檔大小:

tinymce.init({
        selector: '#tinydemo',
        content_style: "img {max-width:100%;}"
    });
           

3.使用插件

除了預設的配置,如果想拓展編輯器的功能,tinymce提供的方式就是插件。

官方的插件很豐富,文檔也很詳細,大多數情況下,我隻需要官方提供的插件即可。

激活插件也很簡單,隻需要做了相應配置即可。

比如,我們想要拓展一個檢視編輯器内容HTML源碼的功能,隻需要如下配置:

tinymce.init({
  selector: '#editor',
  plugins: 'code'
})
           

在menubar的位置,多了一個Tool的分組,分組裡有一個source code的項,點選即可檢視源碼

如果我們不習慣使用menubar,而是習慣使用toolbar,我們隻需要如下配置:

tinymce.init({
  selector: '#editor',
  toolbar: 'code',
  plugins: 'code'
})
           

toolbar位置上多了一個檢視源碼的圖示,點選是相同的功能

有時候,這些基礎的功能可能滿足不了我們的需求,我們可能對這些插件進行配置。

tinymce.init({
  selector: '#editor',
   toolbar: "numlist bullist",
  plugins: 'lists'
})
           

示例中,我們配置了list元件,它支援無序(ul)清單和有序清單的功能,但是清單樣式是固定的,我們可以引入新的插件advlist,并配置

tinymce.init({
  selector: '#editor',
  toolbar: 'bullist numlist',
  plugins: 'lists advlist'
})
           

此時,我們發現我們可以選擇樣式了,有多種樣式供我們選擇,如果我們想固定某種樣式,我們可以這樣配置:

tinymce.init({
  selector: '#editor',
  toolbar: 'bullist numlist',
  plugins: 'lists advlist',
  advlist_number_styles: 'lower-alpha'
})
           

我們發現可選項隻有一個了

每個插件有哪些配置項、配置參數和配置值,官方文檔中都有詳細的描述

這些配置不太重要,一般一次配置之後就不會有改動。

4.配置插件庫

這裡會寫一下編輯器用到的插件的介紹、配置、和使用,太簡單的插件和沒用到的插件不在此說明。

Advanced Code Editor

此插件為付費插件

此插件可美化代碼預覽時候的視圖,并且還有收起/展開标簽的功能。配置此插件後,需要移除code插件。

tinymce.init({
  selector: "textarea",  // change this value according to your HTML
  plugins: "advcode",
  toolbar: "code"
});
           

AutoLink

此插件可在輸入形如「www.qq.com」的連結時,自動将文本轉化為超連結,空格和換行鍵都可以觸發

tinymce.init({
  selector: "textarea",  // change this value according to your HTML
  plugins: "autolink"
});
           

nonbreaking

鍵盤的Tab鍵,預設是切換到下一個元素的focus。此可以改變這個預設行為。

需要注意的是,table插件中也有改變改預設行為的代碼,是以要在table插件之後引用該插件。

tinymce.init({
  selector: "textarea",  // change this value according to your HTML
  plugins: "nonbreaking",
  // 此配置會改變預設行為,會在光标之後添加三個空格。
  nonbreaking_force_tab: true
});
           

autosave

此插件會自動儲存編輯器的内容到localStorage。會同時存儲兩個字段,一個是内容,一個是存儲時間。

可以配置自動儲存的時間間隔,一般以秒為機關;也可以配置内容存儲的過期時間,一般以分鐘為機關,超過這個時間段,資料會從localStorage中被清除。

tinymce.init({
  selector: "textarea",  // change this value according to your HTML
  plugins: "autosave",
  // 自動儲存的時間間隔
  autosave_interval: '30s',
  // 自動儲存的資料存儲的最大時間
  autosave_retention: '30m'
});
           

powerpaste

此插件為付費插件

此插件可以保留剪切闆内容的樣式、文檔結構。

tinymce.init({
  selector: "textarea",  // change this value according to your HTML
  plugins: "powerpaste",
  /**
   * 粘貼前是否保留文本樣式
   * @param 'clean' 不保留
   * @parma 'merge' 保留
   * @parma 'prompt' 詢問使用者
   */
  powerpaste_word_import: 'prompt',
  powerpaste_html_import: 'prompt',
  /**
   * 在粘貼到富文本之前,可以修改粘貼的内容。内容已經DOM格式化
   * @param plugin
   * @param args
   * @returns {Promise<void>}
   */
  paste_postprocess (plugin, args) {}
});
           

5.修改預設樣式

改變格式工具的預設行為

TinyMCE提供給開發人員接口,能夠覆寫格式工具的預設行為,将自定義行為添加到源碼中輸出。

當使用者單擊編輯器中粗體按鈕時,編輯器會按預設操作應用文本樣式——也就是加粗,TinyMCE内建一個文本格式化引擎,它允許你去指定該觸發行為進行什麼操作。例如,你可以定義粗體按鈕被單擊的行為是文字變紅而不是加粗。

内置格式

TinyMCE允許重寫的内置格式,如下表所示:

  • alignleft
  • aligncenter
  • alignright
  • alignjustify
  • bold
  • italic
  • underline
  • strikethrough
  • forecolor
  • hilitecolor
  • fontname
  • fontsize
  • blockquote
  • removeformat
  • p
  • h1, h2, h3, h4, h5, h6
  • div
  • address
  • pre
  • div
  • code
  • dt, dd
  • samp

一些内置格式fontsize、fontname、forecolor、hilitecolor,它們的值使用變量%value代替。此變量将替換為使用者選擇的值。

你一定會覺得這是在說神馬,我怎麼完全看不懂!我剛讀這部分文檔的時候也是雲裡霧裡,直到看完才明白官方要表達神馬,是以,我在這裡插入個例子,親自試一下就明白了。
tinymce.init({
    selector: '#tinydemo',
    plugins:'code',
    toolbar:'undo redo forecolor bold italic | alignleft aligncenter alignright | code',
    formats: {
        alignright: {selector : 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li,table,img', classes : 'right'},
        bold: {inline:'span', styles:{color:'#f00'} },
        forecolor: {inline : 'span', styles : {color:'%value',fontWeight:'700'} },
        custom_format: {block : 'h1', attributes : {title:'Header'}, styles : {color:'red'} }
    }
});
           

效果如下:

地表最強富文本編譯器——Tinymce使用指南TinyMCE相容性一、安裝環境二、複制靜态檔案到public目錄三、頁面使用四、tinymce的三種模式五、頁面多個編輯器的配置六、編輯器配置說明七、業務上一些常用的API

内置格式的參數

看完例子,再了解下面這些參數就容易很多了。

名稱 說明
inline 包裹選中文本的内聯元素名稱,比如span,加粗改變顔色預設都在外圍插個span,然後再加個style=""
block 指定一個塊元素,如h1,目前焦點外圍的塊元素将被其替換。比如焦點在p标簽内,當你使用格式工具指定為“标題1”時,p将會替換成h1。
selector 利用CSS3選擇器中所選則内容的查找比對的内容(如表中的奇數行)。
classes 值為以空格分隔的class清單,如:class1 class2。簡單說就是給選中的塊加自定義class,如上例的右對齊。
styles 值為包含名稱/值的一個對象。将自定義css樣式置入到選中内容中,如上例的加粗和顔色。
attributes 值為包含名稱/值的一個對象。給html标簽添加自定義屬性。
exact 可設值為:true,此選項将禁用樣式合并功能,用于解決一些css繼承問題,例如下劃線、删除線。預設為false。
wrapper 指定目前格式是塊元素,例如div或blockquote。

schema:照顧老舊浏覽器

該選項可指定生成的代碼是html4還是html5标準。

該值預設是html5,可選值還有:html4、html5-strict。

html5模式是完整的HTML5規範,它相容舊的HTML4。html5-strict是HTML5的嚴格模式,它隻允許HTML5規範的元素,不包括已經被移除标準的元素。html4模式則是包括完整的HTML4過渡規範。在需要相容老舊浏覽器時,可能會用到該選項。

七、業務上一些常用的API

<textarea id="tinydemo">這裡是預設文字。</textarea>
<input type="button" onclick="initTiny()" value="建立編輯器" >
<input type="button" onclick="getContent()" value="獲得内容" >
<input type="button" onclick="setContent()" value="設定内容" >
<input type="button" onclick="goEnd()" value="光标放最後" >
<input type="button" onclick="insertContent()" value="插入内容" >
<input type="button" onclick="saveContent()" value="同步内容到textarea" >
<input type="button" onclick="boldContent()" value="加粗文本" >
<input type="button" onclick="colorContent()" value="标紅文字" >
<input type="button" onclick="fontSize()" value="文字大小" >
<input type="button" onclick="getText()" value="獲得純文字" >
<input type="button" onclick="copyContent()" value="複制選中文字" >
<input type="button" onclick="pasteContent()" value="粘貼" >
<input type="button" onclick="mceImage()" value="打開圖檔對話框" >
<input type="button" onclick="indent2em()" value="自定義首行縮進" >
<input type="button" onclick="hideTiny()" value="隐藏編輯器" >
<input type="button" onclick="showTiny()" value="顯示編輯器" >
<input type="button" onclick="destroyTiny()" value="銷毀編輯器" >
           
var tinyID='tinydemo';
function initTiny(){
    tinymce.init({
        selector: '#'+tinyID,
        language:'zh_CN',
        plugins:'link image indent2em',
        auto_focus: true,
    });
}
function destroyTiny(){
    tinyMCE.editors[tinyID].destroy();
    //tinyMCE.editors[tinyID].remove();
}
function getContent(){
    var cnt = tinyMCE.editors[tinyID].getContent();
    console.log(cnt);
    alert(cnt);
}
function getText(){
    var cnt = tinyMCE.editors[tinyID].getContent({ format: 'text' });
    console.log(cnt);
    alert(cnt);
}
function goEnd(){
    editor = tinyMCE.editors[tinyID];
    editor.execCommand('selectAll');
    editor.selection.getRng().collapse(false);
    editor.focus();
}
function setContent(){ tinyMCE.editors[tinyID].setContent('設定内容'); }
function insertContent(){ tinyMCE.editors[tinyID].insertContent('<b>插入内容</b>'); }
function saveContent(){ tinyMCE.editors[tinyID].save(); }
function showTiny(){ tinyMCE.editors[tinyID].show(); }
function hideTiny(){ tinyMCE.editors[tinyID].hide(); }
function boldContent(){ tinyMCE.editors[tinyID].execCommand('bold'); }
function colorContent(){ tinyMCE.editors[tinyID].execCommand('ForeColor',false,'#f33'); }
function fontSize(){ tinyMCE.editors[tinyID].execCommand('fontSize',false,'24px'); }
function copyContent(){ tinyMCE.editors[tinyID].execCommand('copy'); }
function pasteContent(){ tinyMCE.editors[tinyID].execCommand('paste'); }
function mceImage(){ tinyMCE.editors[tinyID].execCommand('mceImage'); }
function indent2em(){ tinyMCE.editors[tinyID].execCommand('indent2em'); }