tinymce系列(三) tinymce 常用API介绍
# tinymce 常用 API 介绍
这篇文章将会介绍常用的 API,对于下面的示例代码,很多都用到了一个 editor
的变量。 注意 editor 是当前的实例,而非全局变量,如需要使用全局变量改用 tinymce.activeEditor
editor 通常来自 PluginManager.add
注册插件后,回调参数中会携带 editor 实例
# 引入模块
tinymce.util.Tools.resolve
- 原文文档 tinymce.util.tools (opens new window)
- 可以引入的模块可以参考文档 API Reference (opens new window) 部分
参考代码节选自 :tinymce 的 fullpage 插件 (opens new window)
var global = tinymce.util.Tools.resolve('tinymce.PluginManager')
var global$1 = tinymce.util.Tools.resolve('tinymce.util.Tools')
var global$2 = tinymce.util.Tools.resolve('tinymce.html.DomParser')
var global$3 = tinymce.util.Tools.resolve('tinymce.html.Node')
var global$4 = tinymce.util.Tools.resolve('tinymce.html.Serializer')
2
3
4
5
如果不使用 util.Tools.resolve 引入,部分功能也可以通过 tinymce.PluginManager
直接调用
# 注册插件
PluginManager.add('插件名称', function(editor,path){})
参数 | 作用 |
---|---|
editor | 获取当前 tinymce 实例 |
path | 获取当前加载的 URL(是相对 tinymce 的网络路径,主要用于加载其他额外资源的时候会用到) |
* editor 对象作为当前 tinymce 的实例非常重要,包括当前插件中的事件绑定,获取当前实例的配置等
* editor 等同于 tinymce.activeEditor 或 tinymce.get('my_editor')
官方示例如下,在 add 的回调方法中进行按钮注册,逻辑绑定等处理
除了基础按钮,下拉菜单,还有非常多的内置表单类型,详情查看文档 tinymce.editor.ui.registry (opens new window)
tinymce.PluginManager.add('MyPlugin', function(editor, url) {
// Register a toolbar button that triggers an alert when clicked
// To show this button in the editor, include it in the toolbar setting
editor.ui.registry.addButton('myCustomToolbarButton', {
text: 'My Custom Button',
onAction: function() {
alert('Button clicked!')
}
})
// Register a menu item that triggers an alert when clicked
// To show this menu item in the editor, include it in the menu setting
editor.ui.registry.addMenuItem('myCustomMenuItem', {
text: 'My Custom Menu Item',
onAction: function() {
alert('Menu item clicked')
}
})
// Either return plugin metadata or do not return
return {
name: 'MyPlugin',
url: 'https://mydocs.com/myplugin'
}
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 获取编辑器传入的参数
editor.getParam
getParma 接收 2 个参数
- 要获取的配置变量名
- 获取不到的时候的默认值
参数传递在 tinymce.init
方法中开始传入,比如传入一个 myvalue
参数:
业务代码中
tinymce.init({
selector: 'textarea.tinymce',
myvalue: { key: 'value' } // 这里的参数是任意类型,可以为string、回调函数等(回调函数建议通过事件的方式触发)
})
2
3
4
插件逻辑中,使用 getParam 获取参数
// 如果要使用 editor 必须在 tinymce.PluginManager.add 回调里面拿到 editor 实例
var someval = editor.getParam('myvalue', { key: '1' })
// 如果想在其他地方获取参数,可以使用 tinymce 当前获取焦点的编辑器获取实例
var someval1 = tinymce.activeEditor.getParam('myvalue', { key: '1' })
// 也可以通过指定 tinymce 的节点ID获取 (textarea.tinymce 就是 class名为 tinymce的textarea 标签)
var someval2 = tinymce.get('textarea.tinymce').getParam('myvalue')
2
3
4
5
6
7
8
# 事件监听与派发
editor.fire() 和 editor.on()
派发后的事件在业务逻辑中,或者不同的插件中也能监听到,只能能获取 editor 实例的地方都能监听
事件派发:通过 editor.fire('事件名',参数值)
事件监听:事件派发后,通过 editor.on('事件名', 回调函数)
进行监听
实现局部的事件派发:
参考使用 tinymce.util.eventdispatcher (opens new window)
var eventDispatcher = new EventDispatcher()
eventDispatcher.on('click', function() {
console.log('data')
})
eventDispatcher.fire('click', { data: 123 })
2
3
4
5
# tinymce 内置请求
建议还是通过业务逻辑完成请求,避免在插件中发起请求
JSON 请求
var json = new tinymce.util.JSONRequest({
url: 'somebackend.php',
params: ['a', 'b'],
success: function(result) {
console.dir(result)
}
})
2
3
4
5
6
7
XHR 请求
// Sends a low level Ajax request
tinymce.util.XHR.send({
url: 'someurl',
success: function(text) {
console.debug(text)
}
})
// Add custom header to XHR request
tinymce.util.XHR.on('beforeSend', function(e) {
e.xhr.setRequestHeader('X-Requested-With', 'Something')
})
2
3
4
5
6
7
8
9
10
11
12
JSONP 请求 在文档没有详细列出,在 tinymce.js 源码可以看到相关的逻辑
JSONP 虽然是通过添加 script 标签发出的请求,不过会在底层参数中加上对应的资源标识,所以可以使用 callback 找到发出的请求对应的参数值
tinymce JSONP 源码实现部分:
var JSONP = {
callbacks: {},
count: 0,
send: function(settings) {
var self = this,
dom = DOMUtils$1.DOM,
count = settings.count !== undefined ? settings.count : self.count
var id = 'tinymce_jsonp_' + count
self.callbacks[count] = function(json) {
dom.remove(id)
delete self.callbacks[count]
settings.callback(json)
}
dom.add(dom.doc.body, 'script', {
id: id,
src: settings.url,
type: 'text/javascript'
})
self.count++
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
JSONP 在插件中使用,发送请求
const $jsonp = tinymce.util.Tools.resolve('tinymce.util.JSONP')
$jsonp.send({
url: 'someurl',
callback: function(json) {
resolve(json)
}
})
2
3
4
5
6
7
8
# 动态添加资源
有时候会有动态加载 JS,或者动态加载样式的需求
tinymce 有时候是通过 iframe 的形式嵌入,直接使用 document.body 插入的资源也无法影响 iframe 内容,所以需要使用内置的 API 进行添加
动态加载 JS tinymce.dom.scriptloader (opens new window)
// Load a script from a specific URL using the global script loader
tinymce.ScriptLoader.load('somescript.js')
// Load a script using a unique instance of the script loader
var scriptLoader = new tinymce.dom.ScriptLoader()
scriptLoader.load('somescript.js')
// Load multiple scripts
var scriptLoader = new tinymce.dom.ScriptLoader()
scriptLoader.add('somescript1.js')
scriptLoader.add('somescript2.js')
scriptLoader.add('somescript3.js')
scriptLoader.loadQueue(function() {
alert('All scripts are now loaded.')
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
通过添加 dom 节点方式添加 tinymce.dom.domutils (opens new window)
tinymce.activeEditor.dom.add(tinymce.activeEditor.getBody(), 'script', {
src: 'somescript4.js',
type: 'text/javascript'
})
2
3
4
# 获取和操作 dom 节点 和 操作 html
操作 dom 的时候尽可能使用内置的 DomQuery
等之类的 API,因为有时候 tinymce 是通过 iframe 的形式嵌入,普通的 document.querySelector
可能无法找到对应的 dom,插入的资源也无法影响 iframe 内容
如果要使用 document.querySelector
等原生 API,使用 tinymce.activeEditor.getBody() 或 editor.doc
替换 document
。
editor.doc.querySelector('.my_plugin') // 获取到编辑器中 .my_plugin 的节点
tinymce.activeEditor.getBody() 或 editor.doc
永远都指向于 tinymce 的 dom 实例
- 获取 dom 节点,更多适用于已有 dom 节点,需要操作节点中的内容
tinymce.dom.DomQuery (opens new window)
tinymce 提供了类似 JQ 的功能。不过没有 JQ 那么完善,使用方法可以直接通过 $ = tinymce.dom.DomQuery
或者使用 $ = tinymce.util.Tools.resolve('tinymce.dom.DomQuery')
- html 操作,更多适用于字符串类型解析为 dom 类型
把 HTML 字符串解析 html 节点tinymce.html.domparser (opens new window)
把 HTML 解析单个节点 tinymce.html.node (opens new window)
# 获取光标选中内容
选中的文本会有 2 个情况,在代码的注释有说明。代码节选中 zk_quick_style 部分
相关 API 文档:
光标操作: tinymce.dom.selection (opens new window)
功能是把选中的文本/没选中状态下把该段文本包裹一个指定的样式
/**
* 获取选中的内容
* @param {*} editor
*/
function getRangeText(editor = tinymce.activeEditor) {
let rngInfo = editor.selection.getRng()
let rangeText = rngInfo.commonAncestorContainer.textContent
if (!rangeText) {
return ''
}
// 这里是因为如果有3段文本,选中其中2段的时候,commonAncestorContainer 的文本其实是给出了3段合并的文字
// 但是选中范围是根据第一段文字和最后一段文字来计算的位置,所以要根据开头文本开始匹配
let _startText = rngInfo.startContainer.textContent
rangeText = rangeText.replace(new RegExp(`.*(${_startText}.*)`), '$1')
let _start = rngInfo.startOffset
let _end = rngInfo.endOffset
let _select = _end - _start
if (_select == 0 || _select == rangeText.length) {
// 情况1:_select == 0 就是没有选中任何文本,那就把当前的 div 的文本都提出来,走默认就行,并且创建选取,选中该文本
// 情况2:在同一行中,选中了全部的字,这时候应该把他上级的节点也选中,否则使用 insert 的时候上面会多一个空行
editor.selection.select(rngInfo.commonAncestorContainer)
} else {
// 如果有选中内容,并且考虑多行的情况, _end 记录的是最后一行选中的字符,而不是光标全中的长度
let _endText = rngInfo.endContainer.textContent
rangeText = rangeText.replace(new RegExp(`(.*)${_endText}`), '$1')
rangeText += _endText.substring(0, _end)
rangeText = rangeText.substring(_start, rangeText.length)
}
return rangeText
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# 保存快照(撤销和重做)
原文文档:tinymce.undomanager (opens new window)
在进行一些操作步骤后如果想记录该操作用用户可以撤销的话,可以使用以下指令
editor.undoManager.add()
# 执行内置指令
指令文档 execcommand (opens new window)
web 中也有内置指令 MDN-execCommand (opens new window),不过该 API 已经废弃,虽然可能还能调用(不清楚兼容性),推荐还是使用 tinymce 封装过的 execCommand
进行指令执行
对于常见的 加粗
,居中
等操作。web 有一套指令,tinymce 在这基础上也封装了独有的指令,调用方式如下:
// 示例
editor.execCommand('指令名称')
// 左对齐指令
editor.execCommand('JustifyLeft')
// 居中
editor.execCommand('JustifyCenter')
2
3
4
5
6
7
8
收集到的常用指令如下:
指令名称 | 效果 |
---|---|
bold | 加粗 |
italic | 斜体 |
subscript | 下标 |
superscript | 上标 |
strikeThrough | 删除线 |
underline | 下划线 |
insertOrderedList | 插入有序列表 |
insertUnorderedList | 插入无序列表 |
justifyCenter | 居中 |
justifyFull | 环绕对齐 |
justifyLeft | 左对齐 |
justifyRight | 右对齐 |
insertHorizontalRule | 插入水平尺 |
文档没有列出很多的资料名称,不过可以通过查阅源码找到想要执行的指令,在 tinymce.js 文件中搜索 EditorCommands.prototype.setupCommands
可以看到大多数的指令和实现方式
# 注册自己的指令
相关文档: addcommand (opens new window)
代码来自官网的示例:
注册了一个叫 mycommand 的指令。效果是通过 内置的 windowManager
弹出 当前选中的文本
editor.addCommand('mycommand', function(ui, v) {
editor.windowManager.alert('Hello world!! Selection: ' + editor.selection.getContent({ format: 'text' }))
})
// 执行指令
editor.execCommand('mycommand')
2
3
4
5
6
# 插入和设置内容
分别是 setContent
和 insertContent
editor.setContent(`<p>把整个编辑器内容设置为这段文本</p>`)
editor.insertContent(`<p>在光标当前位置插入当前文本</p>`)
2
# 最后
tinymce 常用的 API 大概就是以上的内容,已经涵盖了事件监听,获取 dom 节点,光标操作,内部指令等。
光有 API 还是不太够,下一章将会介绍 tinymce 常用内置 UI 组件介绍