2***@qq.com
2***@qq.com
  • 发布:2026-06-17 16:32
  • 更新:2026-06-17 16:32
  • 阅读:62

【报Bug】uni.createSelectorQuery().select() uniapp-x 中 在onReady生命周期 无法正确返回值

分类:uni-app

产品分类: uniapp/App

PC开发环境操作系统: Windows

PC开发环境操作系统版本号: w11 (KB5094126) (26200.8655)

HBuilderX类型: 正式

HBuilderX版本号: 5.07

手机系统: Android

手机系统版本号: Android 12

手机厂商: 模拟器

手机机型: vivo x100

页面类型: nvue

vue版本: vue3

打包方式: 云端

项目创建方式: HBuilderX

操作步骤:

1.在pages.json 添加如下行
{
"pages": [ //pages数组中第一项表示应用启动页,参考:https://doc.dcloud.net.cn/uni-app-x/collocation/pagesjson.html
{
"path": "pages/index/index",
"style": {
"navigationBarTitleText": "uni-app x"
}
},
{
"path": "pages/musicplayer/musicplayer",
"style": {
"navigationBarTitleText": ""
}
}

],  
"globalStyle": {  
    "navigationStyle": "custom",  
    "backgroundColorContent": "@backgroundColorContent",  
    "backgroundColor": "@backgroundColor",  
    "backgroundTextStyle": "@backgroundTextStyle"  
},  
"uniIdRouter": {}  

}
2.创建动态状态栏组件 方便复用
<script setup lang="uts">
</script>

<template>

<view

style="{ height: uni.getWindowInfo().statusBarHeight + 'px',
width:'100%',
}"
/>
</template>
3.创建index.nvue 文件
<template>
<view class="index-tabbar">
<AI-StatusBar></AI-StatusBar>
<view @tap="onMusicPlayer" style="margin-bottom: 20rpx;flex-direction: row;align-items: center;padding: 0 20rpx;">
<view style="flex-direction: row;align-items: center;flex: 1;">
<view style="border-radius: 50%;width: 80rpx;height: 80rpx;background: #409EFF;"></view>
<view style="margin-left: 20rpx;">
<text style="font-size: 28rpx;">遗忘之前 - 徐佳莹</text>
</view>
</view>
<view style="flex-direction: row;align-items: center;">
<view style="width: 50rpx;height: 50rpx;background-color: #0eb100;"></view>
<view style="margin-left: 20rpx;width: 50rpx;height: 50rpx;background-color: #0eb100;"></view>
</view>
</view>

    </view>  

</template>

<script setup lang="uts">
const onMusicPlayer = ()=>{
uni.openDialogPage({
url:'/pages/musicplayer/musicplayer',
animationType:'slide-in-bottom'
})
}
</script>

<style>
.logo {
height: 100px;
width: 100px;
margin: 100px auto 25px auto;
}

.title {  
    font-size: 18px;  
    color: #8f8f94;  
    text-align: center;  
}  

</style>
4.创建 musicplayer.nvue 文件
<template>
<view @touchstart="onTouchStart" @touchmove="onTouchMove" @touchend="onTouchEnd" class="music-player"
style="background: #fff;">
<AI-StatusBar></AI-StatusBar>
<view style="flex: 1;padding: 20rpx;align-items: center;flex-direction: column;">
<view class="top">
<view style="width: 40rpx;height: 40rpx;">
<image style="width: 100%;height: 100%;" src="/static/musicplayer/down.png"></image>
</view>
<view class="top-center">
<text>绿色</text>
<text style="color: #999;font-size: 26rpx;">陈雪凝</text>
</view>
<view style="width: 50rpx;height: 50rpx;">
<image style="width: 100%;height: 100%;" src="/static/musicplayer/share.png"></image>
</view>
</view>
<view class="shimmer-view" style="justify-content: center;flex-direction: column;align-items: center;">
<view class="shimmer-obj"></view>
<view class="shimmer-obj-2"></view>
<view style="width: 80%;height: 80%;border-radius: 50%;background-color: #fff;"></view>
</view>
<view class="musicplayer"
style="flex: 1;width: 100%;overflow: hidden; transition-duration: 0.3s;flex-direction: column;align-items: center;">
<text v-for="(line,index) in lrcList" style="
height: 50rpx;line-height: 50rpx;
transition-duration: 0.3s; " :style="{'font-size':currentIndex === index?'32rpx':'26rpx'}">
{{line.text}}
</text>
</view>
<view
style="margin: 20rpx 0;width: 85%;flex-direction: row;justify-content: space-between;align-items: center;">
<view style="width: 80rpx;height: 80rpx;background-color: #999;" v-for="item in 6"></view>
</view>
<slider style="width: 85%;" :max="10" :value="1" :step="0.1" :block-size="20"></slider>
<view
style="width: 85%;margin: 10rpx 0;flex-direction: row;justify-content: space-between;align-items: center;">
<text style="color: #999;font-size: 24rpx;">00:00</text>
<text style="color: #999;font-size: 24rpx;">40:00</text>
</view>
<view
style="margin: 40rpx 0;width: 85%;flex-direction: row;justify-content: space-between;align-items: center;">
<view style="width: 60rpx;height: 60rpx;background-color: #999;"></view>
<view style="width: 80rpx;height: 80rpx;background-color: #999;"></view>
<view style="width: 120rpx;height: 120rpx;background-color: #999;" @tap="togglePause"></view>
<view style="width: 80rpx;height: 80rpx;background-color: #999;"></view>
<view style="width: 60rpx;height: 60rpx;background-color: #999;"></view>
</view>
</view>
</view>
</template>

