富文本插入词条

基本业务点

  • 在富文本中插入词条
  • 可作为一个整体,需要整体插入并可可以整体删除
  • 可在指定文本光标处插入词条
  • 需要自动换行

这三个小点是不是看起来很简单,确实看起来相当的简单,但是实现起来却有点尴尬

基础知识点普及

  • 很多人一想到富文本编辑器,第一想法,这个不是我们能写的,其实他本质上也是 html和js写的,我曾有幸看过一眼 wangEditor的源代码,所以就没那么恐惧了
  • 在div 标签上加上 contentEditable 即可开启元素的编辑模式
  • span.style[‘-webkit-user-modify’] = ‘read-only’ 设置富文本内的标签为只读标签
  • tinymceinsertContent 方法,用于插入内容
  • tinymcesetContent 方法,用于直接设置内容,即直接覆盖整个富文本
  • 将富文本内的标签的contentEditable 设置为false,表示不可编辑

补充

  • span.style[‘-webkit-user-modify’] = ‘read-only’ 和 span.setAttribute("contentEditable", false); 的区别在于
    • 前者表示span元素的内容只读,但是不可删除,满足不了标签整体删除的功能
    • 后者表示span里的内容不可编辑,但是整体是可以删除的,可以满足标签整体删除的功能

基础实现方案 (有问题的方案)

  • 虽然方案是有问题的,但是也是一个探索的过程,收获良多

方案一 ,打底方案

效果

  • 基础实现
    • 实现了词条的插入
  • 缺陷
    • 换行有问题
    • 词条整体删除有问题

缺陷分析

  • 由代码可知,每次添加,都会往里面套一层div,这种嵌套的情况,无疑会导致换行
  • span.style['-webkit-user-modify'] = 'read-only' 设置了这个属性,故不能整体删除,不可取
onOpenChange(e, value, key) {
    console.log(e, value);
    if (this[value]) {
        if (!e) {
            const div = document.createElement("div")
            const span = document.createElement("span")
            div.style.display = 'inline-block'
            span.style.color = key === 0 ? "#3fbf70" : '#fbc628'
            span.style.pointerEvents = 'none';
            span.style['-webkit-user-modify'] = 'read-only'
            span.innerHTML = "{" + this[value] + "}"
            div.innerHTML = span.outerHTML
            let str = div.outerHTML
            tinymce.get('tinymce' + this.info.id).insertContent(str);
            this[value] = null
            this.btnChange(key)
        }
    }
}

方案二 优化方案

  • 使用flex布局调整布局方式,在富文本内层,子集span外层包一个div,再加flex属性

结果

  • 失败

缺陷

  • 无法删除 span 里的标签内容
  • 无法定位到光标,尝试方案
    • 给子元素加一个margin的间距(可能是没空间了)
      • 尝试失败
    • 将span的只读属性去除 span.style[‘-webkit-user-modify’] = ‘read-only’
      • 尝试失败
      • span去除了只读属性后,不能作为整体标签删除,会出现一个一个字符删除的情况,不符合需求
onOpenChange(e, value, key) {
  if (this[value]) {
    if (!e) {
      debugger
      const div = this.tmpEditorDom
      const span = document.createElement("span")
      div.style.display = 'flex'
      div.style.justifyContent = 'flexStart'
      div.style.flexWrap = 'wrap'
      span.style.color = key === 0 ? "#3fbf70" : '#fbc628'
      span.style.pointerEvents = 'none';
      span.style['-webkit-user-modify'] = 'read-only'
      span.innerHTML = "{" + this[value] + "}"
      div.appendChild(span)
      let str = div.outerHTML
      tinymce.get('tinymce' + this.info.id).setContent(str);
      this[value] = null
      this.btnChange(key)
    }
  }
}

方案三 理想方案

在插入的时候新的span节点的时候,获取到当前的光标,将当前标向后移动字符串 </div> 的长度,更新光标的位置,然后插入dom节点,以避免元素的嵌套

问题

  • 理想很丰满,现实很骨干,我查阅了文档,根本获取光标位置更新光标位置的方法没有这个方法,

结果

  • 失败

最终实现方案

  • 调用 span.setAttribute("contentEditable", false); 方法,即可实现,span元素里的内容不可编辑,但是整体是可以删除的,可以满足标签整体删除的功能
  • 并加上 span.style.margin = '0 3px' 给予光标插入的位置

结果

  • 完美解决
onOpenChange(e, value, key) {
    if (this[value]) {
    if (!e) {
        const span = document.createElement("span")
        span.style.color = key === 0 ? "#3fbf70" : '#fbc628'
        span.style.margin = '0 3px'
        span.setAttribute("contentEditable", false);
        span.innerHTML = "{" + this[value] + "}"
        let str = span.outerHTML
        tinymce.get('tinymce' + this.info.id).insertContent(str);
        this[value] = null
        this.btnChange(key)
    }
    }
    
}

感悟

  • 高端的代码,除了优秀的设计思想,还需要对底层api有足够的了解,否者等于0
  • 写代码的时候不遇到了自己不会的需求,需要去探索,并且这个探索过程还是极其有趣的
  • 虽然有些方案是错误的,但是这探索的过程会让我们学到更多的东西,并且距离真相越来越近,直至解决问题

致谢

  • 感谢项目组同事 韦剑大哥 给予我学习和探讨问题的机会,以及将最后的最优解和我分享
  • 10
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值