上一篇文章,我们通过一个富文本组件并为其自定义了 v-module,使其像表单元素一样支持双向数据绑定。但还有不小问题。比如输入回车换行,会在文本上包裹 html 标签。Chrome 中渲染为 div,IE中 渲染为 p,Firefox中 渲染为 br。当然这些附加的标签在浏览器中显示是 Ok 的,但有的终端是不支持 html 标签的,因此得转换它们。
代码实现
最先想到的是用正则表达式来替换,但不太好匹配,写起来很复杂,改了几版还是有问题。后来换了个思路终于搞定。
insertReturn (el) {
const range = document.createRange()
// 返回用户当前的选区
const sel = document.getSelection()
// 获取当前光标位置
const offset = sel.focusOffset
// div当前内容
const content = el.innerHTML
// 添加换行符
let separator = '\n'
// 光标在文本最后
if (offset === content.length) {
separator = '\n\r'
}
el.innerHTML = content.slice(0, offset) + separator + content.slice(offset)
// 设置光标为当前位置
range.setStart(el.childNodes[0], offset + 1)
// 使得选区(光标)开始与结束位置重叠
range.collapse(true)
// 移除现有其他的选区
sel.removeAllRanges()
// 加入光标的选区
sel.addRange(range)
},
handleKeyDown(event) {
event.preventDefault()
this.insertReturn(event.target)
}
分析
这里我们为可编辑div新增了 handleKeyDown
处理函数,使用 event.preventDefault()
取消了浏览器在文本回车换行的默认行为。用 insertReturn
方法来统一处理:使用回车换行来分割字符串,如果是在文本中间用 \r\n
,文本开头用 \n
就可以了。代码都有注释,就不细讲了。
参考
- 访问 codesandbox 查看完整实例代码及最终效果。
- 关于
range
可以参考我之前写的开发在线文本编辑器。
? Happy coding!
评论 (0)