从零开始实现一个富文本编辑器

create on in library with 0 comment and 478 view

现在的开源富文本有很多,但最后还是想自己捣鼓一个,首先可以熟悉一个库的开发环境,其次可以熟练掌握富文本的实现原理。

what is it

什么是富文本编辑器?富文本编辑器即 Rich Text Editor, 简称 RTE, 是一种可内嵌于浏览器,所见即所得的文本编辑器,它提供类似于 Microsoft Word 的编辑功能。

核心原理

与input,textarea文本框不同的是,RTE采用 document 暴露的 execCommand 方法来实现的,该方法以命令为参数,这些命令可操纵可编辑内容区域的元素。
当某元素的contentEditable属性设为true时,该元素的内容则可编辑,然后调用 execCommand() 将影响其可编辑的内容,详情见execCommand文档

实现过程

构建开发环境

我主要采用以下技术来搭建:

  • node
  • gulp
  • rollup
  • babel

设计编辑器

  • UI界面

编辑器设计为两个部分,分别为
1). 工具栏
2). 编辑区

微信截图_20190214171901.png

  • 接口设计

导出一个全局对象 oct ,该对象拥有方法 exec, init。

exec:封装document.execCommand方法
init:传入相关配置(插入编辑器的元素,支持的工具项,事件等),实例化编辑器

示例:

oct.init({ ele: document.getElementById('editor'), tool: ['b','i','u'], onchange: function(){ console.log('editor is changing'); } });

功能实现

  • 设置默认样式
const defaultClasses = { actionbar: 'oct-actionbar', // 工具栏 button: 'oct-button', // 按钮 content: 'oct-content' // 可编辑区 }
  • 封装document.execCommand函数
export const exec = (command, value = null) => document.execCommand(command, false, value)
  • 定义actionbar对应的icon和命令
const actionbar = { 'b': { icon: `<b>B</b>`, // 图标 exec: () => exec('bold') // 执行的命令 }, 'i': { icon: `<i>I</i>`, exec: () => exec('italic') }, 'u': { icon: `<u>U</u>`, exec: () => exec('underline') }, 's': { icon: `<s>S</s>`, exec: () => exec('strikeThrough') }, 'h1': { icon: '<b>H<sub>1</sub></b>', exec: () => exec('formatBlock', '<h1>') }, 'h2': { icon: '<b>H<sub>2</sub></b>', exec: () => exec('formatBlock', '<h2>') } }

a. init函数

export const init = (arg) => { // 入参为一个对象
...
}

b. 构建可编辑区域

let content = document.createElement('div') content.classList.add(defaultClasses.content) content.contentEditable = true // 使其可编辑

c. 构建工具栏

// 构建工具栏 let tools = document.createElement('div'); tools.classList.add(defaultClasses.actionbar) // 没有传入数组对象,则默认使用全部工具按钮 if(!arg.tool || Object.prototype.toString.call(arg.tool).slice(-6,-1) !== 'Array') { arg.tool = Object.keys(actionbar); } arg.tool.forEach((type) => { let actionType = actionbar[type] if(actionType) { let button = document.createElement('button') button.classList.add(defaultClasses.button) button.innerHTML = actionType.icon button.onclick = () => actionType.exec() && content.focus() tools.appendChild(button); } })

d. 将工具栏和可编辑区插入到对应的元素中

arg.ele.classList.add('oct') arg.ele.appendChild(tools) arg.ele.appendChild(content)

e. export对象

export default { exec, init }

f. gulp打包

gulp build

使用

此时,在index.html中引用并执行init方法。

<!DOCTYPE html> <html lang="en"> <head> <title>Octane</title> <link rel="stylesheet" href="./dist/oct.css"> </head> <body> <div id="editor"></div> <script src="./dist/oct.js"></script> <script> oct.init({ele: document.getElementById('editor')}); </script> </body> </html>

浏览器打开,查看效果。

oct_first.gif

这样,一个超简单的编辑器就完成了!

详细代码见 github octane editor

😁😂😃😄😅😆😇😈😉😐😑😒😓😔😕😖😗😘😙😠😡😢😣😤😥😦😧😨😩😰😱😲😳😴😵😶😷😸😹🙀🙁🙂🙃🙄🙅🙆🙇🙈
🙂