Uniapp踩坑 -- $ref无法使用,如何手动获取input焦点

文章描述了在uniapp开发过程中遇到的表单验证和元素聚焦问题。首先尝试使用$event.target和$refs获取DOM元素并聚焦,但遇到报错。接着发现uniapp内置组件不支持ref属性,document方法在微信小程序中也不适用。最终,作者通过设置数据状态focusState来手动控制输入框的焦点,实现了失去焦点时的错误提示和重新聚焦功能。

起因是做一个表单验证,希望失去焦点的时候,验证输入的正确性,如果输入格式不规范则弹出错误提示并获取焦点,然而却被各种报错折磨了一个小时

首次尝试,使用$event.target获取dom元素

@blur="dataExamine($event.target)"
e.focus()

报错提示

第二次尝试,使用vue的$ref

<input ref="input" @blur="dataExamine()"></input>
this.$refs.input.focus()

依旧报错

 网络查询后得知uniapp的ref属性不能用在uniapp的内置组件上面,只能用在自定义组件上面

第三次尝试,使用document.getElementById

相同的报错原因,找不到focus()这个函数

再次查询网络,发现微信小程序无法使用document,只能通过下列形式获取

const query = uni.createSelectorQuery().in(this);
query.select('#id')

然而通过该方法获取dom元素依旧无法使用focus()方法

最后解决,使用uniapp自带的自动获取焦点

经过网络搜索,没有找到什么简单实现的方法,无奈只能把自动变成手动

<input :focus="focusState" @blur="dataExamine()"></input>

data()里

focusState: true,

在失去焦点的时候,将focusState设为false,在需要获取的的时候再设为true

dataExamine() {
		this.focusState = false
		let daysIsNotEmpty = uni.$utils.verification.isNotEmpty(this.banDays)
		let daysIsCorrect = this.banDays !== 0 && 
!/^0/.test(this.banDays) && Number.isInteger(this.banDays)
		if (!daysIsNotEmpty || !daysIsCorrect) {
			this.$nextTick(() => {
				this.focusState = true
			})
		}
}

最终实现获取焦点

总结

1. uniapp 的内置组件不能使用$ref

2. uniapp 不能使用document

