uni-app vue3微信小程序v-for子项@click事件传参有误

uni-app vue3微信小程序v-for子项@click事件传参有误

开发环境 版本号 项目创建方式
Windows win10 HBuilderX
产品分类:uniapp/小程序/微信

### 示例代码:
``` html
<template>  
  <view class="container">  
    <button class="item" [@click](/user/click)="reverse" size="mini">反转数组</button>  
    <view class="item" v-for="item of arr" :key="item._id" [@click](/user/click)="show(item)"> {{ item.text }} </view>  
    <view>{{ output }}</view>  
  </view>  
</template>  

<script setup>  
import { ref } from 'vue'  

let output = ref('')  
let arr = ref([{ _id: 1, text: 'aaa' }, { _id: 2, text: 'bbb' }, { _id: 3, text: 'ccc' }, { _id: 4, text: 'ddd' }])  
function show(e) {  
  output.value += JSON.stringify(e) + '\r\n'  
}  
function reverse() {  
  arr.value = arr.value.reverse()  
}  
</script>  

<style scoped>  
.item {  
  margin: 20rpx;  
  padding: 20rpx;  
}  
</style>

操作步骤:

  1. 点击aaa,下方显示aaa
  2. 点击反转数组
  3. 点击ddd,下方显示aaa,应显示ddd

预期结果:

@click中的参数应该随数组变化而变化

实际结果:

@click中的参数没有随数组反转而变化

bug描述:

v-for展示item后,点击第一项,显示aaa,然后反转数组,再点击第一项,还是显示aaa,应显示ddd。


更多关于uni-app vue3微信小程序v-for子项@click事件传参有误的实战教程也可以访问 https://www.itying.com/category-93-b0.html

3 回复

稍后修复,临时解决方案,不指定key,或者将key指定为index

更多关于uni-app vue3微信小程序v-for子项@click事件传参有误的实战教程也可以访问 https://www.itying.com/category-93-b0.html


升级至HBuilderX Alpha 3.3.6

这是一个在 uni-app 中使用 Vue 3 的 Composition API 时,结合微信小程序平台可能遇到的响应式问题。

问题核心在于:当使用 reverse() 方法直接修改数组时,Vue 3 的响应式系统能够检测到数组的变化并更新视图,但微信小程序平台的事件处理机制可能导致事件处理器捕获的参数是旧的、未更新的引用。

原因分析:

  1. 直接修改数组引用reverse() 方法会直接修改原数组并返回该数组的引用。在 Vue 3 中,arr.value = arr.value.reverse() 这个操作会触发响应式更新,视图会重新渲染。
  2. 事件参数绑定时机:在微信小程序环境中,@click="show(item)" 这种内联事件处理器中的 item 参数,可能是在 v-for 循环的初始渲染阶段就被“固化”绑定到了对应的事件处理器上。当数组顺序改变后,视图虽然更新了,但之前绑定的事件处理器中的 item 参数可能仍然是旧的引用,指向了原来位置上的数据对象。

解决方案:

推荐使用不改变原数组,而是返回一个新数组的方法来更新数据。这样可以确保每次更新都创建一个全新的数组引用,Vue 的响应式系统能更可靠地追踪依赖,事件处理器也能绑定到正确的数据上。

reverse 函数修改为:

function reverse() {
  arr.value = [...arr.value].reverse(); // 创建新数组再反转
}

或者使用 slice() 创建副本:

function reverse() {
  arr.value = arr.value.slice().reverse();
}
回到顶部