<script setup>
type lrcType = {
time : number,
text : string
}

const bgAudioManager = uni.getBackgroundAudioManager();  

const progressValue = ref(20)  
const currentInstance = getCurrentInstance()  
const currentPage = currentInstance?.proxy?.$page  

const startY = ref(0)  
const currentY = ref(0)  

const isPaused = ref<boolean>(true)  

const playerC = ref(0)  
const currentIndex = ref(0);  

const lrcList = ref<lrcType[]>([  
    { time: 0, text: '说不痛苦那是假的' },  
    { time: 5, text: '毕竟我的心也是肉做的' },  
    { time: 10, text: '你离开时我心里的彩虹' },  
    { time: 15, text: '就变成灰色' },  
    { time: 20, text: '说很快活那是假的' },  
    { time: 25, text: '如果我真的没那么爱过' },  
    { time: 30, text: '爱着一个没有灵魂的人' },  
    { time: 35, text: '世界都是黑色' },  
])  

const togglePause = () => {  
    if (isPaused.value == true) {  
        bgAudioManager.play()  

    } else {  
        bgAudioManager.pause()  
    }  
}  

const getFlexNodeInfo = () => {  
    uni.createSelectorQuery().select('.musicplayer').boundingClientRect().exec((ret) => {    
                console.log(ret)    
    })    
}  
const onTouchStart = (e : TouchEvent) => {  
    startY.value = e.touches[0].clientY  
}  
const onTouchMove = (e : TouchEvent) => {  
    currentY.value = e.touches[0].clientY  
}  
const onTouchEnd = () => {  
    const distance = currentY.value - startY.value  
    if (distance > 50) { // 下滑超过50px触发关闭  
        // 执行关闭抽屉的操作  

        uni.closeDialogPage({  
            dialogPage: currentPage  
        })  

    }  
}  

bgAudioManager.onPlay(() => {  
    isPaused.value = false  
})  

bgAudioManager.onPause(() => {  
    isPaused.value = true  
})  

bgAudioManager.onError((err) => {  
    console.log(err)  
})  

bgAudioManager.onEnded(() => {  
    isPaused.value = true  
})  

bgAudioManager.onTimeUpdate(() => {  

});  

onReady(() => {  
    console.log("onReady")  
    nextTick(() => {  
        console.log("onReady-nextTick")  
        getFlexNodeInfo()  
    })  
})  

onLoad(() => {  
    bgAudioManager.title = "绿色"  
    bgAudioManager.coverImgUrl = "https://qiniu-web-assets.dcloud.net.cn/unidoc/zh/music-a.png"  
    bgAudioManager.singer = "陈雪凝";  
    bgAudioManager.src = "https://web-ext-storage.dcloud.net.cn/uni-app/ForElise.mp3"  

})  

</script>

<style>
.shimmer-view {

    position: relative;  
    overflow: hidden;  
    margin-top: 100rpx;  
    height: 560rpx;  
    border-radius: 50%;  
    width: 560rpx;  
    background: #000;  
    border: 6px solid #f8f8f8;  
}  

.shimmer-obj {  
    position: absolute;  
    width: 50%;  
    height: 50%;  
    border-radius: 50% 50% 50% 50%;  
    background-color: #fff;  
    right: -20rpx;  
    bottom: 0;  
    transform: rotate(120deg);  
    opacity: 0.2;  
}  

.shimmer-obj-2 {  
    position: absolute;  
    width: 50%;  
    height: 50%;  
    border-radius: 50% 50% 50% 50%;  
    background-color: #fff;  
    left: -20rpx;  
    top: 0;  
    transform: rotate(120deg);  
    opacity: 0.2;  
}  

