基本业务点
- 在富文本中插入
词条
- 可作为一个整体,需要整体插入并可可以整体删除
- 可在指定文本光标处插入词条
- 需要自动换行
这三个小点是不是看起来很简单,确实看起来相当的简单,但是实现起来却有点尴尬
基础知识点普及
- 很多人一想到富文本编辑器,第一想法,这个不是我们能写的,其实他本质上也是 html和js写的,我曾有幸看过一眼 wangEditor的源代码,所以就没那么恐惧了
- 在div 标签上加上
contentEditable
即可开启元素的编辑模式 - span.style[‘
-webkit-user-modify
’] = ‘read-only’ 设置富文本内的标签为只读标签 tinymce
的insertContent
方法,用于插入内容tinymce
的setContent
方法,用于直接设置内容,即直接覆盖整个富文本- 将富文本内的
标签的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去除了只读属性后,不能作为整体标签删除,会出现一个一个字符删除的情况,不符合需求
- 给子元素加一个margin的间距(可能是没空间了)
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
- 写代码的时候不遇到了自己不会的需求,需要去探索,并且这个探索过程还是极其有趣的
- 虽然有些方案是错误的,但是这探索的过程会让我们学到更多的东西,并且距离真相越来越近,直至解决问题
致谢
- 感谢项目组同事 韦剑大哥 给予我学习和探讨问题的机会,以及将最后的最优解和我分享