Trae根据原型设计稿生成微信小程序密码输入框的踩坑记录

devtools/2025/2/28 23:17:47/

一、需求描述

最近经常使用Trae生成一些小组件和功能代码(对Trae赶兴趣的可以看之前的文章《TraeAi上手体验》),刚好在用uniapp开发微信小程序时需要开发一个输入密码的弹框组件,于是想用Trae来实现。原型设计稿如下:
在这里插入图片描述

Trae_4">二、Trae生成的雏形组件

经过一次描述附加原型设计图后,Trae给我生成了初始代码,预览如下:

在这里插入图片描述

在微信开发者工具中使用似乎是可以的,它还细心的额外给我增加了对确认按钮的激活条件(多选框需要至少选一个),这个激活条件我是没有体现在需求描述上的,但实际也是需要的。

然而,在实际使用的时候,会发现以下问题:

①它在界面上使用了4个input输入框,当输入框为空时再按下backspace键,无法触发@input或者@keyup,导致无法将光标回退到上一个输入框。同时,因为使用了4个不同的input输入框,导致在输入后光标自动移动到下一个输入框时会引起输入法键盘的闪动。

②input上虽然设置了type=“number”,但在微信开发者工具中,还是能输入其它字符。

③虽然它在弹窗关闭时对所有输入变量进行了重置,但再次打开弹框时,多选的checkbox组件依然显示之前的勾选状态,而没有被重新初始化为未勾选状态。

④需求描述和原型设计稿中都有右上角关闭的描述,但实际没有显示弹窗的右上角的关闭按钮(其实代码是有生成,但它给的关闭图片并不存在,图片路径却不是随机的,而似乎有根据项目使用的cdn来生成,所以差点让我信以为真)

三、问题修复

上面4个问题中,第一个问题是最主要的,也是比较麻烦的。

在保留4个input输入框的方式下,最初为了解决当输入框为空时再按下backspace键,无法触发@input的问题时,Trae想到了插入零宽字符\u200B的方案:

在这里插入图片描述

但在实际测试过程中,会导致输入的数字无法正常显示。

经过几次尝试,如果在不改变实现方式,也就是保留4个input输入框的方式下,无法解决事件触发及输入法键盘闪动的问题。于是Trae给出来用“4个普通view元素+隐藏的input”的方式来实现密码输入:

在这里插入图片描述

主要改动说明:1. 移除了多个输入框,改用一个隐藏的真实输入框
2. 添加了显示用的密码框
3. 简化了输入处理逻辑
4. 在关闭弹窗时增加了状态重置
5. 优化了样式结构,确保隐藏输入框覆盖整个输入区域

经过上述修改,输入法闪动的问题解决了,backspace回退的问题也解决了。但是引入了一个新的问题:

由于真实的输入框是覆盖在上层,虽然它也设置了opacity: 0;,在微信开发者工具中没有发现什么问题,但是在Android真机上却显示了输入框的文字和闪烁的光标。

输入框文字可以用css样式进行隐藏,但光标却始终无法隐藏:

Trae给出的几次方案:

方案一:
在这里插入图片描述

 .real-password-input {position: absolute;top: 0;left: 0;width: 100%;height: 100rpx;opacity: 0;z-index: 1;background: transparent;color: transparent;caret-color: transparent;}

方案二:

在这里插入图片描述

 .real-password-input {pointer-events: none;  /* 添加这行 */
}

方案三:

