前言
TinyMCE是一款开源、易用、UI 时新、所见即所得的富文本编辑器。是富文本领域中的佼佼者。整体设计和模式,都是非常不错的。其提供的 API 极其丰富和强大,简单点 就是专业牛👍,可供广大开发者用户,方便快捷的自行进行扩展或根据实际业务需求进行二次开发。下面我将分享 3 种方式,带你玩废 tinymce,适合接触过 tinymce 的 小伙伴,如果没有接触过 就随便看看,收藏也不吃亏,保不齐,后面用得上,知道可以这样玩就好了😎
利用 tinymce 官方提供的 UI 组件扩展
tinymce 官方提供还算多的 UI 组件,基本满足大部分应用场景,
此外 对话框(dialog)的主体必须是panel
(单个面板)或tabpanel
(面板的集合)。每个面板都可以包含面板组件,这些组件可以是布局组件,也可以是输入、按钮和文本等基本组件。通过提供的 UI 组件 你可以扩展成你想要的大部分组件
利用 iframe 引入自定义功能页面
利用 iframe 引入自定义功能页面 这种方式 ,自定义页面和 tinymce 本身相对独立,互不干扰,只需要控制好自定义功能页面 和 tinymce 之间的数据通信就好了。这种开发模式,主要利用了 tinymce API 的 URL 对话框 ( windowManager.openUrl(args: Object))URL 对话框配置具有三个主要部分,以匹配对话框 UI 的三个主要部分:
主要配置参数有如下表格所示
更多选项可前往查看
还是先上手 先来搭个起手式 举一个小例子 一个不可编辑的输入框组件
先在创建一个 index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>新窗口</title>
</head>
<body>
<div>
<input id="inputID" type="text" value="Hello Five!" placeholder="Hello Five!" oninput="onInputFn()">
</div>
<script>
let inputID = document.getElementById('inputID')
//初始化 如果有值 可以替换掉
window.parent.openUrlData?inputID.value = window.parent.openUrlData: ''//使用window.parent.openUrlData 调用父页面的数据
window.parent.openUrlData = inputID.value
// 更新数据
function onInputFn(){
window.parent.openUrlData = inputID.value
}
</script>
</body>
</html>
复制代码
核心代码
var getOpenUrlValue = function (editor:any) {//获取选中节点的值作为初始值
return editor.dom.getParent(editor.selection.getNode(), '[data-tp-open-url]')?.innerText
}
//@ts-ignore
window.openUrlData = getOpenUrlValue(editor)||'' // 利用window挂上全局 openUrlData 在iframe的子页面 使用window.parent.openUrlData 调用
editor.windowManager.openUrl({
title: 'openUrl',
width: 300,
url: '/openUrl/index.html',//根据自己的实际路径来
buttons: [
{
type: 'cancel',
text: 'Close'
},
{
type: 'custom',
text: 'Save',
name: 'save',
primary: true
},
],
onAction: function (api:any, details:any) {
switch (details.name) {
case 'save':
//@ts-ignore
editor.insertContent('<span style="" contenteditable="false" >'+window.openUrlData+'</span>')
api.close();
break;
default:
break;
}
}
});
}
复制代码
效果如下图所示
当然基本搭好后开始美化,加上上下文菜单 和 按钮状态
添加按钮核心代码
//状态选择器适配器 用于更新按钮状态
const stateSelectorAdapter = function (editor:any, selector:any) {
return function (buttonApi:any) {
return editor.selection.selectorChangedWithUnbind(selector.join(','),buttonApi.setActive).unbind;
};
}
editor.ui.registry.addToggleButton('tp-openurl', {
icon: 'tp-openurl',
tooltip: 'Open Url',
onSetup: stateSelectorAdapter(editor, [
'*[data-tp-open-url]',
]),
onAction: () => Main.create(editor,opt)
});
var cmd = function (command:string) {
return function () {
return editor.execCommand(command);
};
};
//注册删除OpenUrl按钮
editor.ui.registry.addButton('tpOpenUrlDelete', {
tooltip: 'Delete',
onAction: cmd('mceTpOpenUrlDelete'),
icon: 'table-delete-table',
});
//注册编辑OpenUrl按钮
editor.ui.registry.addButton('tpOpenUrlProps ', {
tooltip: 'Edit Open Url',
onAction: cmd('tpOpenUrl'),
icon: 'tp-openurl',
});
//注册编辑OpenUrl 删除逻辑
editor.addCommand('mceTpOpenurlDelete', function () {
try {
editor.dom.getParent(editor.selection.getNode(), '[data-tp-open-url]').remove() //获得选中节点 删除即可
editor.focus();
} catch (error) {
}
})
//上下文菜单配置 (已注册的按钮)
var openurlToolbar = 'tpOpenUrlProps \| tptpOpenUrlDelete'
if (openurlToolbar.length > 0) {
var isOpenurl = function (_openurl:any) {//判断是否是 Openurl 用于触发上下文菜单
return editor.dom.is(_openurl, '[data-tp-open-url]') && editor.getBody().contains(_openurl);
};
//注册上下文菜单
editor.ui.registry.addContextToolbar('tp-openurl', {
predicate: isOpenurl,
items: openurlToolbar,
scope: 'node',
position: 'node'
});
}
复制代码
以上就是一个简单的小例子 可以自行扩展,例如接入 LogicFlow 流程图框架 ,开发成一个流程图插件,流程图插件,流程图部分是在 vue2.0 中开发,打包后通过 tinymce API URL 对话框 ( windowManager.openUrl(args: Object))引入核心代码
var getLogicflowValue = function (editor:any) {
let objectVal = editor.dom.getParent(editor.selection.getNode(), '[data-tp-logicflow]')
if(objectVal){
try {
//@ts-ignore
window.tpLogicflow.tp_initData = objectVal.firstChild || ''
} catch (error) {
//@ts-ignore
window.tpLogicflow.tp_initData = ''
}
}else{
//@ts-ignore
window.tpLogicflow.tp_initData =''
}
};
getLogicflowValue(editor)
editor.windowManager.openUrl({
title: data.name,
size: 'large',
url: '/logicflow/index.html',
buttons: [
{
type: 'cancel',
text: 'Close'
},
{
type: 'custom',
text: 'Save',
name: 'save',
primary: true
},
],
onAction: function (api:any, details:any) {
switch (details.name) {
case 'save'
//@ts-ignore
window.tpLogicflow.saveGraphSVGData().then(res=>{
editor.insertContent('<span data-tp-logicflow data-tp-logicflow contenteditable="false" data-tp-no-img><object data="'+res.url+'" style="'+res.style+'"/></span>')
api.close();
break;
default:
break;
}
}
});
复制代码
流程图插件数据通信
window.tpLogicflow = {
translateI18n: editor.editorManager.i18n.translate // 用于支持多语言
复制代码
利用 webCompontent 硬核扩展
想知道如何利用 webCompontent 扩展,哪肯定得先了解一下 webCompontent (必须得看 ,了解过的 麻烦再看一遍 😨)
什么是 Web Component?
Web Component 是一种 W3C 标准 支持的组件化方案,通过它,我们可以编写可复用的 组件,同时,就如同写单页 VUE 模板,他并非一项单一的技术,而是由三项技术组成:
Custom elements(自定义元素):一组 JavaScript API,允许您定义 custom elements 及其行为,然后可以在您的用户界面中按照需要使用它们。Shadow DOM(影子 DOM):一组 JavaScript API,用于将封装的“影子”DOM 树附加到元素(与主文档 DOM 分开呈现)并控制其关联的功能。通过这种方式,您可以保持元素的功能私有,这样它们就可以被 脚本化
和样式化
,而不用担心与文档的其他部分发生冲突。HTML templates(HTML 模板):<template>
和 <slot>
元素使您可以编写不在呈现页面中显示的标记模板,类似比 Vue
的模板语法。然后它们可以作为自定义元素结构的基础被多次重用。
Web Component 生命周期
和大多数框架一样,Web Component 也含有许多控制组件生命周期的方法。
connectedCallback:当 custom elemen t 首次被插入 DOM 时,被调用。
disconnectedCallback:当 custom element 从 DOM 中删除时,被调用。
adoptedCallback:当 custom element 被移动到新的文档时,被调用。
attributeChangedCallback: 当 custom element 增加、删除、修改自身属性时,被调用。
他需要 搭配 observedAttributes 使用。
实现 web component 的基本方法
创建一个类或函数来指定 web 组件的功能,如果使用类,请使用 ECMAScript 2015 的类语法 (参阅类获取更多信息)。使用 CustomElementRegistry.define() 方法注册您的新自定义元素 ,并向其传递要定义的元素名称、指定元素功能的类、以及可选的其所继承自的元素。如果需要的话,使用 Element.attachShadow() 方法将一个 shadow DOM 附加到自定义元素上。使用通常的 DOM 方法向 shadow DOM 中添加子元素、事件监听器等等。如果需要的话,使用
评论