欢迎光临
我们一直在努力

一次:key 表达式导致的uni-app小程序事件传参事故

一、问题重现

<!– DOM示例 –>
<view v-for="(item,index) in list" :key="item.id || index">
<view @click="goSign(item)">签署协议</view>
</view>

<!– JS示例 –>
goSign(item){
console.log(item) // undefined
}

        最近在 uni-app 项目里遇到一个很隐蔽的问题:列表页点击“签署协议”时,方法明明写的是:@click="goSign(item)",正常来说item是可以获取到值的。但是实际在uni-app中goSign函数的item居然是undefined。

二、问题分析

        第一反应通常会怀疑事件绑定、数据接口、组件层级,甚至怀疑是不是某个 SDK 影响了运行。但最后排查下来,问题出在一个非常不起眼的地方:

<view v-for="(item,index) in list" :key="item.id || index">

        在 H5 / 普通 Vue 里,这种写法一般没问题。item.id || index 会作为表达式正常执行,goSign(item) 也能拿到当前循环项。但 uni-app 编译到微信小程序时,事情不完全一样。微信小程序模板没有 Vue 那种完整的 JS 闭包能力。uni-app 为了支持 v-for 里的事件传参,会在编译阶段生成一套“根据列表和 key 回查原始 item”的逻辑。当我们写:

:key="item.id || index"

uni-app 可能会把它处理成类似:

['list', 'id||index', item.id || index]

也就是说,它没有把 item.id || index 当成一个运行时表达式重新执行,而是把中间的 id||index 当成了字段路径。运行时再去列表里找:

row['id||index']

        但真实数据里当然没有一个叫 id||index 的字段,于是回查失败,事件参数里的 item 就变成了 undefined。

三、修复建议

不要在小程序端的 v-for :key 里写复杂表达式,提前把 key 算成一个真实字段:

this.list = result.data.map((item, index) => ({
…item,
rowKey: item.id || index
}))

DOM里改成:

<view v-for="(item, index) in list" :key="item.rowKey">
<view @click="goSign(item)">签署协议</view>
</view>

        这次问题的教训是:uni-app 虽然写起来像 Vue,但目标平台是小程序时,模板表达式、事件传参、v-for key 并不总是等价于浏览器里的 Vue 行为。在小程序端,最稳的写法永远是:让 key 指向一个真实、稳定、简单的字段。

赞(0)
未经允许不得转载:171主机测评 » 一次:key 表达式导致的uni-app小程序事件传参事故
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址