当前位置: 移动技术网 > IT编程>网页制作>HTML > 荐 手撸实现一个富文本编辑器

荐 手撸实现一个富文本编辑器

2020年07月11日  | 移动技术网IT编程  | 我要评论

 重点是弄懂以下几个知识点

contenteditable window.getSelection()Rangedocument.execCommand 

附上链接

Window/getSelection

Document.createRange()

document.execCommand()

 注意:document.execCommand 这个方法已经废弃,但是浏览器还是支持,只不过随时可能不支持

  • 实现方式 ES6 class类和jq

1、首先创建个html文件 做好准备工作

引入所需的jq文件

<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.js"></script>

body中富文本所需要渲染哪个div中

<div id="box"></div>

创建一个类 里面声明菜单配置以及生成dom结构的方法

class Editor {
    constructor(id) {
        this.id = id //渲染dom
        this.lastAddress = '' //焦点最后位置
        this.config = [ //菜单配置
            {
                title: 'B',
                name: 'bold'
            },
            {
                title: 'C',
                name: 'foreColor',
                list: [{
                        title: 'blue',
                        val: '#007ACC'
                    },
                    {
                        title: 'red',
                        val: '#E21918'
                    },
                    {
                        title: 'green',
                        val: '#1AA15F'
                    }
                ]
            },
            {
                title: 'H',
                name: 'FontSize',
                list: [{
                        title: 'H1',
                        val: '6'
                    },
                    {
                        title: 'H2',
                        val: '5'
                    },
                    {
                        title: 'H3',
                        val: '4'
                    },
                    {
                        title: 'H4',
                        val: '3'
                    },
                    {
                        title: 'H5',
                        val: '2'
                    },
                    {
                        title: 'H6',
                        val: '1'
                    }
                ]
            }
        ]
    }

    //创建编辑dom
    createDom() {
    }
}

new个事例调用createDom()方法

<script>
        let editor = new Editor('#box')
        editor.createDom()
</script>

2、createDom()的实现

判断一下是否传入渲染的dom的id

//检验是否传入dom
        if ($(this.id).length === 0) {
            console.log('未传入DOM')
            return;
        }

首先创建菜单和编辑的区域

 //创建菜单 和 编辑区域
        let div_top = $("<div id='div_top'></div>");
        let div_bottom = $("<div id='div_bottom'><div id='area' contenteditable></div></div>");
        $(this.id).append(div_top, div_bottom)

contenteditable 这个属性指定元素内容是否可编辑。 这个也是编辑的基础

接下来就是生成菜单了,jq的each方法遍历this.config

 //生成菜单
        $(this.config).each(function (i, n) {
            var menu = ''
            if (!n.list) {
                menu = `<div class='memu-l'><i class='memu-l-btn' name='${n.name}'>${n.title}</i></div>`
            } else {
                var str = ''
                if (n.name === 'foreColor') {
                    $(n.list).each(function (j, k) {
                        str = str + `<div class='memu-l-list' name='${n.name}' val='${k.val}' ><i class='memu-l-btn' name='${n.name}' val='${k.val}' style='color:${k.val}'>${k.title}</i></div>`
                    })
                } else if (n.name === 'FontSize') {
                    $(n.list).each(function (j, k) {
                        str = str + `<div class='memu-l-list'><${k.title}><i class='memu-l-btn' name='${n.name}' val='${k.val}'>${k.title}</i></${k.title}></div>`
                    })
                }
                menu = `<div class='memu-l'><i class='memu-l-btn' name='${n.name}'>${n.title}</i><div class="memu-l-btn_"> ${str}</div></div>`
                // console.log(i, menu)
            }
            $("#div_top").append(menu)
        })

最后我们来看看生成后的样子(css 就不看了) 

接下来就是实现相对应的功能了

1、封装好document.execCommand方法

  //编辑插入事件
    execCommand(type, bool, val = null) {
        document.execCommand(type, bool, val);
    }

2、然后就是给功能按钮添加点击事件

//功能
        $('.memu-l-btn').on('click', function (e) {
            //阻止默认事件
            e.preventDefault();
            //执行功能
            self.execCommand($(e.target).attr("name"), false, $(e.target).attr("val"))
})

比如加粗,当你点击的时候发现原本编辑区域有焦点的,结果一点击焦点消失了

这样自热也就没有加粗了,

这时候会想到该如何去处理焦点的保存和恢复 这个时候就要用到  window.getSelection()Range 

3、封装保存焦点的方法

在编辑区域具有焦点的时候,点击粗体按钮的时候  getSelection().getRangeAt(0)获取焦点的位置然后保存起来

// 保存当前焦点位置
    saveRangeAddress() {
        const self = this
        // 获取selection对象 保存焦点
        const selection = window.getSelection ? window.getSelection() : document.getSelection()
        self.lastAddress = selection.getRangeAt(0)
        console.log('保存******', self.lastAddress)
    }

4、封装设置焦点的方法

先判断存在是否getSelection,不存在的话就直接让编辑区域得到焦点,存在的话判断是否有焦点的最后位置,有的话selection.removeAllRanges()清除所有焦点在addRange恢复最后一个焦点位置,如果不存在使用 document.createRange 方法让焦点恢复到最后一个子节点的位置,在保存当时焦点的位置便于下次使用

// 设置焦点最后所处位置
    setRangeAddress() {
        const self = this
        //清除焦点 还原最后焦点的位置
        const selection = window.getSelection ? window.getSelection() : document.getSelection()
        //防止直接点击功能按钮没有焦点
        $('#area').focus()
         //判断是否具有getSelection对象
        if (selection) {
            // 判断是否有焦点最后位置
            if (self.lastAddress) {
                //存在最后焦点位置 回到原来的位置
                selection.removeAllRanges()
                selection.addRange(self.lastAddress)
            } else {
                // 如果之前没有保存焦点则新建一个
                const content = $('#area')[0]
                const range = document.createRange()
                range.setStart(content, 0)
                range.setEnd(content, 0)
                selection.addRange(range)
                self.lastAddress = range
            }
        } else {
            $('#area').focus()
        }
    }

5、在回到第二步 改进一下方法

添加了保存焦点位置,和设置焦点位置

保存位置一定要在执行了事件之后保存才不会导致焦点变化

  //功能
        $('.memu-l-btn').on('click', function (e) {
            //阻止默认事件
            e.preventDefault();
            //设置最后焦点位置
            self.setRangeAddress()
            //执行功能
            self.execCommand($(e.target).attr("name"), false, $(e.target).attr("val"))
            //发生改变后在执行一次保存焦点
            // console.log('memu-l-btn 保存')
            self.saveRangeAddress()
        })

看看效果吧

6、不关功能按钮需要点击的时候保存,手动调整调整和键盘事件也需要添加保存焦点事件

点击保存

//点击 记录焦点最后的位置
        $('#area').on('click', function () {
            const selection = window.getSelection ? window.getSelection() : document.getSelection()
            if (selection) {
                // console.log('click 保存')
                self.saveRangeAddress()
            }
        })

键盘点击保存

//按键 插入dom 记录焦点最后的位置
        $('#area').on('keyup', function (e) {
            self.saveRangeAddress()
        })

7、输出代码和渲染代码


    //输出代码
    exportHtml() {
        return $('#area').html()
    }

    //渲染
    visibleHtml() {
        console.log(this.exportHtml())
        $('#visible').html(this.exportHtml())
    }

 

初次接触富文本这个东西,写的不好,还请各位大佬勿怪

本文地址:https://blog.csdn.net/qq_39235055/article/details/107229315

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网