近期在开发 AI 对话产品的时候为了晋升用户体验加强了对话输入框的相干能力,产品初期阶段对话框只是一个单行输入框,导致在文本内容很多的时候体验很不好,所以进行体验降级,相似还原了微信输入框的性能(只是其中的一点点哈🤏)。
初期认为这应该改变不大,就是把 input
换成 textarea
吧。然而理论开发过程发现并没有这么简略,本文仅作为开发过程的记录,因为是基于 uniapp
开发,相干实现代码都是基于uniapp
。
简略剖析咱们大略须要实现以下几个性能点:
- 默认单行输出
- 可多行输出,但有最大行数限度
- 超过限度行术后内容在外部滚动
- 反对回车发送内容
- 反对常见组合键在输入框内换行输出
- 多行输出时高度自适应 & 页面整体自适应
单行输出
默认单行输出比较简单间接应用 input
输入框即可,应用 textarea
的时候目前的实现形式是通过设置行内款式的高度管制,如咱们的行内高度是 36px
,那么就设置其高度为36px
。为什么要通过这种形式设置呢?因为要思考后续多行输出超出最大行数的限度,须要通过高度来管制textarea
的最大高度。
<textarea style="{height: 36px}" />
多行输出
多行输出外围要留神的就是管制元素的高度,因为不能随着用户的输出始终减少高度,咱们须要设置一个最大的行数限度,超出限度后就不再减少高度,内容能够持续输出,能够在输入框内高低滚动查看内容。
这里须要借助于 uniapp
内置在 textarea
的@linechange
事件,输入框行数变动时调用并回传高度和行数。如果不应用 uniapp
则须要对输出文字的长度及以后行高计算出对应的行数,这种状况还须要思考单行文本没有满一行且换行的状况。
代码如下,在 linechange
事件中获取到最新的高度设置为 textarea
的高度,当超出最大的行数限度后则不解决。
linechange(event) {const { height, lineCount} = event.detail
if (lineCount < maxLine) {this.textareaHeight = height}
}
这是失常的输出,还有一种状况是用户间接粘贴内容输出的场景,这种时候不会触发 @linechange
事件,须要手动解决,依据粘贴文本后的 textarea
的滚动高度进行计算出对应的行数,如超出限度行数则设置为最大高度,否则就设置为理论的行数所对应的高度。代码如下:
const paddingTop = parseInt(getComputedStyle(textarea).paddingTop);
const paddingBottom = parseInt(getComputedStyle(textarea).paddingBottom);
const textHeight = textarea.scrollHeight - paddingTop - paddingBottom;
const numberOfLines = Math.floor(textHeight / lineHeight);
if (numberOfLines > 1 && this.lineCount === 1) {
const lineCount = numberOfLines < maxLine ? numberOfLines : maxLine
this.textareaHeight = lineCount * lineHeight
}
键盘发送内容
失常咱们应用电脑聊天时发送内容都是应用回车键发送内容,应用 ctrl
,shift
,alt
等和回车键的组合键将输入框的文本进行换行解决。所以接下来要实现的就是对键盘事件的监听,基于事件进行发送内容和内容换行输出解决。
首先是事件的监听,uniapp
不反对 keydown
的事件监听,所以这里应用了原生 JS 做监听解决,为了防止反复监听,对每次开始监听前先进行移除事件的监听,代码如下:
this.$refs.textarea.$el.removeEventListener('keydown', this.textareaKeydownHandle)
this.$refs.textarea.$el.addEventListener('keydown', this.textareaKeydownHandle)
而后是对 textareaKeydownHandle
办法的实现,这里须要留神的是组合键对内容换行的解决,须要获取到以后光标的地位,应用 textarea.selectionStart
可获取,基于光标地位减少一个换行 \n
的输出即可实现换行,外围代码如下:
const cursorPosition = textarea.selectionStart;
if((e.keyCode == 13 && e.ctrlKey) ||
(e.keyCode == 13 && e.metaKey) ||
(e.keyCode == 13 && e.shiftKey) ||
(e.keyCode == 13 && e.altKey)
){
// 换行
this.content = `${this.content.substring(0, cursorPosition)}\n${this.content.substring(cursorPosition)}`
}else if(e.keyCode == 13){
// 发送
this.onSend();
e.preventDefault();}
高度自适应
当多行输出内容时输入框所占据的高度减少,导致页面理论内容区域的高度减小,如果不进行动静解决会导致理论内容会被遮挡。如下图所示,红色区域就是须要动静解决的高度。
次要须要解决的场景就是输出内容行数变动的时候和用户粘贴文本的时候,这两种状况都会基于以后的可视行数计算输入框的高度,那么内容区域的高度就好计算了,应用整个窗口的高度减去输入框的高度和其余固定的高度如导航高度和底部平安间隔高度即是实在内容的高度。
this.contentHeight = this.windowHeight - this.navBarHeight - this.fixedBottomHeight - this.textareaHeight;
最初
到此整个输入框的体验优化外围实现过程就完结了,减少了多行输出,组合键换行输出内容,键盘发送内容,整体内容高度自适应等。整体实现过程的细节性能点还是比拟多,有实现过相似需要的同学欢送留言交换~
看完本文如果感觉有用,记得点个赞反对,珍藏起来说不定哪天就用上啦~
专一前端开发,分享前端相干技术干货,公众号:南城大前端(ID: nanchengfe)