⚡仿制豆包输入框⚡ChatArea再度升级🚀

1,379 阅读6分钟

前言

大家好,随着 ChatArea 发布已经有一年多了,之前功能主要针对聊天IM的场景应用,复刻了很多钉钉和微信的交互功能,期间还和一些IM的开源作者对接更新功能,后期的版本迭代打算复刻的AI对话框交互功能

先来看看本期复刻的场景功能:豆包输入框标签下拉选择

screenshots.gif

点击 风格 按钮 => 出现下拉选择弹窗 => 选择对应选项将回填到输入框并生成一个 可选标签 同时该 可选标签也可以唤起选择弹窗并更改数据选项

封装思路

1.封装插件功能让其他开发者使用最好能脱离框架的限制,使其能同时适用于与过去现在乃至未来的主流开发框架,毕竟框架会随着时间迭代更新,思索之后作者开发技术选型采用的是原生JS开发,而不是在现有主流框架上去开发对应场景组件

2.能让输入框支持复杂的元素结构,明显这不是一个简单的 input标签或是textarea标签,作者使用的方式是利用元素的contenteditable属性使其可以编辑。顺便回顾一下你在业务场景中有使用过类似的场景: 他是一个输入框, 内容不是简单的纯文本,诶!这是不是有点像我们常用到的富文本编辑器,没错!目前市面上主流的富文本编辑器封装也是使用元素的contenteditable属性,当前也有一部分开发者使用canvas去封装富文本编辑器。

contenteditable

关于contenteditable属性开发的注意点有很多,本文重点概况一下实现思路

<!-- 使元素成为可编辑区域 -->
<p contenteditable="true"></p>

screenshots.gif 观察右侧dom结构,在我们输入或者删除内容的时候,p标签下的内容也随之动态的修改

这一次我们额外为p标签添加一些子元素span,再看看页面渲染情况
<p contenteditable="true">
    <span>元素1</span>
    <span>元素2</span>
</p>

screenshots.gif 这一次我们会发现,当我继续输入或者删除时,字符内容的变更都是处在当前光标节点的元素下变化,直至这个元素被删除导致光标节点切换到另一个元素下。

此时产生了一个问题,诶?明明我子元素没有开启contenteditable属性凭啥他的内容怎么也可以写入更改?子元素看起来“不可编辑”,但实际是父元素编辑区域的一部分(类似文本流中的普通文本),如果想让这个元素变成一个整体且其内容不可被修改需要手动设置其contenteditable属性

<p contenteditable="true">
    <span>元素1</span>
    <span contenteditable="false">元素2</span>
</p>

screenshots.gif 修改后的元素2,在我们输入文本内容后都不会追加至其元素内,当明确设置contenteditable属性为falsee,用户无法选中或修改其内容(即使通过父元素区域尝试选中也会被阻止),这样会使我们的光标节点再也无法处于元素2之中,差不多表现为一个不可交互的“孤岛”

再来一次,但是这一次我们明确每个子元素的作用
<p contenteditable="true">
    <!-- 定义type为:input 是输入元素, 提供用户在输入框内的文案输入 -->
    <span data-set-type="input">[]</span>
    <!-- 定义type为: tag 是 特殊展示标签元素,如表情包,@提及 提供用户在输入框内特殊操作形成的视图反馈 -->
    <span data-set-type="tag" contenteditable="false">@某某</span>
</p>

等等!如果直接这样渲染,我们在输入框最后输入是不是又会在p标签下追加输入,这不是我们想要的效果,我们需要每次输入时,保证用户输入的文本都在我们定义的type为input的元素内,所以我们需要追加一条输入元素

<p contenteditable="true">
    <span data-set-type="input">[]</span>
    <span data-set-type="tag" contenteditable="false">@某某</span>
    <span data-set-type="input">[]</span>
</p>

[]的占位作用是因为实际光标选取节点处理逻辑更为复杂, 你可以暂时把[]想象就是一个输入框,这方便我们后续的交互理解,最终页面呈现的情况就是[] @某某 [|], 这里我们把|代表着当前输入框光标

当我们在后置元素[|]内输入12的时:

效果:[] @某某 [12|]

接着点击退格一次

效果:[] @某某 [1|]

继续点击退格一次

效果:[] @某某 [|]

关键点:要是继续退格一次呢,此时后置[]内可是什么都没有了,所以我们要删除这个输入区域

预期效果:[] @某某 |

??,可光删除这个[]输入区域就完成了吗,我们可是在一个内容为空的输入区域内按下了退格键, 这在页面上的呈现效果是 只对着@某某按下了删除, 所以我们要连并删除并且把光标定向到上一个[]区域内

最终需要效果:[|]

思考一下上述的例子 其实输入元素特殊标签元素之间交互就是如何去切换,改造他们的展示结构,以下是两个常见的拆分合并示例

输入元素拆分例子:

当前:[] @某某 [12|34]

在当前光标插入了新的特殊标签元素@某某2

解析:这里我们需要将[12|34]输入元素 根据光标所在位置|拆分成两个输入元素[12][34],并在他们之间插入@某某2,最后将光标位置重新定向到[|34]

最终效果:[] @某某 [12] @某某2 [|34]

输入元素合并例子

当前:[12] @某某 [|34]

在当前光标处点击了退格删除键

解析:当前光标|前置内容 为 @某某 我们需要删除掉这个特殊标签元素,变为[12] [34] , 最后合并并将光标位置重新定向到前置元素的内容末尾[12|]

最终效果:[12|34]

根据以上例子,相信你对 contenteditable属性的交互有了大概的理解

即使里面还有很多复杂的操作 比如折行、合并行、复制、粘贴、撤销、恢复、重写等等,其实都是在整合输入元素特殊标签元素之间关系

如果日常中开发业务,之前没有对这块的梳理经验那开发精力将大部分浪费在这些光标 DOM之间的处理,因此作者封装了ChatArea目的就是为了让你宝贵的精力专注于业务层,而不是交互层

话题扯远了,ChatArea复刻的豆包输入框标签下拉选择

screenshots.gif

当前这还只是初版效果,详细的配置和使用方式在官网文档里都有提供,也欢迎大家多多提出意见,还是那句话 把交互层交给我业务层留给各位

最后再展示一些ChatArea其他功能点

支持@提及功能以及拼音匹配筛选功能

screenshots.gif

支持自定义触发标签

screenshots.gif

支持人员列表异步匹配

screenshots.gif

支持表情链接以及自定义html结构插入,并全都支持复制粘贴

screenshots.gif

更多特效点击访问官网文档