在这里插入图片描述

  .real-password-input {position: absolute;top: -9999rpx;  // 将输入框移出可视区域left: -9999rpx;width: 100%;height: 100rpx;opacity: 0;z-index: 1;background: transparent;color: transparent;}

当然还有deepseek给出的unselectable=“on” ,readonly(微信小程序input没有这个属性),disabled,这些方案都不行。

最终为了不让光标显示出来,那么只能采用方案三,但方案三有个问题,就是如果输入完成,输入法的键盘消失后,如果想再次输入该怎么办?能否再次点击那4个输入框来唤起输入法的键盘呢?

一般我们使用input来获取焦点是这样的input.focus(),但在uniapp微信小程序的开发中,实际上发现这样是无效的。当然同时也发现了,在弹框出现后如果想让input自动获得焦点,也同样不能使用这样的方式,哪怕你设置了setTimeout延时:

在这里插入图片描述
好在Trae最终给出了另一个方案:

在这里插入图片描述
通过focus的设置,解决了在弹窗显示时自动获取焦点的问题。那么对于点击密码输入框自动获取焦点的解决是否也可以通过改变focus属性的方式实现呢?答案是可以的,只不过这时候我们加上了setTimeout的包裹:

const handlePasswordInputClick = () => {isFocus.value = falsesetTimeout(() => {isFocus.value = true}, 100)
}

第一个问题终于解决,剩下的三个问题中的第三个问题checkbox组件勾选状态重置问题,Trae最终也给出了解决办法:

在这里插入图片描述

最终得到的完整代码如下:

<template><uni-popup ref="popup" type="center" :mask-click="false" @change="handlePopupChange"><view class="share-popup"><view class="share-popup-header"><text class="share-popup-title">分享xx记录</text><uni-icons type="closeempty" size="20" color="#118170" class="popup-detail-header__close"@click="handleClose" /></view><view class="share-content"><view class="share-tip">选择分享内容,并设置查看密码后,对方通过输入密码就能查看到患者分享的记录内容了~</view><view class="share-options"><checkbox-group @change="handleShareOptionChange"><label v-for="(item, index) in shareOptions" :key="item.value" class="share-option-item"><checkbox :value="item.value" color="#00D997" :checked="checkedStatus[index]"/><text>{{item.label}}</text></label></checkbox-group></view><view class="password-section"><view class="password-title">输入密码</view><view class="password-input-group" @click="handlePasswordGroupClick"><view v-for="(item, index) in 4" :key="index"class="password-input"@click="handlePasswordInputClick">{{ password[index] }}</view><input type="number"maxlength="4"v-model="realPassword"class="real-password-input"@input="handlePasswordInput"ref="passwordInput":focus="isFocus" /></view></view><button class="confirm-btn" :class="{'confirm-btn-active': isValid}":disabled="!isValid"@click="handleConfirm">确认</button></view></view></uni-popup>
</template><script setup>
import { ref, computed, nextTick } from 'vue'const popup = ref(null)
const password = ref(['','','',''])
const realPassword = ref('')
const selectedOptions = ref([])
const passwordInput = ref(null)
const isFocus = ref(false)
const checkedStatus = ref(new Array(3).fill(false))const shareOptions = [{ label: '选项1, value: '1' },{ label: '选项2', value: '2' },{ label: '选项3', value: '3' }
]const isValid = computed(() => {return password.value.every(v => v !== '') && selectedOptions.value.length > 0
})const handlePasswordInput = (e) => {const value = e.detail.valueif (!/^\d*$/.test(value)) {nextTick(() => {realPassword.value = realPassword.value.replace(/\D/g, '')})return}const valueArray = value.split('')password.value = new Array(4).fill('').map((_, index) => valueArray[index] || '')// 当输入满4位数时,自动失去焦点if (value.length === 4) {isFocus.value = false}
}const handlePasswordGroupClick = () => {const input = passwordInput.valueif (input) {input.focus()}
}const handleShareOptionChange = (e) => {selectedOptions.value = e.detail.valuecheckedStatus.value = shareOptions.map(option => selectedOptions.value.includes(option.value))
}const handleConfirm = () => {popup.value.close()
}const handleClose = () => {popup.value.close()
}const resetState = () => {password.value = ['','','','']realPassword.value = ''selectedOptions.value = []checkedStatus.value = new Array(3).fill(false)
}const handlePopupChange = (e) => {isFocus.value = e.showif (!e.show) {resetState()}
}const show = () => {resetState()nextTick(() => {popup.value.open()})
}const handlePasswordInputClick = () => {isFocus.value = falsesetTimeout(() => {isFocus.value = true}, 100)
}defineExpose({show
})
</script><style lang="scss" scoped>
.share-popup {width: 622rpx;background: #FFFFFF;border-radius: 24rpx;padding: 40rpx;&-header {display: flex;justify-content: space-between;align-items: center;margin-bottom: 30rpx;}&-title {font-size: 36rpx;font-weight: 500;color: #1A1A1A;}&-close {width: 48rpx;height: 48rpx;}
}.share-content {.share-tip {font-size: 26rpx;color: #999999;line-height: 37rpx;margin-bottom: 30rpx;}
}.share-options {margin-bottom: 40rpx;.share-option-item {display: flex;align-items: center;margin-bottom: 20rpx;font-size: 30rpx;color: #1A1A1A;}
}.password-section {.password-title {font-size: 30rpx;color: #1A1A1A;margin-bottom: 20rpx;}.password-input-group {display: flex;justify-content: space-between;margin-bottom: 40rpx;position: relative;}.password-input {width: 100rpx;height: 100rpx;background: #F5F5F5;border-radius: 12rpx;text-align: center;font-size: 36rpx;line-height: 100rpx;cursor: pointer;}.real-password-input {position: absolute;top: -9999px;left: -9999px;width: 1rpx;height: 1rpx;opacity: 0;z-index: 1;background: transparent;color: transparent;caret-color: transparent;}
}.confirm-btn {width: 100%;height: 88rpx;background: #CCCCCC;border-radius: 44rpx;color: #FFFFFF;font-size: 32rpx;display: flex;align-items: center;justify-content: center;&-active {background: linear-gradient(132deg, #00D997 0%, #00D57D 100%);}
}
</style>

四、后续

上面我们通过改变focus属性的方式解决了在弹窗显示时自动获取焦点的问题,但后面我们发现这种方式能否生效与弹窗显示的方式有关:

①当用户通过点击的交互方式触发显示弹框时,通过改变focus属性的方式可以让input自动获得焦点,在移动端表现为输入法的软键盘被唤起,在微信开发者工具中表现为直接可以输入数字显示到输入框中。

②当弹框是通过脚本唤起,而非用户交互的结果时,通过改变focus属性的方式,在开发者工具中无法自动获得焦点,但在移动端可以自动获得焦点,不过对focus属性的改变最好是在弹框显示的回调里通过setTimeout进行设置,否则可能会无法生效(比如在iphone上会出现):

const handlePopupChange = (e) => {setTimeout(() => {isFocus.value = e.show}, 100)
}

http://www.ppmy.cn/devtools/163467.html

相关文章

第十章:服务器消费者管理模块

目录 第一节&#xff1a;代码实现 1-1.Consumer类 1-2.QueueConsumer类 1-3.QueueConsumerManger类 第二节&#xff1a;单元测试 下期预告&#xff1a; 服务器的消费者管理模块在mqserver目录下实现。 第一节&#xff1a;代码实现 创建一个名为mq_consumer.hpp的文件&#…

若依Vue,tab切换时实现缓存之前的查询条件、不刷新页面、不请求

1、菜单里面的路由地址和缓存 2、页面中对应路由地址&#xff0c;首字母大写驼峰命名

【Python爬虫(80)】当Python爬虫邂逅边缘计算:探索数据采集新境界

【Python爬虫】专栏简介:本专栏是 Python 爬虫领域的集大成之作,共 100 章节。从 Python 基础语法、爬虫入门知识讲起,深入探讨反爬虫、多线程、分布式等进阶技术。以大量实例为支撑,覆盖网页、图片、音频等各类数据爬取,还涉及数据处理与分析。无论是新手小白还是进阶开发…

SocketTool、串口调试助手、MQTT中间件基础

目录 一、SocketTool 二、串口通信 三、MQTT中间件 一、SocketTool 1、TCP 通信测试&#xff1a; 1&#xff09;创建 TCP Server 2&#xff09;创建 TCP Client 连接 Socket 4&#xff09;数据收发 在TCP Server发送数据12345 在 TCP Client 端的 Socket 即可收到数据12…

react使用拖拽,缩放组件,采用react-rnd解决

项目中需求&#xff0c;要求给商品图片添加促销标签&#xff0c;并且可拉伸大小&#xff0c;和拖拽位置 最后选择用react-rnd来实现 话不多说&#xff0c;直接上代码&#xff01;&#xff01;&#xff01; 1.在项目根目录下执行以下代码&#xff0c;引入react-rnd yarn add r…

【Arxiv 大模型最新进展】北大 Parenting 方法登场:参数魔法解锁检索增强语言模型新高度!

【Arxiv 大模型最新进展】北大 Parenting 方法登场&#xff1a;参数魔法解锁检索增强语言模型新高度&#xff01; &#x1f31f; 嗨&#xff0c;你好&#xff0c;我是 青松 &#xff01; &#x1f308; 自小刺头深草里&#xff0c;而今渐觉出蓬蒿。 NLP Github 项目推荐&#…

利用python和gpt写一个conda环境可视化管理工具

最近在学习python&#xff0c;由于不同的版本之间的差距较大&#xff0c;如果是用环境变量来配置python的话&#xff0c;会需要来回改&#xff0c;于是请教得知可以用conda来管理&#xff0c;但是conda在管理的时候老是要输入命令&#xff0c;感觉也很烦&#xff0c;于是让gpt帮…

windows下适用msvc编译ffmpeg 适用于ffmpeg-7.1

需要的工具: visual studio 2019 (可以是其他版本&#xff0c;只是本人电脑上装的为2019) msys2 ffmpeg-7.1源码 1. 修改msys2_shell.cmd 在msys2目录修改msys2_shell.cmd 打开后找到行set MSYS2_PATH_TYPEinherit 删除开头的rem 2. 运行msys2 运行x64 Native Tools Command …