uni-app:createSelectorQuery获取元素对象

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()

×

喜欢就点赞,疼爱就打赏