<think>好的,用户现在想在UniApp中为uni-collapse组件设置动态ref,并了解如何使用它。我需要回顾之前的对话和已有的知识来提供准确的帮助。 首先,用户之前询问过如何动态设置ref的index,我给出了两种方法:动态绑定ref字符串和响应式对象存储实例。现在用户的问题具体到uni-collapse组件,可能需要类似的解决方案,但需要结合uni-collapse的特性。 uni-collapse是一个折叠面板组件,通常包含多个uni-collapse-item。用户可能需要动态生成这些item,并为每个item设置ref,以便在代码中访问它们,比如控制展开或折叠状态。 考虑到UniApp的环境,尤其是小程序平台的限制,使用函数式ref或动态字符串绑定可能仍然适用。但要注意,uni-collapse-item可能有一些特定的方法或属性需要调用,比如toggle方法。 接下来,我需要检查用户提供的引用内容是否有帮助。引用[1]关于HTTP的Location头,似乎与当前问题无关。引用[2]是关于目录结构的,可能也不相关。因此,可以忽略这些引用,专注于用户之前的讨论和UniApp的文档。 根据之前的回答,动态ref的两种方法仍然有效。但uni-collapse-item可能需要通过父组件uni-collapse来管理状态,或者每个item有自己的ref。例如,用户可能希望动态控制某个特定item的展开状态,这时需要获取该item的实例并调用其方法。 需要注意,uni-collapse的API是否有特殊要求。比如,是否每个item需要唯一的name属性,或者是否可以通过ref直接调用toggle方法。查阅UniApp文档,发现uni-collapse-item通常通过name属性来标识,父组件uni-collapse可以通过value属性控制哪些item展开。但用户可能希望直接通过ref访问item实例,而不是通过父组件的value。 因此,动态设置每个uni-collapse-item的ref,存储到响应式对象中,然后在需要时调用它们的方法,比如toggle。例如,点击按钮时展开某个item,可以通过ref获取该item并调用toggle。 另外,考虑到小程序环境,可能需要使用selectComponent方法,特别是在ref无法直接获取的情况下。因此,可以建议用户两种方法:使用Vue的响应式ref或者小程序的selectComponent。 总结步骤:动态生成uni-collapse-item,为每个item设置动态ref,存储这些ref以便后续访问,处理平台差异,并提供示例代码说明如何使用这些ref来控制item的状态。</think>在 UniApp 中为 `uni-collapse` 组件设置动态 `ref` 并实现交互控制,需结合 **动态索引绑定** 和 **组件实例管理** 技术,以下是具体实现方案: --- ### 一、动态绑定 ref 实现折叠项控制 通过 `v-for` 动态生成折叠项,并利用 **函数式 ref** 或 **动态字符串** 捕获组件实例。 ```vue <template> <uni-collapse> <!-- 动态生成折叠项 --> <uni-collapse-item v-for="(item, index) in list" :key="index" :title="item.title" :ref="(el) => setCollapseRef(el, index)" <!-- 函数式 ref --> > {{ item.content }} </uni-collapse-item> </uni-collapse> <button @click="toggleItem(0)">切换第一个折叠项</button> </template> <script setup> import { ref } from 'vue'; const collapseRefs = ref({}); // 响应式存储折叠项实例 // 动态捕获组件实例 const setCollapseRef = (el, index) => { if (el) collapseRefs.value[index] = el; }; // 通过索引控制折叠状态 const toggleItem = (index) => { const collapseItem = collapseRefs.value[index]; collapseItem.toggle(); // 调用官方提供的 toggle() 方法[^1] }; </script> ``` --- ### 二、兼容小程序的特殊处理 若在小程序环境中遇到 `ref` 失效问题,需改用 **选择器查询** 获取组件实例: ```vue <template> <uni-collapse> <uni-collapse-item v-for="(item, index) in list" :key="index" :id="`collapse-item-${index}`" <!-- 设置动态 ID --> > {{ item.content }} </uni-collapse-item> </uni-collapse> </template> <script setup> const toggleItem = (index) => { uni.createSelectorQuery() .select(`#collapse-item-${index}`) .node() .exec(res => { res[0].node.toggle(); // 通过节点操作 }); }; </script> ``` --- ### 三、通过数据驱动实现状态同步(推荐) 结合 `uni-collapse` 的 `value` 属性实现更可靠的联动控制: ```vue <template> <uni-collapse :value="activeNames" @change="onCollapseChange"> <uni-collapse-item v-for="item in list" :key="item.name" :name="item.name" <!-- 必须设置 name 属性 --> :title="item.title" > {{ item.content }} </uni-collapse-item> </uni-collapse> </template> <script setup> import { ref } from 'vue'; const activeNames = ref([]); // 存储展开项 name 值 // 切换指定折叠项 const toggleItem = (name) => { const index = activeNames.value.indexOf(name); if (index > -1) { activeNames.value.splice(index, 1); // 关闭 } else { activeNames.value.push(name); // 展开 } }; </script> ``` --- ### 关键差异对比 | 方法 | 优点 | 缺点 | 适用场景 | |---------------------|--------------------------|-----------------------------|-----------------------| | 动态 ref 绑定 | 直接调用组件方法 | 需处理多平台兼容性 | H5/App 环境 | | 选择器查询 | 兼容小程序 | 代码冗余,性能较低 | 微信小程序 | | 数据驱动 (value 属性) | 官方推荐,响应式同步 | 需维护 name 值列表 | 多平台通用[^1] | --- ### 注意事项 1. **命名规范**:动态 `ref` 标识符避免使用纯数字,建议 `item-0` 格式 2. **生命周期**:组件卸载时需清理 `collapseRefs` 中的无效引用 3. **平台特性**:小程序中 `ref` 可能延迟加载,建议在 `onReady` 后操作 4. **性能优化**:动态生成超过 50 个折叠项时,推荐使用数据驱动方案 ---
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值