createSelectorQuery获取元素对象
在 uni-app 中,通过 uni.createSelectorQuery() 获取到的元素对象是一个包含DOM元素各种信息的纯对象,不是真实的DOM节点,而是经过封装的描述对象。
如何获取
// 获取元素对象
const query = uni.createSelectorQuery()
query.select('#box').fields({
size: true,
rect: true
}, (elementObject) => {
console.log(elementObject) // 这就是元素对象
}).exec()
元素对象示例:
{
id: "module-123", // 元素ID
dataset: { // 自定义属性
type: "category",
index: "1"
},
left: 0, // 左边距
right: 375, // 右边距
top: 100, // 上边距
bottom: 300, // 下边距
width: 375, // 宽度
height: 200, // 高度
scrollLeft: 0, // 水平滚动位置
scrollTop: 50 // 垂直滚动位置
}
与浏览器DOM对象的区别
// 浏览器中的真实DOM对象
const dom = document.getElementById('box')
console.log(dom.offsetHeight) // 真实高度
console.log(dom.classList) // 类名列表
console.log(dom.style) // 样式对象
dom.innerHTML = '新内容' // 可以直接修改
// uni-app中的元素对象
const element = {
width: 375, // 只有数据
height: 200, // 只有数据
top: 100 // 只有数据
// ❌ 没有方法可以修改DOM
// ❌ 不能直接操作元素
}
选择DOM元素
.select()- 获取单个元素
// 选择第一个匹配的元素
uni.createSelectorQuery()
.select('.group') // 只选择第一个 class="group" 的元素
.fields({size: true}, (data) => {
console.log('单个元素:', data);
// 输出: { width: 375, height: 200 }
console.log('高度:', data.height); // 直接使用
})
.exec();
// HTML结构:
<view class="group">红酒</view> ← 只会选择这个
<view class="group">白酒</view> ← 忽略
<view class="group">啤酒</view> ← 忽略
.selectAll() - 获取所有元素
// 选择所有匹配的元素
uni.createSelectorQuery()
.selectAll('.group') // 选择所有 class="group" 的元素
.fields({size: true}, (dataArray) => {
console.log('所有元素:', dataArray);
// 输出: [
// { width: 375, height: 200 },
// { width: 375, height: 150 },
// { width: 375, height: 180 }
// ]
// 需要遍历数组使用
dataArray.forEach((data, index) => {
console.log(`第${index+1}个高度:`, data.height);
});
})
.exec();
.select() VS .selectAll()
基本区别对比
| 特性 | .select() |
.selectAll() |
|---|---|---|
| 选择方式 | 选择第一个匹配的元素 | 选择所有匹配的元素 |
| 返回结果 | 单个元素对象 | 元素对象数组 |
| 回调参数 | (data) => {} 单个对象 |
(dataArray) => {} 对象数组 |
| 适用场景 | 需要唯一元素时 | 需要遍历多个同类元素时 |
性能考虑
// 场景:有100个商品需要获取高度
// 方式1:使用 .select() 循环(100次查询)
for(let i = 0; i < 100; i++) {
uni.createSelectorQuery()
.select(`#goods-${i}`)
.fields({size: true}, (data) => {})
.exec(); // 执行100次查询,性能差
}
// 方式2:使用 .selectAll()(1次查询)
uni.createSelectorQuery()
.selectAll('.goods-item') // 一次查询获取所有
.fields({size: true}, (dataArray) => {
// 一次回调处理所有数据
})
.exec(); // 只执行1次查询,性能好
选择器的使用建议
// 1. 需要唯一元素时用 .select()
.select('#module-123') // ✅ ID是唯一的
.select('.page-title') // ⚠️ 如果只有一个标题也可以用
// 2. 需要多个同类元素时用 .selectAll()
.selectAll('.goods-item') // ✅ 多个商品
.selectAll('.group') // ✅ 多个分类
.selectAll('view') // ⚠️ 太宽泛,不推荐
// 3. 混合使用
const query = uni.createSelectorQuery();
// 获取标题(唯一)
query.select('.header').fields({size: true});
// 获取列表项(多个)
query.selectAll('.list-item').fields({size: true});
query.exec(); // 一次执行
选择器语法
ID选择器(最常用)
// 选择 id="module-123" 的元素
.select('#module-123')
// 在你的代码中
.select(`#module-${item._id}`) // 动态ID
类选择器
// 选择 class="group" 的元素
.select('.group')
// 选择 class="item active" 的元素
.select('.item.active')
标签选择器
// 选择第一个 <view> 元素
.select('view')
// 选择第一个 <image> 元素
.select('image')
属性选择器
// 选择有 type 属性的元素
.select('[type]')
// 选择 type="category" 的元素
.select('[type="category"]')
// 选择 data-id 以 "00" 开头的元素
.select('[data-id^="00"]')
层级选择器
// 选择 .group 下的 .name 元素
.select('.group .name')
// 选择 #module-123 下的第一个 view
.select('#module-123 view:first-child')
选择器性能
// ID选择器最快
.select('#module-123') // ✅ 推荐,性能最好
// 类选择器次之
.select('.group') // ⚠️ 性能中等
// 属性选择器较慢
.select('[data-type="category"]') // ⚠️ 性能较差
// 复杂层级选择器最慢
.select('.group .list .item:first-child') // ⚠️ 性能最差
动态内容的选择
// 如果是动态渲染的内容,需要等待DOM更新
const showElement = ref(false);
const handleClick = async () => {
showElement.value = true; // 动态显示元素
// 等待DOM更新
await nextTick();
// 现在可以选择了
uni.createSelectorQuery()
.select('#dynamic-element')
.fields({size: true}, (data) => {
console.log('动态元素高度:', data.height);
})
.exec();
}
通过 fields 配置获取的属性
基本语法
view.fields({
id: true, // 是否获取元素id
rect: true, // 是否获取元素布局位置(left, top, right, bottom)
size: true, // 是否获取元素尺寸(width, height)
scrollOffset: true, // 是否获取滚动偏移(scrollLeft, scrollTop)
dataset: true, // 是否获取自定义属性(data-*)
}, (data) => {
// 回调函数,data包含请求的信息
console.log(data);
}).exec();
第一个参数:配置对象
// 可以同时请求多种信息
view.fields({
id: true, // 元素id
rect: true, // 位置信息
size: true, // 尺寸信息
scrollOffset: true, // 滚动偏移
dataset: true, // 自定义数据属性
properties: ['src', 'alt'] // 指定属性(如img的src)
}, (data) => {})
第二个参数:回调函数
view.fields({size: true}, (data) => {
// 当查询成功时,回调函数被调用
// data 包含请求的信息
console.log(data);
})
data 就是通过 fields 请求获取的元素信息对象。data 的内容由 fields 的参数决定
// 当你这样请求时:
view.fields({size: true}, (data) => {
console.log(data)
}).exec()
// data 就是包含元素尺寸信息的对象
// data = {
// width: 375, // 元素宽度
// height: 200 // 元素高度
// }
// 请求 rect
view.fields({rect: true}, (data) => {
// data 只包含位置信息
console.log(data)
// 输出: {
// left: 0, // 左边距
// right: 375, // 右边距
// top: 100, // 上边距
// bottom: 300, // 下边距
// width: 375, // 宽度(也包含)
// height: 200 // 高度(也包含)
// }
})
.exec()
.exec() 的本质
.exec() 是 执行查询 的方法,它的作用是触发并执行之前定义的所有选择器查询。
// 1. 创建查询对象
const query = uni.createSelectorQuery();
// 2. 定义查询(只是定义,还没执行)
query.select('#box').fields({size: true}, (data) => {
console.log('获取到数据:', data);
});
// 3. .exec() 执行查询(真正开始查询)
query.exec(); // 必须调用,否则回调永远不会执行
两种写法
// 写法1:分开写
const query = uni.createSelectorQuery();
const view = query.select('#module-123');
view.fields({size: true}, (data) => {
console.log('数据:', data);
});
query.exec(); // 最后执行
// 写法2:链式写(常用)
uni.createSelectorQuery()
.select('#module-123')
.fields({size: true}, (data) => {
console.log('数据:', data);
})
.exec(); // 链式结尾
多个查询共用一个 .exec()
// 一次 exec 可以执行多个查询
const query = uni.createSelectorQuery();
// 查询1
query.select('#module-001').fields({size: true}, (data1) => {
console.log('第一个元素:', data1);
});
// 查询2
query.select('#module-002').fields({size: true}, (data2) => {
console.log('第二个元素:', data2);
});
// 查询3
query.selectAll('.group').fields({size: true}, (data3) => {
console.log('所有group:', data3);
});
// 一次 exec 执行所有查询
query.exec(); // 上面的3个回调都会执行
.exec() 的参数
// .exec() 可以接收一个回调函数
uni.createSelectorQuery()
.select('#box')
.fields({size: true})
.exec((results) => {
// results 是所有查询结果的数组
console.log('所有结果:', results);
});
// 等同于:
const query = uni.createSelectorQuery();
query.select('#box').fields({size: true});
query.exec((results) => {
console.log(results); // [ {width: 375, height: 200} ]
});
属性详细说明
id - 元素ID
<view id="module-123">内容</view>
// 获取id
query.select('#module-123').fields({id: true}, (elementObj) => {
console.log(elementObj.id) // "module-123"
}).exec()
dataset - 自定义属性
<view
id="box"
data-type="category"
data-user-id="1001"
data-index="3"
>
分类
</view>
query.select('#box').fields({dataset: true}, (elementObj) => {
console.log(elementObj.dataset)
// 输出: {
// type: "category",
// userId: "1001", // data-user-id 转成 userId
// index: "3"
// }
}).exec()
rect - 位置信息
query.select('#box').fields({rect: true}, (elementObj) => {
console.log('左边距:', elementObj.left) // 元素左边界到视口左边
console.log('右边距:', elementObj.right) // 元素右边界到视口左边
console.log('上边距:', elementObj.top) // 元素上边界到视口顶部
console.log('下边距:', elementObj.bottom) // 元素下边界到视口顶部
}).exec()
// 可视化的位置关系:
// 视口顶部(0)
// ↓
// ┌─────────────────┐
// │ │ ← top: 100px
// │ 元素区域 │
// │ │ ← bottom: 300px
// └─────────────────┘
// ← left: 0px → ← right: 375px →
size - 尺寸信息
query.select('#box').fields({size: true}, (elementObj) => {
console.log('宽度:', elementObj.width) // 元素宽度
console.log('高度:', elementObj.height) // 元素高度
}).exec()
scrollOffset - 滚动信息
// 用于可滚动元素(scroll-view)
query.select('.scroll-view').fields({scrollOffset: true}, (elementObj) => {
console.log('水平滚动距离:', elementObj.scrollLeft)
console.log('垂直滚动距离:', elementObj.scrollTop)
}).exec()
properties - 指定属性
// 获取图片的特定属性
query.select('img').fields({
properties: ['src', 'alt', 'width', 'height']
}, (elementObj) => {
console.log('图片地址:', elementObj.src)
console.log('图片描述:', elementObj.alt)
}).exec()