uni-app vue3 微信小程序中 v-if 元素上的点击事件触发错误
uni-app vue3 微信小程序中 v-if 元素上的点击事件触发错误
开发环境 | 版本号 | 项目创建方式 |
---|---|---|
Mac | macOS 15.0 (24A335) | HBuilderX |
产品分类:uniapp/小程序/微信
PC开发环境操作系统:Mac
PC开发环境操作系统版本号:macOS 15.0 (24A335)
HBuilderX类型:正式
HBuilderX版本号:4.28
第三方开发者工具版本号:RC 1.06.2409131
基础库版本号:3.6.0
项目创建方式:HBuilderX
示例代码:
<template>
<view class="main">
<view class="mobile layout-flex-acjs">
<input class="input" type="number" placeholder="请输入乘车人手机号" placeholder-style="color: #b7becc" maxlength="11"
:focus="mobileFocus" v-model="mobile" @focus="mobileFocus = true" @blur="mobileFocus = false"
v-if="mobileFocus || mobile" />
<text v-else class="input" @tap="tapMobile"> 请输入乘车人手机号 </text>
<view class="image" @tap="clearMobile" v-if="mobileFocus && mobile">
<image src="https://tx-t3propublic.t3go.cn/t3-admin/1446319048521506850" />
</view>
</view>
<view class="record">
<view class="record-h layout-flex-acjs" @tap="toPassengerHistory">
<text>历史乘车人</text>
<view class="image">
<image src="https://tx-t3propublic.t3go.cn/t3-admin/1446312561728389153" />
</view>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
mobile: '',
mobileFocus: false, // 号码输入框聚焦
};
},
methods: {
tapMobile() {
this.mobileFocus = true;
},
clearMobile(e) {
console.log('xxx-clearMobile', e);
this.mobile = '';
},
toPassengerHistory(e) {
console.log('xxx-toPassengerHistory', e);
},
},
};
</script>
<style lang="less" scoped>
.layout-flex {
display: flex;
&-ac {
display: flex;
align-items: center;
}
&-acjc {
display: flex;
align-items: center;
justify-content: center;
}
&-acjs {
display: flex;
align-items: center;
justify-content: space-between;
}
}
.main {
padding-top: 48rpx;
margin: 0 auto;
width: 702rpx;
min-height: 208rpx;
background: #ffffff;
box-shadow: 0px 16rpx 24rpx 0px rgba(49, 56, 84, 0.08);
border-radius: 24rpx;
box-sizing: border-box;
.mobile {
padding: 26rpx 4rpx 26rpx 24rpx;
margin: 0 auto;
width: 654rpx;
height: 112rpx;
background: #f7f8fc;
// box-shadow: 0px 2rpx 6rpx 0px rgba(49, 56, 84, 0.03);
border-radius: 16rpx;
box-sizing: border-box;
.input {
flex: 1;
height: 60rpx;
font-size: 44rpx;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #02102a;
line-height: 60rpx;
caret-color: #ff8533;
}
.image {
padding: 20rpx;
width: 44rpx;
height: 44rpx;
image {
width: 44rpx;
height: 44rpx;
}
}
}
.record {
position: relative;
padding: 32rpx 0 40rpx;
&-h {
padding: 0 48rpx;
text {
font-size: 24rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #747881;
line-height: 34rpx;
}
.image {
image {
width: 24rpx;
height: 24rpx;
}
}
}
&-l {
padding: 0 16rpx;
box-sizing: border-box;
margin-top: 24rpx;
height: 56rpx;
white-space: nowrap;
}
&-i {
display: inline-block;
margin-right: 16rpx;
padding: 12rpx 24rpx 10rpx;
height: 56rpx;
background: rgba(255, 231, 214, 0.3);
border-radius: 8rpx;
border: 2rpx solid rgba(255, 133, 51, 0.5);
box-sizing: border-box;
font-size: 24rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #996220;
line-height: 34rpx;
&:first-child {
margin-left: 32rpx;
}
&:last-child {
margin-right: 32rpx;
}
}
.mask {
position: absolute;
top: 86rpx;
width: 72rpx;
height: 64rpx;
&-1 {
left: 0;
background: linear-gradient(90deg, #ffffff 0%, rgba(255, 255, 255, 0) 100%);
}
&-2 {
right: 0;
background: linear-gradient(90deg, rgba(255, 255, 255, 0) 0%, #ffffff 100%);
}
}
}
}
</style>
收到, 我看下
已加分,感谢反馈,已确认bug
NB,感谢
在你的工程,你这边同时绑定了blur 事件和click事件。点击的时候,先后触发blur 事件 和 click事件,blur先触发。 blur触发时更新了事件绑定逻辑,把click绑定的事件替换了导致的bug(下个版本修复)。
一般来讲小程序端,这个bug触发条件也比较苛刻,需要同时连续触发两个事件且触发的事件影响v-if的标签,且v-if上面也绑定对应的事件。 所以影响范围较小
回复 BFC: 我不太理解为什么click绑定的事件会被替换。 我发现uni-app在vue3版本里好像把事件当成变量去渲染了,导致一个事件在AppData、WXML里会变化更新。我感觉并不是同时绑定多个事件的问题。 私信讲的那个例子是子组件向父组件 emit 事件,在老版本正常,但是新版本异常。
还没修复吗?
如果发版后仍有问题,请艾特我来跟进。github 上 issues 先关闭了,有进展会在这里进行更新
好的
还没修复吗?
还没修复吗?
在 uni-app
结合 Vue 3
开发微信小程序时,如果遇到 v-if
条件渲染的元素上点击事件触发错误的问题,通常可能是因为 v-if
控制的元素在 DOM 中被销毁和重建导致的。这种情况在条件频繁切换时尤为常见。为了确保事件能够正确绑定,可以考虑以下几种方法:
1. 使用 v-show
替代 v-if
如果元素的显示与隐藏不需要真正地从 DOM 中移除,可以使用 v-show
指令。v-show
只是切换元素的 CSS display
属性,不会销毁和重建元素。
<template>
<view v-show="isVisible" @click="handleClick">
点击我
</view>
</template>
<script>
export default {
data() {
return {
isVisible: true
};
},
methods: {
handleClick() {
console.log('元素被点击');
}
}
};
</script>
2. 确保事件绑定在稳定的父元素上
如果必须使用 v-if
,可以尝试将事件绑定在一个稳定的父元素上,然后通过事件委托来处理点击事件。
<template>
<view @click="handleParentClick">
<view v-if="isVisible" class="clickable-child">
点击我(通过父元素事件委托)
</view>
</view>
</template>
<script>
export default {
data() {
return {
isVisible: true
};
},
methods: {
handleParentClick(event) {
const target = event.target;
if (target.classList.contains('clickable-child')) {
console.log('子元素被点击(通过父元素)');
}
}
}
};
</script>
<style>
.clickable-child {
/* 确保子元素可点击样式 */
cursor: pointer;
}
</style>
3. 使用 nextTick
确保 DOM 更新完成
如果条件切换后需要确保 DOM 更新完成再绑定事件,可以使用 Vue
的 nextTick
方法。
<template>
<view v-if="isVisible" ref="clickableElement">
点击我
</view>
<button @click="toggleVisibility">切换可见性</button>
</template>
<script>
import { ref, nextTick } from 'vue';
export default {
setup() {
const isVisible = ref(true);
const clickableElement = ref(null);
const toggleVisibility = () => {
isVisible.value = !isVisible.value;
nextTick(() => {
if (clickableElement.value) {
clickableElement.value.addEventListener('click', () => {
console.log('元素被点击(nextTick后绑定)');
});
}
});
};
return {
isVisible,
clickableElement,
toggleVisibility
};
}
};
</script>
这些方法可以帮助你解决 v-if
元素上点击事件触发错误的问题。根据具体场景选择合适的方法。