UNPKG

s94-editor

Version:

富文本编辑器的基础模块

566 lines (387 loc) 20.1 kB
# **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) } } }); }) ```