s94-editor
Version:
富文本编辑器的基础模块
566 lines (387 loc) • 20.1 kB
Markdown
# **s94-editor**
> 富文本编辑器的基础模块,提供富文本编辑器的基础功能,界面高度自由化
## **安装**
```
$ npm install s94-editor
```
## **使用**
```js
var Editor = require('s94-editor');
var editor = new Editor(document.querySelector('.editor-outer'));
```
# **属性和方法**
[new Editor(textarea[, config])](#Editor) 构造函数,构建编辑器
[range](#range) 编辑器当前的选区返回
[container](#container) 编辑器的容器
[textarea](#textarea) 编辑器的textarea,里面承载了编辑器对应的html代码
[config](#config) 配置参数
[menu](#menu) 菜单实例对象
[belongNode(dom[, test])](#belongNode) 向上遍历获取符合条件的节点
[setRange([range])](#setRange) 设定的选择范围
[updateRange([range])](#updateRange) 更新选择范围
[updateValue()](#updateValue) 更新textarea的值
[updateHtml()](#updateHtml) 更新编辑器的html内容
[execCommand(name[, data])](#execCommand) 执行编辑命令
[alignType()](#alignType) 文本布局类型
[isbold()](#isbold) 是否加粗
[isstrike()](#isstrike) 是否删除线
[isitalic()](#isitalic) 是否斜体
[isunderline()](#isunderline) 是否下划线
[rangePath()](#rangePath) 路径节点列表
[lastRow()](#lastRow) 设定最后一行空白节点
[encode_tag(html)](#encode_tag) 编码html中的特殊标签(form,script)
[decode_tag(html)](#decode_tag) 解码encode_tag方法编译过的html
[html()](#html) 当前编辑器的html代码
[配置参数](#configEditor)
# **菜单组件属性和方法**
[new Editor.Menu(editor[, config])](#EditorMenu) 内置的菜单构造函数
[Menu.menuList](#Menu_menuList) 所有注册的菜单
[Editor.Menu.add(name, title, innerHTML, onclick)](#Menu_add) 注册菜单
[container](#menu_container) 菜单的容器
[editor](#menu_editor) 菜单对应的编辑器
[list](#menu_list) 生成的菜单节点对象的键值对象
[add(name, title, innerHTML, onclick)](#menu_add) 添加菜单
[showSelect(list[, options])](#menu_showSelect) 显示自带的列表类型子菜单
[showForm(list[, options])](#menu_showForm) 显示自带的表单类型子菜单
<p id="Editor"></p>
## **new Editor(textarea[, config])**
- textarea `Node` 构建编辑器容器的样本,必须为textarea元素
- config `Object` 配置数据,查看[详细介绍](#configEditor)
- 返回 `Editor` 编辑器对象
>以textarea为样本,复制textarea的所有attr来窗初编辑器的容器,同时也是用来承载编辑器对应的html代码的容器
```js
var Editor = require('s94-editor');
var editor = new Editor(document.querySelector('.editor-outer'));
```
<p id="range"></p>
## **range**
- 属性 `Range` 选择范围,查看<a href="https://developer.mozilla.org/zh-CN/docs/Web/API/Range" target="_blank">详细介绍</a>
>获取编辑器当前的选区返回
<p id="container"></p>
## **container**
- 属性 `Node` 编辑器的容器
>获取编辑器当前所在的容器
<p id="textarea"></p>
## **textarea**
- 属性 `Node` textarea
>获取编辑器构建的样本textarea元素,编辑器对应的html代码会不间断的赋值到该元素的value属性上。
>但是不能完全保证该元素的value等同于`editor.html()`(例如当使用js改变了编辑器容器内的html后,没有调用`updateValue`方法的时候)。所有获取编辑器内容的html依然建议调用`editor.html()`方法
<p id="config"></p>
## **config**
- 属性 `Object` 配置参数
>获取编辑器当前配置参数,该对象的值是构造函数传入的`config`和默认的配置参数合并后的结果
<p id="menu"></p>
## **menu**
- 属性 `Editor.Menu|config.Menu` 菜单实例对象
>编辑器的菜单实例对象
<p id="belongNode"></p>
## **belongNode(dom[, test])**
- dom `Node` 开始节点
- test `Function` 判断方法,方法的`this`为当前判断的节点对象,方法返回true表示当前节点符合条件,默认`this.nodeType===1`为判断条件
- 返回 `Node|False` 符合条件的节点,如果直到容器节点也没用符合的,返回false
>向上遍历获取符合条件的节点
```js
console.log(editor.belongNode(editor.range.startContainer)); //打印当前编辑的节点
```
<p id="setRange"></p>
## **setRange([range])**
- range `Range` 选择范围对象,查看<a href="https://developer.mozilla.org/zh-CN/docs/Web/API/Range" target="_blank">详细介绍</a>。默认为当前`Editor`的range
- 返回 `Editor` 编辑器对象
>设定浏览器的选择范围,有获取锚地的效果。
```js
editor.setRange();
```
<p id="updateRange"></p>
## **updateRange([range])**
- range `Range` 选择范围对象,查看<a href="https://developer.mozilla.org/zh-CN/docs/Web/API/Range" target="_blank">详细介绍</a>。默认为浏览器的选择范围
- 返回 `Editor` 编辑器对象
>更新当前`Editor`的range,该方法组件会在必要的时候自动调用
>该方法调用后,会在`editor.container`上广播`update:range`事件,事件对象的range属性可以获取当前`Editor`的range
```js
editor.updateRange();
```
<p id="updateValue"></p>
## **updateValue()**
- 返回 `Editor` 编辑器对象
>更新textarea的value属性,该方法组件会在必要的时候自动调用,一般用于用户自定义菜单功能时,如果该功能对内容有变化的时候调用该方法,同步textarea中的值
>该方法调用后,会在`editor.container`上广播`update:value`事件,事件对象的value属性可以获取编辑器对应的html
```js
editor.updateValue();
```
<p id="updateHtml"></p>
## **updateHtml()**
- 返回 `Editor` 编辑器对象
>更新编辑器的html内容,该方法根据textarea的value重新渲染编辑器容器的html内容。
```js
editor.updateHtml();
```
<p id="execCommand"></p>
## **execCommand(name[, data])**
- name `String` 执行命令名称。等同于`document.execCommand`的第1个参数
- quality `mixed` 执行附带参数,默认为null。等同于`document.execCommand`的第3个参数,部分优化的不同
- 返回 `Editor` 编辑器对象
>在当前编辑位置,执行编辑命令。查看<a href="https://developer.mozilla.org/zh-CN/docs/Web/API/Document/execCommand" target="_blank">详细介绍</a>,对`document.execCommand`做了部分优化见代码示例
```js
//createLink
editor.execCommand("createLink", "http://s94.top"); //插入 <a href="http://s94.top">http://s94.top</a>
editor.execCommand("createLink", {
text: "牧人与鱼",
href: "http://s94.top"
}); //插入 <a href="http://s94.top">牧人与鱼</a>
//foreColor、hiliteColor、bold、strikeThrough、italic、underline
editor.execCommand("bold", true); //data为true表示当选区为一个点时,在当前位置插入不占位的空白字符,方便判断当前节点是否为加粗
```
<p id="alignType"></p>
## **alignType()**
- 返回 `String` 文本布局类型,left|center|full|right
>返回当前选区的文本布局类型,是对节点的`text-align`样式结果的统一化
```js
console.log(editor.alignType()); //left
```
<p id="isbold"></p>
## **isbold()**
- 返回 `Boolean` 是否加粗
>返回当前选区的节点文本样式是否为 **加粗**
```js
console.log(editor.isbold()); //false
```
<p id="isstrike"></p>
## **isstrike()**
- 返回 `Boolean` 是否加粗
>返回当前选区的节点文本样式是否为 **删除线**
```js
console.log(editor.isstrike()); //false
```
<p id="isitalic"></p>
## **isitalic()**
- 返回 `Boolean` 是否加粗
>返回当前选区的节点文本样式是否为 **斜体**
```js
console.log(editor.isitalic()); //false
```
<p id="isunderline"></p>
## **isunderline()**
- 返回 `Boolean` 是否加粗
>返回当前选区的节点文本样式是否为 **下划线**
```js
console.log(editor.isunderline()); //false
```
<p id="rangePath"></p>
## **rangePath()**
- 返回 `Array` 路径节点列表,
>返回当前选区的节点路径节点列表,
```js
var nodeNamePath=[];
editor.rangePath().forEach(function(row){
nodeTypePath.push(row.nodeName);
})
console.log(nodeNamePath.join(">")); //div>p>span
```
<p id="lastRow"></p>
## **lastRow()**
- 返回 `Node` 最后一行的节点对象
>检测最后一行是否为空的P标签,如果不是,添加一个空的没用样式的P标签。并返回。该方法主要用于在执行编辑内容的样式修改后,很多情况下换行后会把之前的样式带上,所以需要调用该方法获取一行没有被污染的P标签
```js
editor.lastRow();
```
<p id="encode_tag"></p>
## **encode_tag(html)**
- 返回 `String` 编码后的html代码
>编码html中的特殊标签(form,script)。
>编码script的目的:防止编辑的html代码里面的js代码污染
>编码form的目的:当编辑器放在form表单里面的时候,如果编辑器里面存在form标签的内容,浏览器会移除form标签,造成内容丢失
```js
console.log(editor.encode_tag('<form action=""></form><script></script>')); //<form-editor-change-tagname action=""></form-editor-change-tagname><script-editor-change-tagname></script-editor-change-tagname>
```
<p id="decode_tag"></p>
## **decode_tag(html)**
- 返回 `String` 解码后的html代码
>解码`encode_tag`方法编码后的html字符串
```js
var coed = editor.encode_tag('<form action=""></form><script></script>');
var html = editor.decode_tag(code);
console.log(html); //<form action=""></form><script></script>
```
<p id="html"></p>
## **html()**
- 返回 `String` 编辑器的html代码
>返回当前编辑器的html代码。在`this.container.innerHTML`的基础上执行了`decode_tag`和剔除了`lastRow`方法加入的空白P标签
```js
console.log(editor.html()); //.......
```
<p id="configEditor"></p>
## **配置参数**
- colors `Array` 使用内置菜单时,设定菜单的字体颜色和背景颜色集合
- fontsizes `Array` 使用内置菜单时,设定菜单的字体大小集合,长度最大为7
- image_callback `Function` 使用内置菜单-图片时,此参数表示点击此菜单后的处理,确认好图片地址后,可以通过直接返回,或者执行函数接受一个参数`next`然后传入图片地址,具体参考<a href="https://www.npmjs.com/package/s94-js" target="_blank">s94-js</a>的new s94.Ready(f)
- menus `Array` 使用内置菜单时,设定显示的菜单列表,同时具备排序效果。
- onpaste `Function` 粘贴内容处理,接收`s94.fn`对象(类似jQuery对象),要求返回节点集
- Menu `Function` 自定义菜单构造函数,如果传入将替换组件自带的菜单,传入当前`Editor`编辑器对象
>除了这些字段,开发者也可以根据自己扩展的功能,自定义配置参数字段,然后可以在`editor.config`和`editor.menu.config`里面去获取。
```js
var Editor = require('s94-editor');
var editor = new Editor(document.querySelector('.editor-outer'), {
colors: ['#333','rgb(194, 250, 94)'], //自定义组件菜单的字体颜色和背景颜色列表
fontsizes: ['12px','0.2rem'], //自定义字体大小列表,最多7个
menus: ['bold','color'],
onpaste: function(list){
list.forEach(function(row){
list.find('img').css("width", "100%"); //设定粘贴的图片样式
return list;
})
},
Menu: function(editor){
var dom = document.createElement('button');
dom.innerHTML = '菜单示例';
$(editor.container).after(dom);
dom.addEventListener('click', function(){
var html = `<h1>这是插入的标题</h1>`;
editor.execCommand('insertHTML', html);
editor.range = document.createRange();
var lastNode = editor.lastRow();
editor.range.setStart(lastNode, 0);
editor.range.setEnd(lastNode, 0);
editor.setRange();
})
}
});
```
<p id="EditorMenu"></p>
## **new Editor.Menu(editor[, config])**
- editor `Editor` 编辑器对象
- config `Object` 配置数据,类似`Editor`构造函数的`config`参数
- 返回 `Editor.Menu` 菜单实例对象
>内置的菜单,一般不用不需要调用,当没有在`Editor`构造函数的`config`参数设定`Menu`的情况下,会自动调用,返回结果赋值到`editor.menu`
```js
var menu = new Editor.Menu(editor);
```
<p id="Menu_menuList"></p>
## **Editor.Menu.menuList**
- 属性 `Object` 全局的菜单列表
>里面包含所有注册的菜单,主要用于查看已有的菜单或者修改某个菜单。如果需要自定义菜单建议调用`Editor.Menu.add(name, title, innerHTML, onclick)`方法
```js
var Editor = require('s94-editor');
Editor.Menu.menuList['bold']['onclick'] = function(menu){
alert("这是修改后的加粗菜单功能")
}
//全局菜单的操作需要在Editor实例化之前调用
var editor = new Editor(document.querySelector('.editor-outer'));
```
<p id="Menu_add"></p>
## **Editor.Menu.add(name, title, innerHTML, onclick)**
- name `String` 组件名称,作为`Menu.menuList`和`menu.list`里面存储的key
- title `String` 鼠标放上去显示的提示信息
- innerHTML `String` 组件菜单html
- onclick `Function` 组件菜单onclick事件回调函数,函数接收的第一个参数不是event,而是menu;this不变,为当前菜单节点对象
- 返回 `Editor.Menu.menuList` 所有注册的菜单键值对象
>该方法用于注册菜单,一般用于全局自定义菜单,示例如下:
```js
var Editor = require('s94-editor');
Editor.Menu.add("test", "测试菜单", '<p style="font-size: 0.6em;">测试</p>', function(menu){
var editor = menu.editor;
var html = `<h1>这是插入的标题</h1>`;
editor.execCommand('insertHTML', html);
editor.range = document.createRange();
var lastNode = editor.lastRow();
editor.range.setStart(lastNode, 0);
editor.range.setEnd(lastNode, 0);
editor.setRange();
})
//全局菜单的操作需要在Editor实例化之前调用
var editor = new Editor(document.querySelector('.editor-outer'));
```
<p id="menu_container"></p>
## **container**
- 属性 `Node` 菜单的容器
>获取菜单的容器,一把用于自定义菜单位置。菜单的默认位置在编辑器容器的前方,可以使用`appendChild`方法自定义菜单位置
```js
var Editor = require('s94-editor');
var editor = new Editor(document.querySelector('.editor-outer'));
document.querySelector('#editor-menu').appendChild(editor.menu.container); //把菜单放到#editor-menu里面去
```
<p id="menu_editor"></p>
## **editor**
- 属性 `Editor` 当前菜单对应的编辑器的实例
>获取当前的编辑器示例,一般用于自定义菜单里面方便调用`editor`的方法,查看[详细介绍](#Editor)
<p id="menu_list"></p>
## **list**
- 属性 `Object` 生成的菜单节点对象键值对象,key为菜单的`name`,{name: `Node`}
>菜单在实例化后,会根据`config.menus`和全局注册的菜单来生成菜单,并把生成的菜单节点对象存储在`menu.list`方便调用
<p id="menu_add"></p>
## **add(name, title, innerHTML, onclick)**
- name `String` 组件名称,作为`menu.list`里面存储的key
- title `String` 鼠标放上去显示的提示信息
- innerHTML `String` 组件菜单html
- onclick `Function` 组件菜单onclick事件回调函数,函数接收的第一个参数不是event,而是menu;this不变,为当前菜单节点对象
- 返回 `Object` 所有生成的菜单键值对象`menu.list`
>添加菜单,`Menu`在实例化的时候,会遍历[全局菜单列表](#Menu_menuList)执行此方法挨个添加菜单。同时,在实例化后,依然可以调用此方法,用于局部添加菜单,不过这样添加的菜单,不能排序,只能添加到末尾。如果需要排序,同时也不希望每个编辑器都有该菜单,请全局注册后,用`config.menus`实现
```js
var Editor = require('s94-editor');
var editor = new Editor(document.querySelector('.editor-outer'));
editor.menu.add('test2','测试2','测试',function(menu){
alert("测试2")
})
```
<p id="menu_showSelect"></p>
## **showSelect(list[, options])**
- list `Array` 菜单配置列表,[{innerHTML:`String`, onclick:`Function`}],参数说明,类似[menu.add](#menu_add)方法
- options `Object` 菜单配置,{type:`String`, className:`String`, close:`Function`}
- type `String` 列表布局类型,`droplist`下拉菜单样式,`pointlist`点阵样式。默认为droplist
- className `String` 自定义容器className,方便自定义样式
- close `Function` 菜单关闭时的回调方法,方法this为子菜单节点对象
- 返回 `underfind`
>显示自带的列表类型子菜单,组件自带的heading、size、align、color、bgcolor都使用了该子菜单,开发者可以在自定义菜单时使用
```js
var Editor = require('s94-editor');
var editor = new Editor(document.querySelector('.editor-outer'));
editor.menu.add('test2','测试2','测试',function(menu){
menu.showSelect([
{innerHTML: 'H1', onclick: function(menu){menu.editor.execCommand('formatBlock','h1')}},
{innerHTML: 'H2', onclick: function(menu){menu.editor.execCommand('formatBlock','h2')}},
])
})
```
<p id="menu_showForm"></p>
## **showForm(list[, options])**
- list `Array` 菜单配置列表,[{type:`String`, name:`String`, label:`String`, value:`String`, list:`Array`, }],参数说明:
- type `String` 表单组件类型,可选值:textarea | select | text ,默认为text
- name `String` 表单组件的name,必须,在提交后,作为获取数据的键值
- label `String` 表单组件的提示信息
- value `String` 表单组件默认初始值
- list `Array` 此字段为`select`组件特有,表示下拉的option列表,格式{html:`String`, value:`String`}
- options `Object` 菜单配置,{title:`String`, className:`String`, ok:`Function`, close:`Function`}
- title `String` 表单的标题
- className `String` 自定义容器className,方便自定义样式
- ok `Function` 菜单点击`确定`后提交的方法,接收一个键值对对象,里面包含表单的数据,方法this为子菜单节点对象
- close `Function` 菜单关闭时的回调方法,方法this为子菜单节点对象
- 返回 `underfind`
>显示自带的表单类型子菜单,组件自带的style、code都使用了该子菜单,开发者可以在自定义菜单时使用
```js
var Editor = require('s94-editor');
var editor = new Editor(document.querySelector('.editor-outer'));
editor.menu.add('test2','测试2','测试',function(menu){
menu.showForm([
{name: "type", label: "操作", type: "select", value: 0, list: [
{html:"下载图片", value: 1},
{html:"直接插入图片", value: 0}
]},
{name: "src", label: "图片地址"},
], {
title: '添加图片',
ok: function(data){
if(!data.src) return;
if(data.type==0){
menu.editor.execCommand('insertImage', data.src);
}else{
//记录当前编辑位置
var range = menu.editor.range;
// TODO 此处请求服务器,下载图片,然后返回自己服务器保存地址,再插入图片。由于请求服务器一般异步操作,此处用setTimeout代替效果
setTimeout(function(){
menu.editor.setRange(range);
menu.editor.execCommand('insertImage', data.src);
},5000)
}
}
});
})
```