uni-app中必须用uni.createSelectorQuery()异步获取元素宽高,因跨端无真实DOM;需在mounted或onReady后调用,select()后必须exec()并等回调,选择器不支持空格,真机调试优先用boundingClientRect()。
uni-app里用uni.createSelectorQuery()获取元素宽高
uni-app不支持直接用document.getelementbyid()或ref + $el拿dom尺寸,因为跨端(尤其是小程序)没有真实dom。必须走uni.createselectorquery()这一套异步查询机制。
常见错误是写完select()就以为能立刻拿到结果,实际要等exec()回调——不等就取值,全是null或undefined。
- 必须在
mounted或onReady后调用,确保节点已渲染 -
select()传的选择器不能带空格(比如.box .inner不行),只支持单层:.box、#myId、view - 真机调试时,微信小程序里
boundingClientRect()比fields({ size: true })更稳;H5端两者都行,但size字段在App端某些版本会漏掉height - 示例:
const query = uni.createSelectorQuery().in(this); query.select('#myBox').boundingClientRect(data => { console.log(data.width, data.height); // 注意:data可能是null }); query.exec();
为什么uni.createSelectorQuery()在onLoad里总拿不到尺寸
页面生命周期里,onLoad触发时组件树还没挂载,uni.createSelectorQuery().in(this)里的this上下文无效,查不到任何节点。
这不是bug,是渲染时机问题。哪怕加setTimeout硬等也不可靠,不同端渲染速度差异大。
- 正确时机只有两个:
mounted(Vue2/3 Composition API可用)、onReady(兼容性更好,所有平台都支持) - 如果元素是v-if动态插入的,还得在
nextTick或setTimeout微任务后查——但优先用watch监听数据变化再查,比盲目延时靠谱 - App端(iOS)偶尔首次
exec()返回空,可尝试重试一次,加个if (!data) setTimeout(() => query.exec(), 16)
用ref配合getRect()替代select()的适用场景
如果你用的是Vue 3 + setup语法,且目标平台是微信小程序或H5(App端getRect()支持不全),可以用ref直接绑定节点再调getRect(),比写选择器更直观。
但注意:getRect()是uni.createSelectorQuery()的语法糖,底层还是走同一套,所以异步、时机、空值判断一个都不能少。
-
ref必须是字符串(如ref="myBox"),不能是响应式变量;模板里要加id或class才好查,否则getRect()可能找不到 - H5端
getRect()返回的top/left是相对于视口的,小程序是相对于页面左上角,计算位置时别混用 - 示例:
<view ref="myBox" id="myBox"></view> // setup里 const myBox = ref(null); onReady(() => { uni.createSelectorQuery().in(this).select('#myBox').boundingClientRect().exec(res => { const rect = res[0]; if (rect) console.log(rect.width); }); });
真机上宽高为0的三个高频原因
不是代码写错了,而是环境或结构导致的“查得到节点但尺寸为0”。这种情况在微信小程序最典型,H5次之,App最少见。
- 父容器没设
height或用了flex: 1但没给父级定高,子元素撑不开——查之前先确认CSS是否生效(真机调试器里看computed样式) - 元素被
v-show="false"隐藏了,boundingClientRect()仍能查到节点但返回0;换成v-if后,节点根本不存在,查出来就是null - 字体加载中、图片未加载完、
rich-text内容异步渲染,导致首次查询时内容高度为0;解决方案是监听load事件或用IntersectionObserver(仅小程序支持)等真正渲染完成后再查

















