2***@qq.com
2***@qq.com
  • 发布:2025-11-05 09:27
  • 更新:2025-11-05 13:14
  • 阅读:48

【报Bug】鸿蒙元服务onLoad 中 nextTick内访问$refs会报错

分类:uni-app

产品分类: uniapp/小程序/鸿蒙元服务

PC开发环境操作系统: Windows

PC开发环境操作系统版本号: Windows 11 家庭中文版 23H2

HBuilderX类型: Alpha

HBuilderX版本号: 4.84

第三方开发者工具版本号: DevEco Studio 6.0.0 Release

基础库版本号:

项目创建方式: HBuilderX

示例代码:
<template>  
  <view class="content">  
    <u-sticky>  
      <image class="logo" src="/static/logo.png"></image>  
    </u-sticky>  
    <test ref="test" v-if="showTest"></test>  
    <button @click="show">  
      show  
    </button>  
    <button @click="close">  
      close  
    </button>  
  </view>  
</template>  

<script>  
import Test from "@/components/Test.vue";  

export default {  
  components: {Test},  
  data() {  
    return {  
      showTest: false  
    }  
  },  
  onLoad() {  
    this.show()  
  },  
  methods: {  
    show() {  
      this.showTest = true;  
      this.$nextTick(() => {  
        setTimeout(()=>{  
          this.$refs.test.alert()  
        }, 200)  
      })  
    },  
    close() {  
      this.showTest = false;  
    }  
  }  
}  
</script>

操作步骤:

从其他页面进入以上页面即可触发

预期结果:

能正常获取$refs的值

实际结果:

报错:报错内容:异常:TypeError: Cannot read properties of undefined (reading 'dataset') at eval (webpack-internal:///./common/vendor.js:60:363) at Array.forEach (<anonymous>) at selectAllComponents (webpack-internal:///./common/vendor.js:60:317) at VueComponent.get [as $refs] (webpack-internal:///./common/vendor.js:60:1052) at VueComponent.invokeGetter (<anonymous>:3:28) at VueComponent.eval (webpack-internal:///./pages/index/index2.js:211:13) at Array.eval (webpack-internal:///./common/vendor.js:943:758) at flushCallbacks$1 (webpack-internal:///./common/vendor.js:941:596) at eval (webpack-internal:///./common/vendor.js:951:503) at e.value (<anonymous>:1:81419)

bug描述:


如图所示,在this.$nextTick外面还能获取this.$refs的值,进去之后就报错,而如果加一个setTimeout,又不报错了。
不止onLoad,在onReady里,也一样报错。而如果手动点击show按钮,则不报错。
h5和微信小程序没有这个问题。报错内容:异常:TypeError: Cannot read properties of undefined (reading 'dataset') at eval (webpack-internal:///./common/vendor.js:60:363) at Array.forEach (<anonymous>) at selectAllComponents (webpack-internal:///./common/vendor.js:60:317) at VueComponent.get [as $refs] (webpack-internal:///./common/vendor.js:60:1052) at VueComponent.invokeGetter (<anonymous>:3:28) at VueComponent.eval (webpack-internal:///./pages/index/index2.js:211:13) at Array.eval (webpack-internal:///./common/vendor.js:943:758) at flushCallbacks$1 (webpack-internal:///./common/vendor.js:941:596) at eval (webpack-internal:///./common/vendor.js:951:503) at e.value (<anonymous>:1:81419)

同时uview的u-sticky组件是写的mounted(){
this.$nextTick()
}
里面同样有一个奇怪的报错,不清楚是不是同一个原因:09:24:01.320 TypeError: Cannot read properties of undefined (reading 'relativeToViewport')
09:24:01.320 at VueComponent.observeContent (webpack-internal:///./uni_modules/uview-ui/components/u-sticky/u-sticky.js:281:29)
09:24:01.320 at VueComponent.eval (webpack-internal:///./uni_modules/uview-ui/components/u-sticky/u-sticky.js:268:23)
09:24:01.320 at Array.eval (webpack-internal:///./common/vendor.js:943:758)
09:24:01.320 at flushCallbacks$1 (webpack-internal:///./common/vendor.js:941:596)
09:24:01.320 at eval (webpack-internal:///./common/vendor.js:951:503)
09:24:01.320 at e.value (<anonymous>:1:81419)
09:24:01.320 at <anonymous>:1:89806
09:24:01.320 at Object.qt [as executeSubscribe] (<anonymous>:1:88966)
09:24:01.320 at <anonymous>:1:28

2025-11-05 09:27 负责人:无 分享
已邀请:
2***@qq.com

2***@qq.com (作者)

目前解决方案:
main.js:

// #ifdef MP-HARMONY  
// 在 new Vue() 之前重写 $nextTick  
const originalNextTick = Vue.prototype.$nextTick  
Vue.prototype.$nextTick = function (callback) {  
  setTimeout(() => {  
    if (typeof callback === 'function') {  
      // 可选择是否使用原始实现  
      return originalNextTick.call(this, callback)  
    } else {  
      // 支持无回调的 Promise 用法:this.$nextTick().then(...)  
      return originalNextTick.call(this)  
    }  
  }, 300)  
}  
// #endif  
const app = new Vue({  
  ...App,  
});  

app.$mount();

写100毫秒还是报错,写300又会有明细的卡顿,用户体验不好。但不写高一点又怕部分性能不好的设备需要这么高的等待时间

  • 2***@qq.com (作者)

    更好一点的临时解决方案:


    // #ifdef MP-HARMONY ||H5  
    // ? 在 new Vue() 之前重写 $nextTick
    const originalNextTick = Vue.prototype.$nextTick
    Vue.prototype.$nextTick = function (callback) {
    const stack = new Error().stack || ''
    let timeout = 0
    // 检查是否由生命周期钩子调用
    if (stack.includes('.created') || stack.includes('.mounted')
    || stack.includes('.onLoad') || stack.includes('.onReady')) {
    timeout = 300
    }
    setTimeout(() => {
    if (typeof callback === 'function') {
    // 可选择是否使用原始实现
    return originalNextTick.call(this, callback)
    } else {
    // 支持无回调的 Promise 用法:this.$nextTick().then(...)
    return originalNextTick.call(this)
    }
    }, timeout)
    }
    // #endif

    2025-11-05 13:36

  • 2***@qq.com (作者)

    回复 2***@qq.com: 实际测试发现此方法并非对每一个页面都有效,而据ai所说,prod发布会将created,created等函数名修改为过短的名称。所以此方法在生产环境无效,要发布也只能dev发布

    2025-11-06 14:27

DCloud_UNI_OttoJi

DCloud_UNI_OttoJi - 日常回复 uni-app/x 问题,如果艾特我没看到,请主动私信

onload 太早了,这个时候 ui 还没开始渲染,等到 onready 或者 onmounted 里操作

  • 2***@qq.com (作者)

    试了,onReady也不行

    2025-11-05 13:14

2***@qq.com

2***@qq.com (作者)


onReady测试,一样不行

要回复问题请先登录注册