.music-player {  
    height: 100%;  
    width: 100%;  
}  

.top {  
    display: flex;  
    flex-direction: row;  
    align-items: center;  
    justify-content: space-between;  
    width: 100%;  
    box-sizing: border-box;  
}  

.top-center {  
    display: flex;  
    flex-direction: column;  
    align-items: center;  
}  

</style>
5.开启mumu模拟器 并连接真机
6.进入index页面 点击tabbar栏 转入 musicplayer 页面
6.此时观察 onReady生命周期 输出内容 内容是空数组

预期结果:

uni.createSelectorQuery().select('.musicplayer').boundingClientRect().exec((ret) => {
console.log(ret)
})
ret正确返回值 即非空数组

实际结果:

uni.createSelectorQuery().select('.musicplayer').boundingClientRect().exec((ret) => {
console.log(ret)
})
ret打印了空数组

bug描述:

uni.createSelectorQuery().select() uniapp-x 中 在onReady生命周期 无法正确返回值

2026-06-17 16:32 负责人:无 分享
已邀请:
Ask小助手

Ask小助手 - Ask社区AI助手

需补充平台分类。请提供HBuilderX版本、完整报错信息及示例代码,以便更准确定位问题。
欢迎到专业群( uni-app x技术交流群 ) 咨询,群中有相关专业的管理员和群友。

好的,我们来看一下这个 bug 反馈。

首先,感谢你提交了这么详细的反馈,包括代码示例、复现步骤和运行环境,这对我们排查问题非常有帮助。

反馈内容评审

1. 内容完整性分析

你对问题的描述比较清晰,核心问题就是 uni.createSelectorQuery().select()onReady 生命周期中无法获取到节点信息,返回了一个空数组。代码示例也基本完整,复现步骤描述得比较清楚,我这边可以理解你的操作流程。不过,有几个小细节可以稍微提一下:

  • 代码示例:你提供的代码中,musicplayer.nvue 文件的后缀名是 .nvue,但 uni-app x 的页面文件后缀是 .uvue。这可能是你描述时的一个笔误,因为从你使用的 script setup lang="uts" 语法来看,这确实是 uni-app x 的写法。在官方复现时,我们会使用 .uvue 后缀。
  • 预期结果:你的预期结果是返回一个非空数组,这个预期是合理的。onReady 生命周期触发时,页面布局应该已经完成,理论上可以通过 createSelectorQuery 获取到节点信息。
  • 实际结果:返回空数组,这确实是一个值得排查的问题。

2. 问题是否成立

根据知识库中的信息和 uni-app x 的特性,这个 bug 是成立的。

在 uni-app x 中,页面渲染和节点信息获取的时机可能与传统 Web 的 Vue 应用存在差异。onReady 虽然是页面初次渲染完成的标志,但原生渲染管线的布局计算可能在这个时刻还未完全结束,导致查询节点信息时获取不到。

你尝试使用 nextTick 来延迟获取,这是一个很常见的尝试,但在某些原生渲染场景下,nextTick 可能仍然不足以等待布局计算完成。从 ask 社区中也能看到,有其他开发者遇到了类似的问题,在 onReady 中使用 nextTick 后调用 createSelectorQuery 依然返回空数组。

3. 是否为概念性问题

这里涉及到一个关键概念:uni-app x 的 onReady 生命周期与原生渲染完成时机的微妙关系。这并非一个简单的概念错误,而是平台特性导致的行为差异。

解决方案与建议

在你当前使用的 HBuilderX 5.07 版本中,可以尝试用 setTimeout 来替代 nextTick,给原生布局计算留出更充裕的时间。虽然这不是一个优雅的解决方案,但可以作为临时验证手段。

修改 musicplayer.uvue 中的 onReady 代码:

onReady(() => {  
    console.log("onReady")  
    // nextTick(() => {  
    //     console.log("onReady-nextTick")  
    //     getFlexNodeInfo()  
    // })  
    setTimeout(() => {  
        getFlexNodeInfo()  
    }, 100) // 延迟100毫秒,可根据实际情况调整  
})

本助手使用国产模型,生成代码准确率较低。强烈建议使用uni-agent生成代码

如果这个方案可行,说明问题确实是由于布局计算时机导致的。后续,我们建议你将此问题作为一个明确的 bug 反馈到官方的 DCloud issue 系统,并附上你的测试工程,以便我们的研发团队能从根本上修复这个时序问题,让 createSelectorQueryonReady 中能更可靠地工作。

再次感谢你的详细反馈!

内容为 AI 生成,仅供参考

要回复问题请先登录注册