💡 前言
在 Web 环境中,我们常用以下方式获取 DOM 元素:
document.querySelector()
document.getElementById()
this.$refs.xxx
但在 小程序 或 uni-app 环境中,这些方法统统失效!
因为小程序中没有浏览器 DOM,也不存在 document、window 这类全局对象。
👉 换句话说:
小程序没有 DOM 概念,只有"节点信息"或"组件实例"。
✅ 一句话总结
在 uni-app(包括微信小程序端) 中,要想获取页面元素或组件引用,必须使用 官方提供的节点查询 API:
uni.createSelectorQuery()
或者:
this.$refs + uni.createSelectorQuery().in(this)
🧩 一、使用 uni.createSelectorQuery() 获取节点信息
这是最通用、跨平台(H5 / App / 小程序)都能使用的方式。
📘 示例
<template>
<view>
<view id="box" class="my-box">Hello Box</view>
</view>
</template>
<script>
export default {
mounted() {
// 必须在节点渲染完成后(mounted / onReady)执行
const query = uni.createSelectorQuery().in(this)
query.select('#box').boundingClientRect(data => {
console.log('节点信息:', data)
/*
data = {
id: "box",
dataset: {},
left: 0,
right: 375,
top: 50,
bottom: 150,
width: 375,
height: 100
}
*/
}).exec()
}
}
</script>
<style>
.my-box {
width: 200rpx;
height: 100rpx;
background-color: pink;
}
</style>
📌 说明
-
uni.createSelectorQuery()类似于浏览器的document.querySelector(); -
但它返回的不是 DOM 节点,而是 节点的布局信息(宽度、高度、坐标等);
-
查询必须在 节点渲染完成 后执行,否则会返回
null。
🧩 二、获取组件实例(类似 Vue 的 $refs)
在 uni-app 中,同样支持 Vue 的 ref 属性,但用法略有区别。
📘 示例
<template>
<view>
<custom-child ref="childRef"></custom-child>
<view ref="myView">我是 view 元素</view>
</view>
</template>
<script>
export default {
mounted() {
// ✅ 获取自定义组件实例
console.log(this.$refs.childRef) // 输出组件实例
// ⚠️ 获取原生节点(view 等)信息,不能直接 this.$refs.myView
const query = uni.createSelectorQuery().in(this)
query.select('#myView').boundingClientRect(res => {
console.log('view 节点信息:', res)
}).exec()
}
}
</script>
📌 要点总结
| 类型 | 获取方式 | 可否用 $refs |
说明 |
|---|---|---|---|
自定义组件 <custom-child> |
this.$refs.xxx |
✅ 可以 | 返回组件实例 |
原生节点 <view> / <scroll-view> |
uni.createSelectorQuery() |
❌ 不行 | 返回节点信息对象 |
🧩 三、常见场景示例
1️⃣ 获取滚动条位置
const query = uni.createSelectorQuery().in(this)
query.select('.scroll-view').scrollOffset(res => {
console.log('滚动位置:', res.scrollTop)
}).exec()
2️⃣ 获取节点尺寸、坐标
query.select('.item').boundingClientRect(res => {
console.log('节点宽高:', res.width, res.height)
}).exec()
🧩 四、常见 API 对比表
| 功能 | Web 写法 | uni-app 对应写法 |
|---|---|---|
| 获取元素 | document.querySelector() |
uni.createSelectorQuery() |
| 获取元素尺寸 | element.getBoundingClientRect() |
.boundingClientRect() |
| 获取滚动偏移 | element.scrollTop |
.scrollOffset() |
| 获取组件实例 | this.$refs.xxx |
同样可用(仅限自定义组件) |
| 不存在的对象 | window、document、HTMLElement |
❌ 无法使用 |
🧩 五、实战示例:滚动到指定元素
<template>
<scroll-view scroll-y :scroll-top="scrollTop">
<view id="target" style="height: 800rpx; background: skyblue;">
我是目标区域
</view>
<view style="height: 800rpx; background: pink;"></view>
</scroll-view>
<button @click="goToTarget">滚动到目标</button>
</template>
<script>
export default {
data() {
return {
scrollTop: 0
}
},
methods: {
goToTarget() {
const query = uni.createSelectorQuery().in(this)
query.select('#target').boundingClientRect(res => {
this.scrollTop = res.top
}).exec()
}
}
}
</script>
🧩 六、封装一个通用工具函数
为了简化开发,可以封装一个通用的 getElementRect() 函数:
// utils/dom.js
export function getElementRect(ctx, selector) {
return new Promise(resolve => {
const query = uni.createSelectorQuery().in(ctx)
query.select(selector).boundingClientRect(res => {
resolve(res)
}).exec()
})
}
使用示例:
import { getElementRect } from '@/utils/dom.js'
export default {
async mounted() {
const rect = await getElementRect(this, '#myBox')
console.log('元素位置与尺寸:', rect)
}
}
⚡ 注意事项
-
必须等待渲染完成后调用 (
mounted或onReady); -
查询链式调用最后必须执行
.exec(); -
如果使用 Vue 3 的
<script setup>语法,可通过getCurrentInstance()获取实例:import { getCurrentInstance } from 'vue'
const { proxy } = getCurrentInstance()
const query = uni.createSelectorQuery().in(proxy)
uni.createSelectorQuery() 在 H5、App、小程序多端兼容。
🎯 总结
| 场景 | 推荐方法 |
|---|---|
| 获取节点宽高、坐标 | uni.createSelectorQuery().boundingClientRect() |
| 获取滚动位置 | .scrollOffset() |
| 获取自定义组件实例 | this.$refs.xxx |
| 组合使用(复杂页面) | uni.createSelectorQuery().in(this) |
🔁 结语:
在小程序环境中,不能直接操作 DOM。
学会使用
uni.createSelectorQuery()才是真正理解小程序渲染机制的关键。它既安全、性能稳定,又能跨多端使用,是替代 Web DOM 操作的核心手段。