简介
本文是基于 VUE3+TS
的代码说明。
记录自己遇到的 div 与 textarea 输入框交互的聚焦、失去焦点、键盘收起、表情插入不失去焦点的需求实现。
需求分析
1.固定在页面底部;
2.默认显示纯文字与发送图标按钮,文字超出的省略显示;
3.点击文字后,显示文本输入框、表情、半透明遮罩层,自动聚焦;
4.有输入内容时,文本输入框右侧显示发送按钮;
5.点击表情,将表情加入到输入框最后,并且输入法键盘不收起;
6.输入框失去焦点、点击键盘上的收起或完成时,隐藏文本输入框和表情,显示默认的纯文字样式。
注意
------以下代码是伪代码------
1.输入框聚焦后,可能存在输入框位置不正确的问题
如输入框被遮挡、输入框没有挨着键盘等类似的问题。
这些问题在网上的解决方案较多,可自行查阅。
我的处理思路如下:
// html
<Teleport to="#inputPosition">
<div v-show="isTextareaFocus" class="textarea-box">
<!-- 输入框与发送按钮 -->
<div>
<textarea ref="textareaRef" />
<button>发送</button>
</div>
<!-- 表情 -->
<div>
<div v-for="(emoji, index) in emojiList" :key="index">{
{
emoji }}</div>
</div>
</div>
</Teleport>
点击文本div时,显示文本输入框,并且自动聚焦
<script setup lang="ts">
import {
ref, nextTick } from 'vue'
const isTextareaFocus = ref(false) // 文本输入框是否聚焦(即显示)
const textareaRef = ref() // 输入框对应的DOM
const emojiList = ['👍', '😀', '😮', '🥰', '😡', '🤣', '😤', '🙏'] // '🫡', '🫰🏻'
/** 方法:输入框文本-是否聚焦、显示 */
const displayTextarea = (display = false) => {
isTextareaFocus.value = display
}
/** 操作:点击文本div */
const handleToFocus = () => {
displayTextarea(true)
nextTick(() => {
textareaRef.value?.focus() // 聚焦
// 部分ios上添加表情后,光标不在最后位置的问题处理
const length = message.value.length
textareaRef.value?.setSelectionRange(length, length)
})
}
</script>
2.键盘按钮的收起,判断输入框是否失去焦点:
1)Android
上,键盘按钮的收起,大部分不会触发输入框的blur事件,会触发webview的改变;
2)IOS
上,键盘按钮的收起,会触发输入框的blur事件,大部分不会触发webview的改变;
3)点击表情时,也会导致输入框失去焦点。
我的处理思路如下:
1)默认都有的处理逻辑
/** 进行手势操作时的过滤处理:如点击、滑动等 */
const touchStartEvent = (e: Event) => {
const target = e.target as HTMLElement
// 这里包含textareaBtn,是为了发送按钮的点击事件能正常触发
if (target.id === 'emoji' || target.id === 'textareaBtn') {
isNeedFocus.value = true
} else {
isNeedFocus.value = false
}
}
2)ios的特殊处理逻辑
if (val) {
// 键盘弹起
const focusEl = textareaRef.value
if (focusEl) {
focusEl.scrollIntoView({
block: 'center' })
}
} else {
// 键盘收起
clickBlur()
}
3.表情的插入
给整个列表、文本输入框盒子
添加touchstart
事件,最先执行的是touchstart
,根据当前touch事件的触发dom的id,判断是否需要保留文本输入框的聚焦;然后执行的表情的点击事件以及文本输入框的失去焦点事件,其中:
1)touchStartEvent
判断触发的dom的id是否是需要保留聚焦的dom,做一个标记;
2)handleInsertEmoji
做表情的插入,以及对文本输入框的聚焦;
3)handleToBlur
做输入框失去焦点的逻辑处理,根据1)中的标记,进行逻辑处理(之所以要重置标记,是为了下次输入框能正常失去焦点)。
// html
<div class="page" @touchstart="touchStartEvent">
...
<!-- 文本输入框、表情栏 -->
<Teleport to="#inputPosition">
<div v-show="isTextareaFocus" class="textarea-box" @touchstart="touchStartEvent">
...
<textarea @blur="handleToBlur" />
...
<!-- 表情 -->
<div class="emoji-list">
<div
id="emoji"
v-for="(emoji, index) in emojiList"
:key="index"
@click.stop="handleInsertEmoji(emoji)"
>{
{
emoji }}</div