web富文本编辑器实现思路

3,036 阅读3分钟

富文本编辑器其实是一个非常有意思的课题,真要深入进去会有很多有意思的东西,也会碰到很多问题,曾经在知乎上看到一个很有意思的话题 《为什么都说富文本编辑器是天坑?》,在这个话题里有很多很具参考性的回答,有兴趣的小伙伴可以去看看。在这里我只提供一个思路,具体的还需要参考更多的资料去实现~

准备阶段

如何在web端实现一个富文本编辑器,会有几个实现方式。而比较方便且能基本满足一般需求的方案是,利用html5的contentEditable属性,再配合上js的document.execCommand()和execCommand相关的一些判断方法。于是我尝试使用这个方案写了一个简单的富文本编辑器,这个编辑器实现了三个功能,加粗、设置标题和设置颜色。先上图让大家有个大致的印象: 在实现功能之前我们先要了解document.execCommand、document.queryCommandValue、document.queryCommandState这三个方法。具体如何使用就不在这里赘述了,具体的用法可以通过下面链接查阅: www.cnblogs.com/tugenhua070… 了解这些知识后,我们就可以开始实现功能了,如何实现这三个功能呢,这里有个大前提,包裹的标签需要添加contentEditable属性。

<p contenteditable="true">
请编辑内容…
</p>

加粗

设置了contenteditable之后,就可以用document.execCommand来实现上面所说的三个功能了。实现加粗功能比较简单,直接使用execCommand中的bold命令即可。

document.execCommand("bold", false, null)

设置标题

实现标题功能,就没这么简单了,需要先用document.queryCommandValue做一些判断,来保证功能能够正常使用。

if (document.queryCommandValue('formatBlock')!=="div"&&document.queryCommandValue('formatBlock')!=="") {
        document.execCommand("formatBlock", false, "div")
    } else {
        document.execCommand("formatBlock", false, "H1")
    }

设置颜色

设置颜色这里直接使用<input type=“color” />,设置颜色也比较简单

document.execCommand("foreColor", false,e.target.value)
// e.target.value是input中获取的色值

一些需要优化的地方

到了这里你也许会觉的编辑器就完成了,但其实还是有需要几个需要优化的地方

  1. 不能存储选区(一旦点击非输入框区域,之前的选区就会消失不能恢复)
  2. 不能判断命令的状态(无法完成功能按钮的交互状态)

存储选区

如何存储选区呢,这里就要提到Selection对象了

Selection 对象表示用户选择的文本范围或插入符号的当前位置。

这里具体思路是存储最近一次的选区,然后在需要的时候进行恢复。需要特别提到的是Select对象的范围会被作为Range对象返回,具体实现代码如下:

tip: 需要设置一个全局变量来保存Range

// golbal.js
let Global = {
   	range: null
}
// selection.js
// 构建一个操作选区的类
class selection {
    constructor() {
    }

	// 存储选区
    static saveSelection() {
        let range = window.getSelection().getRangeAt(0)
        Global.range = range
    }
    // 恢复选区
    static recoverSelection() {
        let selection = window.getSelection()
        selection.removeAllRanges()
        selection.addRange(Global.range)
    }
}

然后在输入框设置存储选区功能

// 这里设定element为输入框对象
element['onmouseup'] = function(e) {
        selection.saveSelection()
    }

每次使用命令之前使用select.recoverSelection()方法就能解决问题了,这里拿加粗功能部分举例

// 恢复选区
select.recoverSelection()
document.execCommand("bold", false, null)

命令状态的判断

还有一个问题就是如何判断命令的状态,在这里就要使用到document.queryCommandValue和document.queryCommandState了。这里还得用上全局变量,用来保存命令的状态。

let Global = {
	range: null,
    bold: false,
    head: false
}

然后就是使用document.queryCommandValue、document.queryCommandState来检查命令的状态。

// bold命令判断	
Global.bold = document.queryCommandState('bold')
// head命令判断
if(document.queryCommandValue('formatBlock')!=="div"&&document.queryCommandValue('formatBlock')!=="") {
            Global.head = true
        } else {
            Global.head = false
        }

到了这里,这个编辑器的功能是基本实现了,具体实现可以参考我的github,地址:github.com/hahaaha/Ric…

参考内容