富文本编辑器是黑客进行`xss`攻击的一个重要入口,因此不得不引起重视。本文就给出一个wangEditor编辑器在前端进行`xss`过滤的解决方案。
----
首先,编辑器本身将默认过滤在编辑源码模式下,用户输入的`
';
如何避免与项目中的css冲突
最后更新于:2022-04-01 23:43:42
有使用者在使用过程中反应编辑器的css和项目中的css会有冲突,导致编辑器的样式被覆盖而显示异常。这里说一个解决样式冲突的方法,不过需要使用者手动调整一下代码。
---
**需要下载`v2.0.18.1`或者以后的版本**
首先,你需要改动一下你的`html`文件,在编辑器的外面包一层有`id`的父容器,如下:
```html
```
然后,在下载的代码中找到`dist`目录的`wangEditor.less`文件,打开,在该文件的最上方和最下方加上如下代码:
```css
/* 在 wangEditor.less 文件的最上方加上下一行代码 */
#editor-container {
/* 此处是 wangEditor.less 原有的代码 */
....
/* 在 wangEditor.less 文件的最下方加上下一行代码 */
}
```
保存,然后将这个`less`文件重新编译为`css`,然后引入到页面中就行了。
**PS:不了解如何将`less`编译为`css`的同学,其实方法很简单。百度搜索『less在线编译』就有会很多在线的工具可一键编译,使用很方便**
----
最后,如果上一步操作还是不能解决冲突,那你就在编辑器`editor-container`便签外面再加一层带`id`的父容器,然后将该`id`再写入`less`文件中,用两个`id`做选择器。还不行,再加。
不过一般情况下,只加上述的第一个父容器就可解决问题。
';
集成到vue.js
最后更新于:2022-04-01 23:43:40
如果你想在`vue.js`的项目中使用`wangEditor`,以下有一个简单的demo,以及一个`vue`组件应用的demo。
-----
**第一,简单demo**
代码如下,也可参见 https://github.com/wangfupeng1988/wangEditor/blob/master/test/vue/test-vue.html 的代码。
```html
editor test
wangEditor width vuejs
以下是编辑器的内容:
{{ editorContent }}
```
---
**第二,vue组件demo**
具体请参见:https://github.com/jiangyoucai/vueComponents ,该demo由 [@jiangyoucai](https://github.com/jiangyoucai) 同学贡献,在此感谢!
';
集成到angular
最后更新于:2022-04-01 23:43:38
如果你想在`angular.js`的项目中使用`wangEditor`,以下是一个集成示例。也可参见 https://github.com/wangfupeng1988/wangEditor/blob/master/test/angular/test-angular.html 的代码。
```html
angular test
wangEditor 集成到 angular 的示例
以下是编辑器的内容:
```
';
集成到React
最后更新于:2022-04-01 23:43:35
目前`React`在前端开发中,正是如日中天的火。想要在`React`中使用wangEditor编辑器,下面给一个简单的demo供参考。具体在项目中如何使用,需要根据情况具体分析,有问题可以在QQ群交流或者提交issue到github。
注意:如果你此时使用了其他包管理工具,例如`seajs` `require.js`或者`webpack`,请参考:http://www.kancloud.cn/wangfupeng/wangeditor2/113994
demo代码如下:
```html
test1
```
';
关于显示压缩图片
最后更新于:2022-04-01 23:43:33
**问题:**
手机端图片压缩问题
我有个问题, 我的网站文章里面有图片, 我的网站主要是在手机端访问, 我希望手机端看到的是一个压缩图片, 点击之后就出现一个原始图片, 用wangEditor怎么弄?
-----
**回答:**
根据编辑器的文档的要求,上传图片,服务器端要返回得到的图片的url地址,例如:`http://www.abc.com/imgs/123.png`
如果你要实现像你说的,得到的是一个压缩图片,点击之后再显示正常图片,那好办!**(压缩图片的工作一定是在你的服务器端做的,否则下面的免谈)**
例如,你上传图片之后,得到的原始图片地址为 `http://www.abc.com/imgs/123.png`,得到的压缩图片地址为`http://www.abc.com/imgs/456.png`,那么这时你可以返回 `http://www.abc.com/imgs/456.png#http://www.abc.com/imgs/123.png`(中间的`#`一定要有)
你返回了这个,前端得到这个url,显示的图片肯定是`456.png`,即压缩图片。这样就实现了你的第一步了。
下一步需要你自己来写js程序实现。
点击这个压缩图片的时候,你可以得到图片的`src`,然后用`#`分割,你就可以得到原始图片的url,即`http://www.abc.com/imgs/123.png`,现在原始图片url都得到了,具体如何显示,不就简单了吗?
';
关于背景图片
最后更新于:2022-04-01 23:43:31
有几位使用者提到在编辑其中增加背景图片的功能,经过思考和参考其他成熟产品,觉得背景图片并不适合在编辑器中直接集成。
编辑器本身要保证编辑出来的内容的纯粹行,能在编辑器外面控制的东西,尽量在外面控制,例如上传附件(上面的章节提到过这个问题)。从设计原则和设计模式上,也提倡这种单一职责和开放封闭,这样才能保证系统的可扩展性。
-----
实现背景图片,你完全可以参考QQ邮箱的『信纸』功能。如下图:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-28_56d26e28e647e.png)
编辑器内容使用编辑器单独控制,而信纸在右侧单独控制。当保存内容时,富文本内容单独保存,信纸的图片地址也单独保存。显示内容时,用一个容器包含富文本,然后在容器上单独加上保存的信纸图片(作为背景图片)即可。
这是大体的过程。
----
还剩下一个问题,就是在编辑内容时,选择了信纸,如何立即让信纸作为背景图片成现在编辑区域?这个其实很简单:
```js
// 选择了信纸之后,执行以下语句
editor.$txt.css('background-img', 'url(./bgimg/a.png)');
```
至于其他的`background`样式,自己在以上语句中自由控制即可。
但是注意:以上语句为`editor.$txt`设置了背景图片,是不会作为编辑器内容被获取的,信纸还得单独保存。
';
关于上传附件
最后更新于:2022-04-01 23:43:29
**有用户问到编辑器能否有上传附件的功能?我的建议是不要把附件做到内容中。**
原因很简单,如果将附件上传之后再插入到富文本内容中,其实就是一个链接的形式。如下图:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-19_56c718ec6f9bf.png)
而用户在用编辑器编辑文本时,操作是非常随意多样的,他把这个链接删了,你服务器要想实时删除上传的附件文件,是难监控到的。
还有,用户如果要上传很多个附件,也是很难管理的,还是因为富文本的内容变化多样,用户可以随便在什么地方插入附件,而且形式和链接一样。
------
反过来,我们想一下平时用附件和编辑器最多的产品是什么——是邮箱。邮箱如何处理附件的,大家应该很清楚。它把文本内容和附件分开,这样附件就可以很轻松、明了的进行管理,绝对不会和编辑内容的链接产生混淆。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-19_56c718ec83f7e.png)
你能看到的所有的邮箱产品,几乎都是这样设计的。
----
因此,在你提问编辑器能否上传附件这个问题的时候,可以想一下能否参照邮箱的实现来设计?
';
关于markdown
最后更新于:2022-04-01 23:43:26
**好多使用者问到,wangEditor编辑器能否集成`markdown`?——答案是:富文本编辑器无法和`markdown`集成到一起。**
----
先不说为什么,咱们先看看一个成熟产品中,对于富文本和`markdown`是如何处理的。
[简书](http://www.jianshu.com/) 是现在很火的一个博客网站,听人说它之所以快速的火起来,和支持`markdown`还有很大的关系。那么咱们看看这位靠着`markdown`火起来的网站,是不是真正的富文本和`markdown`集成起来了?
其实它的`markdown`编辑器和富文本编辑器完全是两个东西,根本没有在一个页面中集成起来。而切换富文本和`markdown`是在用户配置页来切换的。
默认进来是富文本编辑器,如下图:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-19_56c70b5087195.png)
可以进入用户配置页面切换成`markdown`编辑器,如下图:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-19_56c70b509b9a2.png)
再回头来新建一片文章,编辑器就切换到`markdown`了。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-19_56c70b50a924e.png)
看明白了吧?
----
下面说说从技术角度为什么难以实现这两者的切换。
简单讲来,富文本和`markdown`对于文字的处理完全是两码事儿。例如,我们选择`abcd`进行加粗,富文本会生成`
abcd`,而`markdown`会生成`**abcd**`。
如果想要两者自由切换,需要在切换时,随时切换两种规则,这就会带来很多问题。
第一,如果文字量大,要处理的信息多,单纯用js进行进算,性能是一个问题。
第二,`**abcd**`格式切换成`
abcd`格式,有现成的js库可利用,但是`
abcd`切换为`**abcd**`怎么办?`markdown`只能编辑常用格式的文字,没有`html`的样式那么强大。例如,`
`或`
abc`切换成为`markdown`就无法实现。
**所以,目前还找不到一款编辑器能自由切换`markdown`和富文本。一个东西不存在,也是有不存在的道理的。**
----
最后,请大家想明白,在你的产品中,到底是想要一个"理想主义"的自由切换,还是想要简书那样的两种形式。
想清楚。
';
常见问题
最后更新于:2022-04-01 23:43:24
';
开发一个插件
最后更新于:2022-04-01 23:43:22
####注意
**开发插件过程中,会用到编辑器提供的API,也需要了解编辑器的对象结构。这些请参见『插件开发 - 对象结构』、『插件开发 - 常用API - 全局API』、『插件开发 - 常用API - 对象API』**
------
####如何引用到页面
将插件代码写到一个独立的js文件中,例如命名为`plugin.js`,编写完成后,要这样引用到页面中。
```html
```
----
####编写 `plugin.js` 做一个demo
在`plugin.js`中编写代码,做一个demo:点击编辑区域的图片时,弹出该图片的`url`。代码如下:
```js
(function () {
// 获取 wangEditor 构造函数和 jquery
var E = window.wangEditor;
var $ = window.jQuery;
// 通过 E.plugin 注入插件代码
E.plugin(function () {
// 此处的 this 指向 editor 对象本身
var editor = this;
var $txt = editor.$txt;
$txt.on('click', 'img', function (e) {
var $img = $(e.currentTarget);
alert($img.attr('src'));
});
});
})();
```
-----------
####实际案例
wangEditor编辑器本身的许多功能都是使用插件机制开发的,例如图片、表格的toolbar
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-05_56b460d9da677.png)
这个插件的代码,可以在`wangEditor.js`中搜索 `// 编辑器区域 table toolbar` 来找到源码。
目前该插件的源码如下(**以搜索到的源码为准**)
```js
// 编辑器区域 table toolbar
(function () {
// 获取 wangEditor 构造函数和 jquery
var E = window.wangEditor;
var $ = window.jQuery;
E.plugin(function () {
var editor = this;
var txt = editor.txt;
var $txt = txt.$txt;
var $currentTable;
// 用到的dom节点
var isRendered = false;
var $toolbar = $('
');
var $triangle = $('
');
var $delete = $('
');
var $zoomSmall = $('
');
var $zoomBig = $('
');
// 渲染到页面
function render() {
if (isRendered) {
return;
}
// 绑定事件
bindEvent();
// 拼接 渲染到页面上
$toolbar.append($triangle)
.append($delete)
.append($zoomSmall)
.append($zoomBig);
editor.$editorContainer.append($toolbar);
isRendered = true;
}
// 绑定事件
function bindEvent() {
// 统一执行命令的方法
var commandFn;
function command(e, callback) {
if (commandFn) {
editor.customCommand(e, commandFn, callback);
}
}
// 删除
$delete.click(function (e) {
commandFn = function () {
$currentTable.remove();
};
command(e, function () {
setTimeout(hide, 100);
});
});
// 放大
$zoomBig.click(function (e) {
commandFn = function () {
$currentTable.css({
width: '100%'
});
};
command(e, function () {
setTimeout(show);
});
});
// 缩小
$zoomSmall.click(function (e) {
commandFn = function () {
$currentTable.css({
width: 'auto'
});
};
command(e, function () {
setTimeout(show);
});
});
}
// 显示 toolbar
function show() {
if ($currentTable == null) {
return;
}
$currentTable.addClass('clicked');
var tablePosition = $currentTable.position();
var tableTop = tablePosition.top;
var tableLeft = tablePosition.left;
var tableHeight = $currentTable.outerHeight();
var tableWidth = $currentTable.outerWidth();
// --- 定位 toolbar ---
// 计算初步结果
var top = tableTop + tableHeight;
var left = tableLeft;
var marginLeft = 0;
var txtTop = $txt.position().top;
var txtHeight = $txt.outerHeight();
if (top > (txtTop + txtHeight)) {
// top 不得超出编辑范围
top = txtTop + txtHeight;
}
// 显示(方便计算 margin)
$toolbar.show();
// 计算 margin
var width = $toolbar.outerWidth();
marginLeft = tableWidth / 2 - width / 2;
// 定位
$toolbar.css({
top: top + 5,
left: left,
'margin-left': marginLeft
});
}
// 隐藏 toolbar
function hide() {
if ($currentTable == null) {
return;
}
$currentTable.removeClass('clicked');
$currentTable = null;
$toolbar.hide();
}
// click table 事件
$txt.on('click', 'table', function (e) {
var $table = $(e.currentTarget);
// 渲染
render();
if ($currentTable && ($currentTable.get(0) === $table.get(0))) {
setTimeout(hide, 100);
return;
}
// 显示 toolbar
$currentTable = $table;
show();
// 阻止冒泡
e.preventDefault();
e.stopPropagation();
}).on('click keypress scroll', function (e) {
setTimeout(hide, 100);
});
E.$body.on('click keypress scroll', function (e) {
setTimeout(hide, 100);
});
});
})();
```
';
『插入符号』菜单
最后更新于:2022-04-01 23:43:20
####前言
- 『插入符号』菜单是一个dropPanel类型的菜单,因为点击它要弹出一个面板Panel,然后再进行其他操作。
- 『插入符号』菜单的扩展过程和『缩进』菜单一样,除了`custom-menu.js`的内容不一样。**所以请先阅读上一节『缩进』菜单的创建过程。**
- 因此,本节直接略过其他过程,直接分析`custom-menu.js`文件源码。
-----
####编写 `custom-menu.js`
直接贴出`custom-menu.js`的源码,里面有非常详细的注释。
```js
(function () {
// 获取 wangEditor 构造函数和 jquery
var E = window.wangEditor;
var $ = window.jQuery;
// 用 createMenu 方法创建菜单
E.createMenu(function (check) {
// 定义菜单id,不要和其他菜单id重复。编辑器自带的所有菜单id,可通过『参数配置-自定义菜单』一节查看
var menuId = 'symbol';
// check将检查菜单配置(『参数配置-自定义菜单』一节描述)中是否该菜单id,如果没有,则忽略下面的代码。
if (!check(menuId)) {
return;
}
// this 指向 editor 对象自身
var editor = this;
// 创建 menu 对象
var menu = new E.Menu({
editor: editor, // 编辑器对象
id: menuId, // 菜单id
title: '符号', // 菜单标题
// 正常状态和选中装下的dom对象,样式需要自定义
$domNormal: $('
'),
$domSelected: $('
')
});
// 要插入的符号(可自行添加)
var symbols = ['∑', '√', '∫', '∏', '≠', '♂', '♀']
// panel 内容
var $container = $('
');
$.each(symbols, function (k, value) {
$container.append('
' + value + '');
});
// 插入符号的事件
$container.on('click', 'a', function (e) {
var $a = $(e.currentTarget);
var s = $a.text();
// 执行插入的命令
editor.command(e, 'insertHtml', s);
});
// 添加panel
menu.dropPanel = new E.DropPanel(editor, menu, {
$content: $container,
width: 350
});
// 增加到editor对象中
editor.menus[menuId] = menu;
});
})();
```
####效果
运行页面的效果如下
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-05_56b460d9cc196.png)
';
『行高』菜单
最后更新于:2022-04-01 23:43:17
####前言
- 『行高』菜单是一个dropList类型的菜单,因为点击它要弹出一个下拉列表,然后再选择操作。
- 『行高』菜单的扩展过程和『缩进』菜单一样,除了`custom-menu.js`的内容不一样。**所以请先阅读上一节『缩进』菜单的创建过程。**
- 因此,本节直接略过其他过程,直接分析`custom-menu.js`文件源码。
-----
####编写 `custom-menu.js`
直接贴出`custom-menu.js`的源码,里面有非常详细的注释。
```js
(function () {
// 获取 wangEditor 构造函数和 jquery
var E = window.wangEditor;
var $ = window.jQuery;
// 用 createMenu 方法创建菜单
E.createMenu(function (check) {
// 定义菜单id,不要和其他菜单id重复。编辑器自带的所有菜单id,可通过『参数配置-自定义菜单』一节查看
var menuId = 'lineheight';
// check将检查菜单配置(『参数配置-自定义菜单』一节描述)中是否该菜单id,如果没有,则忽略下面的代码。
if (!check(menuId)) {
return;
}
// this 指向 editor 对象自身
var editor = this;
// 由于浏览器自身不支持 lineHeight 命令,因此要做一个hook
editor.commandHooks.lineHeight = function (value) {
var rangeElem = editor.getRangeElem();
var targetElem = editor.getSelfOrParentByName(rangeElem, 'p,h1,h2,h3,h4,h5,pre');
if (!targetElem) {
return;
}
$(targetElem).css('line-height', value + '');
};
// 创建 menu 对象
var menu = new E.Menu({
editor: editor, // 编辑器对象
id: menuId, // 菜单id
title: '行高', // 菜单标题
commandName: 'lineHeight', // 命令名称
// 正常状态和选中装下的dom对象,样式需要自定义
$domNormal: $('
'),
$domSelected: $('
')
});
// 数据源
var data = {
// 格式: 'value' : 'title'
'1.0': '1.0倍',
'1.5': '1.5倍',
'1.8': '1.8倍',
'2.0': '2.0倍',
'2.5': '2.5倍',
'3.0': '3.0倍'
};
// 为menu创建droplist对象
var tpl = '
{#title}';
menu.dropList = new E.DropList(editor, menu, {
data: data, // 传入数据源
tpl: tpl // 传入模板
});
// 增加到editor对象中
editor.menus[menuId] = menu;
});
})();
```
-----
####效果
运行页面的效果如下:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-05_56b460d9ba82a.png)
';
『缩进』菜单
最后更新于:2022-04-01 23:43:15
####前言
- 把扩展菜单的`js`文件写在一个独立的文件中,命名为`custom-menu.js`,这个文件最终要引用到页面中。
- **将要扩展的『缩进』菜单的id命名为 `indent`** 。菜单id不能已有的菜单的id重复,现有菜单的id,可参见『参数配置 - 自定义菜单』
-------
####页面
假设现在`custom-menu.js`已经编写完成(下文将描述该文件如何编写),要引用到页面中。而且页面中还有对`editor.config.menus`配置以显示刚刚扩展的菜单,详情可参见『参数配置 - 自定义菜单』。例如:
```html
```
----
####编写 `custom-menu.js`
可直接查看源代码,里面有详细的注释描述
```js
(function () {
// 获取 wangEditor 构造函数和 jquery
var E = window.wangEditor;
var $ = window.jQuery;
// 用 createMenu 方法创建菜单
E.createMenu(function (check) {
// 定义菜单id,不要和其他菜单id重复。编辑器自带的所有菜单id,可通过『参数配置-自定义菜单』一节查看
var menuId = 'indent';
// check将检查菜单配置(『参数配置-自定义菜单』一节描述)中是否该菜单id,如果没有,则忽略下面的代码。
if (!check(menuId)) {
return;
}
// this 指向 editor 对象自身
var editor = this;
// 创建 menu 对象
var menu = new E.Menu({
editor: editor, // 编辑器对象
id: menuId, // 菜单id
title: '缩进', // 菜单标题
// 正常状态和选中状态下的dom对象,样式需要自定义
$domNormal: $('
'),
$domSelected: $('
')
});
// 菜单正常状态下,点击将触发该事件
menu.clickEvent = function (e) {
// 找到当前选区所在的 p 元素
var elem = editor.getRangeElem();
var p = editor.getSelfOrParentByName(elem, 'p');
var $p;
if (!p) {
// 未找到 p 元素,则忽略
return e.preventDefault();
}
$p = $(p);
// 使用自定义命令
function commandFn() {
$p.css('text-indent', '2em');
}
editor.customCommand(e, commandFn);
};
// 菜单选中状态下,点击将触发该事件
menu.clickEventSelected = function (e) {
// 找到当前选区所在的 p 元素
var elem = editor.getRangeElem();
var p = editor.getSelfOrParentByName(elem, 'p');
var $p;
if (!p) {
// 未找到 p 元素,则忽略
return e.preventDefault();
}
$p = $(p);
// 使用自定义命令
function commandFn() {
$p.css('text-indent', '0');
}
editor.customCommand(e, commandFn);
};
// 根据当前选区,自定义更新菜单的选中状态或者正常状态
menu.updateSelectedEvent = function () {
// 获取当前选区所在的父元素
var elem = editor.getRangeElem();
var p = editor.getSelfOrParentByName(elem, 'p');
var $p;
var indent;
if (!p) {
// 未找到 p 元素,则标记为未处于选中状态
return false;
}
$p = $(p);
indent = $p.css('text-indent');
if (!indent || indent === '0px') {
// 得到的p,text-indent 属性是 0,则标记为未处于选中状态
return false;
}
// 找到 p 元素,并且 text-indent 不是 0,则标记为选中状态
return true;
};
// 增加到editor对象中
editor.menus[menuId] = menu;
});
})();
```
----
#### 最终效果
最终运行页面的效果如下:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-05_56b460d9ab2fc.png)
';
扩展一个菜单
最后更新于:2022-04-01 23:43:13
目前 wangEditor 编辑器的菜单有三种类型:
- 基本命令类型,例如『粗体』、『斜体』、『引用』
- dropList 类型,例如『字体』、『标题』
- dropPanel 类型,例如『插入链接』、『插入图片』、『地图』等
下面通过扩展『缩进』、『行高』、『插入符号』三个示例来演示如果扩展不同类型的菜单。
----
**扩展菜单过程中,会用到编辑器提供的API,也需要了解编辑器的对象结构。这些请参见『插件开发 - 对象结构』、『插件开发 - 常用API - 全局API』、『插件开发 - 常用API - 对象API』**
';
命令API
最后更新于:2022-04-01 23:43:11
####命令API
以下是编辑器命令操作相关的API,**使用以下API,最好先要了解浏览器的`document.execCommand`的相关知识**
-----
- **`editor.command`**
对`document.execCommand`执行浏览器基础命令的封装。在二次开发中,如果遇到这种情况,尽量用分装好的`edtior.command`。例如:
```js
$('#btn').click(function (e) {
// 注意,下面的 e 参数尽量要传,否则可能导致其他问题
// 等同于 document.execCommand('bold')
editor.command(e, 'bold');
// 等同于 document.exexCommand('BackColor', false, '#003399')
editor.command(e, 'BackColor', '#003399');
});
```
-----
- **`editor.commandForElem`**
针对当前选中的元素,向上查找,得到符合传入条件的父元素。然后把这个父元素当做选区,来执行命令。除了第一个参数之外,后面的参数和`editor.command`相同。例如:
```js
$('#btn').click(function (e) {
// 注意,下面的 e 参数尽量要传,否则可能导致其他问题
// 针对当前选区所处于的 b strong 元素,然后执行命令
editor.command('b,strong', e, 'bold');
// 为所处的整个 p 元素设置背景色
editor.command('p', e, 'BackColor', '#003399');
});
```
-----
- **`editor.customCommand`**
用于自定义的命令操作,而非`document.execCommand`提供的基础命令。
**注意,建议你对编辑内容的所有修改,都使用命令的方式。如果基础命令满足不了要求,一定要使用这里的自定义命令。不要忽略命令,自己写代码来修改。那样会出现各种问题!!!**如果觉得好奇,可以搜索源码中的`E.fn.customCommand`来看看,自定义命令中那些复杂的操作过程。
程序举例:
```js
$('#btn').click(function (e) {
// 注意,下面的 e 参数尽量要传,否则可能导致其他问题
editor.command(e, function () {
// 这里的 this 指向 editor 对象本身
var editor = this;
editor.$txt.append('
自定义命令追加的内容
');
});
});
```
-----
- **`editor.queryCommandValue`**
对`document.queryCommandValue`的封装,使用方法和`document.queryCommandValue`一样。分装中,规避了`IE8`异常错误。
-----
- **`editor.queryCommandState`**
对`document.queryCommandState`的封装,使用方法和`document.queryCommandState`一样。分装中,规避了`IE8`异常错误。
-----
- **`editor.queryCommandSupported`**
对`document.queryCommandSupported`的封装,使用方法和`document.queryCommandSupported`一样。分装中,规避了`IE8`异常错误。
----
- **`editor.commandHooks`**
当遇到浏览器的`document.execCommand`不支持的命令时,就需要自定义一个命令,放在`editor.commandHooks`中。例如,IE浏览器的`document.execCommand`不支持`insertHtml`命令,为了保证IE浏览器的可用性,就需要增加这样的hook
```js
editor.commandHooks.insertHtml = function (html) {
var $elem = $(html);
var rangeElem = editor.getRangeElem();
var targetElem;
targetElem = editor.getLegalTags(rangeElem);
if (!targetElem) {
return;
}
$(targetElem).after($elem);
};
```
';
选区API
最后更新于:2022-04-01 23:43:08
###选区API
以下是与选择区域有关的API,**下面有些API在IE8、9可能无效,但是不会报错**。
*使用下面的API,最好要了解一下`javascript`的`range`和`selection`的基础知识。如果要兼容IE8、9,还有了解IE8、9特有的`selection`和 `textRange`的知识。*
-----
- **`editor.currentRange`**
获取或者设置当前的选中区域,例如
```js
var range = editor.currentRange(); // 获取
editor.currentRange(range); // 设置
```
-----
- **`editor.collapseRange`**
折叠传入的选区,或者当前选区。例如:
```js
editor.collapseRange(); // 折叠当前选区,到结束位置
editor.collapseRange(range); // 折叠传入的选区,到结束位置
editor.collapseRange(null, 'start'); // 折叠当前选区,到开始位置
editor.collapseRange(range, 'start'); // 折叠传入的选区,到开始位置
```
-----
- **`editor.getRangeText`**
获取当前选区的文字内容,例如
```js
var rangeText = editor.getRangeText();
```
-----
- **`editor.getRangeElem`**
获取当前选区所在的容器元素,不会是`text node`,而是`elem node`。例如
```js
var elem = editor.getRangeElem();
```
-----
- **`editor.isRangeEmpty`**
判断当前选区有没有选中文字内容。**说明:如果鼠标拖拽选择了若干个文字,那就是有选中内容;如果鼠标点击了某个地方,为选中文字,只有光标闪烁,那就是无选中内容**
```js
if ( editor.isRangeEmpty() ) {
console.log('当前选区无选中内容');
}
```
-----
- **`editor.saveSelection`**
将传入的选区对象或者从浏览器捕获的选区,保存为编辑器的当前选区。
```js
editor.saveSelection(); // 捕获浏览器的选区,保存
editor.saveSelection(range); //将传入的选区对象,保存为当前选区
```
-----
- **`editor.restoreSelection`**
将编辑器的当前选区,或者传入的选区对象,恢复为浏览器能看得见的选择区域。
```js
editor.restoreSelection(); // 恢复当前选区为浏览器的选择区域
editor.restoreSelection(range); // 将传入的选区对象,恢复为浏览器的选择区域
```
-----
- **`editor.restoreSelectionByElem`**
将传入的`elem`元素,作为选区,恢复为浏览器的选择区域。
```js
// 获取编辑器的最后一个 p 元素
var $p = editor.$txt.find('p').last();
var p = $p.get(0);
if (!p) {
return;
}
editor.restoreSelectionByElem(p); // 回复选区至最后一个 p,折叠到结束位置结束位置
editor.restoreSelectionByElem(p, 'start'); // 回复选区至最后一个 p,折叠到结束位置开始位置
```
';