uni-app 通过eventChannel向被打开页面传送数据时,vue3中仅第一次页面跳转执行,vue2中正常跳转执行

uni-app 通过eventChannel向被打开页面传送数据时,vue3中仅第一次页面跳转执行,vue2中正常跳转执行

开发环境 版本号 项目创建方式
Windows window10 HBuilderX

示例代码:

index页面

<template>  
    <view>  
        index页面  
        <button type="default" @click="goto">goto</button>  
    </view>  
</template>  

<script>  
    export default {  
        methods: {  
            goto() {  
                uni.navigateTo({  
                    url: '../test/test',  
                    events: {  
                        // 为指定事件添加一个监听器,获取被打开页面传送到当前页面的数据  
                        someEvent: function(data) {  
                            console.log(data)  
                        }  
                    },  
                    success: (res) => {  
                        // 通过eventChannel向被打开页面传送数据  
                        res.eventChannel.emit('acceptDataFromOpenerPage', {  
                            data: 'acceptDataFromOpenerPage触发'  
                        })  
                    }  
                })  
            }  
        }  
    }  
</script>

test页面

<template>  
    <view>  
        test页面  
    </view>  
</template>  

<script>  
    export default {  
        onLoad(option) {  
            // #ifdef APP-NVUE  
            const eventChannel = this.$scope.eventChannel; // 兼容APP-NVUE  
            // #endif  
            // #ifndef APP-NVUE  
            const eventChannel = this.getOpenerEventChannel();  
            // #endif  
            eventChannel.emit('someEvent', {  
                data: 'someEvent触发'  
            });  
            // 监听acceptDataFromOpenerPage事件,获取上一页面通过eventChannel传送到当前页面的数据  
            eventChannel.on('acceptDataFromOpenerPage', function(data) {  
                console.log(data)  
            })  
        }  
    }  
</script>

操作步骤:

在vue3模式下 反复点击跳转和返回

// index页面  
uni.navigateTo({  
    url: '../test/test',  
    events: {  
        // 为指定事件添加一个监听器,获取被打开页面传送到当前页面的数据  
        someEvent: function(data) {  
            console.log(data)  
        }  
    },  
    success: (res) => {  
        // 通过eventChannel向被打开页面传送数据  
        res.eventChannel.emit('acceptDataFromOpenerPage', {  
            data: 'acceptDataFromOpenerPage触发'  
        })  
    }  
})  

// test页面  
onLoad(option) {  
    // #ifdef APP-NVUE  
    const eventChannel = this.$scope.eventChannel; // 兼容APP-NVUE  
    // #endif  
    // #ifndef APP-NVUE  
    const eventChannel = this.getOpenerEventChannel();  
    // #endif  
    eventChannel.emit('someEvent', {  
        data: 'someEvent触发'  
    });  
    // 监听acceptDataFromOpenerPage事件,获取上一页面通过eventChannel传送到当前页面的数据  
    eventChannel.on('acceptDataFromOpenerPage', function(data) {  
        console.log(data)  
    })  
}

预期结果:

// 跳转几次控制台输出几次  
// 第一次  
index.vue:16 {data: "someEvent触发"}  
test.vue:21 {data: "acceptDataFromOpenerPage触发"}  
// 第二次  
index.vue:16 {data: "someEvent触发"}  
test.vue:21 {data: "acceptDataFromOpenerPage触发"}  
// 第三次  
index.vue:16 {data: "someEvent触发"}  
test.vue:21 {data: "acceptDataFromOpenerPage触发"}

实际结果:

// 无论跳转多少次控制台只打印输出一次  
index.vue:16 {data: "someEvent触发"}  
test.vue:21 {data: "acceptDataFromOpenerPage触发"}

更多关于uni-app 通过eventChannel向被打开页面传送数据时,vue3中仅第一次页面跳转执行,vue2中正常跳转执行的实战教程也可以访问 https://www.itying.com/category-93-b0.html

18 回复

使用 nextTick 可以解决第二次不会触发的问题:

<script setup> import { onLoad } from '[@dcloudio](/user/dcloudio)/uni-app'; import { getCurrentInstance, nextTick } from 'vue'; const instance = getCurrentInstance(); onLoad(async () => { await nextTick(); const eventChannel = instance.proxy.getOpenerEventChannel(); eventChannel.on('event-name', (...payloads) => { // 处理 payloads }); }); </script>

使用 onLoad 生命周期是为了兼容小程序,如果不需要发布小程序,可以不用这个生命周期。

更多关于uni-app 通过eventChannel向被打开页面传送数据时,vue3中仅第一次页面跳转执行,vue2中正常跳转执行的实战教程也可以访问 https://www.itying.com/category-93-b0.html


好用,成功解决,谢谢~

22年都5月了,这bug还存在。

这都半年了,为毛还没修复?

遇到一样的问题 H5存在 小程序正常

此问题已记录后续会优化,已加分,感谢您的反馈!

您好,那这是官方个bug是吧,最好在官网给个备注提示,我自己试了半天都没成功,一直以为是我自己的写法问题呢。另外我想问一下再hbuilder可以配置跳转查看源码呢?我想直接点击进去看看 eventChannel.on(‘acceptId’,function(data) { console.log('detail.vue id = ’ + JSON.stringify(data)); }),

已经2022年6月了,还没修复

何时能修复呢

这都一年了,还没修复?

vue3 的h5会有这个问题…都提了一段时间了还是没有改好,app没有遇到

我们就是h5 vue3,还好项目刚开始就发现了,迫使我们降到vue2

回复 删除这个账号: 哈哈,还好我们是app,但是我用h5开发方便然后遇到了,没有改成VUE2

有一个小技巧可以规避这个bug.
思路 经过反复实验发现在第二次跳转及以后是先执行完第二个页面的生命周期,再执行uni.navigateTo的success,所以可以通过页面栈获取第二个页面,然后直接调用页面中的methods传参.代码如下.
路由跳转代码:

option.success = function(res) {  
    let pages =  getCurrentPages()  
    if(option.url == ("/" + pages[pages.length-1].route)){  
        pages[pages.length-1].routeParameterEvent(option.parameter)  
    }else{  
        res.eventChannel.emit(res.eventChannel.id, option.parameter)  
    }  
}  
uni.navigateTo(option);  

第二个页面接收参数代码:

onLoad: function(option) {  
    // #ifdef APP-NVUE  
    const eventChannel = this.$scope.eventChannel; // 兼容APP-NVUE  
    // #endif  
    // #ifndef APP-NVUE  
    const eventChannel = this.getOpenerEventChannel();  
    // #endif  
    this.eventChannel = eventChannel  
    // // 监听routeParameterEvent事件,获取上一页面通过eventChannel传送到当前页面的数据  
    eventChannel.on(eventChannel.id, this.routeParameterEvent)  
},  
methods: {  
    routeParameterEvent(data) {  
        this.routeParameter = data  
    }  
}<br>

思路虽然奇特,但是增加了麻烦,还不如用缓存了。

一年了还没好呢。。。

这是一个 Vue 3 中 eventChannel 的事件监听器缓存问题。在 Vue 3 的 Composition API 中,页面组件的生命周期行为与 Vue 2 有所不同,导致 onLoad 中的事件监听器在页面实例复用时没有被正确清理和重新绑定。

解决方案:

在 test 页面的 onUnload 生命周期中手动移除事件监听器:

<script setup>
import { onUnload } from '@dcloudio/uni-app'

const eventChannel = getOpenerEventChannel()

onLoad(() => {
  eventChannel.emit('someEvent', {
    data: 'someEvent触发'
  })
  
  eventChannel.on('acceptDataFromOpenerPage', function(data) {
    console.log(data)
  })
})

onUnload(() => {
  // 清理事件监听器
  eventChannel.off('acceptDataFromOpenerPage')
})
</script>

或者使用选项式 API:

<script>
export default {
  onLoad(option) {
    const eventChannel = this.getOpenerEventChannel()
    eventChannel.emit('someEvent', {
      data: 'someEvent触发'
    })
    
    this.dataHandler = function(data) {
      console.log(data)
    }
    
    eventChannel.on('acceptDataFromOpenerPage', this.dataHandler)
  },
  onUnload() {
    const eventChannel = this.getOpenerEventChannel()
    eventChannel.off('acceptDataFromOpenerPage', this.dataHandler)
  }
}
</script>
回到顶部