uni-app 自定义组件中使用uni.createSelectorQuery()获取节点信息在屏幕翻转后信息不正确

发布于 1周前 作者 nodeper 来自 Uni-App

uni-app 自定义组件中使用uni.createSelectorQuery()获取节点信息在屏幕翻转后信息不正确

项目信息 详情
产品分类 uniapp/App
PC开发环境操作系统 Windows
PC开发环境操作系统版本号 Win10
HBuilderX类型 正式
HBuilderX版本号 4.28
手机系统 Android
手机系统版本号 Android 10
手机厂商 小米
手机机型 Redmi
页面类型 vue
vue版本 vue3
打包方式 云端
项目创建方式 HBuilderX

示例代码:

const GetRect = (selector : string, context ?: any, all = false) => {
return new Promise((resolve, reject) => {
try {
let query = uni.createSelectorQuery();
if (context) {
query = uni.createSelectorQuery().in(context);
}
query[all ? "selectAll" : "select"]
.boundingClientRect(function (rect) {
if (all && rect && Array.isArray(rect) && rect.length) {
resolve(rect);
}
if (!all && rect) {
resolve(rect);
}
resolve(rect);
})
.exec();
} catch (e) {
//TODO handle the exception
}
});
}

const calcScrollXWidth = async () => {
const rect = await GetRect(`#cont-box-${formId.value}`, proxy, true);
console.log('cont-box', rect)
if (rect) {
let maxRect = 0
if (Array.isArray(rect)) {
rect.forEach((item) => {
if (!maxRect) {
maxRect = item.width
} else if (maxRect < item.width) {
maxRect = item.width
}
})
}
if (maxRect) {
scorllXWidth.value = maxRect
}
}
}

操作步骤:

将屏幕从横屏翻转为竖屏后使用 uni.createSelectorQuery()获取节点的宽高

预期结果:

获取当前屏幕状态下的节点宽高

实际结果:

取到的是横屏下的宽高

bug描述:

在使用uni.createSelectorQuery()获取自定义组件的节点宽度和高度时,屏幕先由竖屏翻转为横屏此时获取的宽高是正确的,从横屏翻转为竖屏此时再获取宽高就一直是横屏时的宽高


2 回复

折叠屏竖屏 请求 createQuerySelector 查询正常,切换为横屏之后查询正常,再切换为竖屏不正常是吗?如果不是请具体描述一下场景。
如果等两秒再请求是否正常?请排查下是功能有延迟,还是功能调整几次之后功能坏了


在 uni-app 中,如果你在自定义组件中使用 uni.createSelectorQuery() 获取节点信息,并且在屏幕翻转后发现获取的信息不正确,这通常是因为页面布局在屏幕翻转后发生了变化,但查询操作可能还在旧的布局状态下执行。为了解决这个问题,你需要在屏幕翻转事件后重新执行节点查询。

以下是一个示例代码,展示如何在自定义组件中处理屏幕翻转事件并重新获取节点信息:

<template>
  <view class="container">
    <view ref="targetNode" class="target-node">Target Node</view>
  </view>
</template>

<script>
export default {
  data() {
    return {
      nodeInfo: null,
    };
  },
  methods: {
    queryNodeInfo() {
      const query = uni.createSelectorQuery().in(this);
      query.select('#targetNode').boundingClientRect(data => {
        this.nodeInfo = data;
        console.log('Node Info:', data);
      }).exec();
    },
    handleOrientationChange() {
      // 清空旧信息,准备获取新信息
      this.nodeInfo = null;
      this.queryNodeInfo();
    },
  },
  mounted() {
    // 初始查询
    this.queryNodeInfo();

    // 监听屏幕翻转事件
    const page = getCurrentPages()[getCurrentPages().length - 1];
    if (page) {
      const orientationChangeHandler = this.handleOrientationChange;
      page.onOrientationChange = orientationChangeHandler; // 假设uni-app支持直接给页面对象添加事件监听(注意:实际使用可能需要调整)

      // 如果需要,也可以监听系统级的resize事件(注意性能影响)
      // window.addEventListener('resize', orientationChangeHandler);

      // 在组件卸载时移除监听器
      this.$once('hook:beforeDestroy', () => {
        if (page.onOrientationChange === orientationChangeHandler) {
          delete page.onOrientationChange;
        }
        // 如果添加了window的resize监听器,也需要移除
        // window.removeEventListener('resize', orientationChangeHandler);
      });
    }
  },
};
</script>

<style>
.container {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100vh;
}
.target-node {
  width: 100px;
  height: 100px;
  background-color: red;
}
</style>

注意

  1. getCurrentPages() 和直接给 page 对象添加事件监听器的方式可能需要根据实际 uni-app 的版本和特性进行调整。如果 onOrientationChange 不是页面对象的有效属性,你可能需要寻找其他方式来监听屏幕翻转事件,例如使用 uni.onWindowResize(如果存在)。
  2. 组件中直接操作页面对象可能不是最佳实践,但在某些情况下可能是必要的。通常,更好的做法是使用全局状态管理或事件总线来处理这类跨组件/页面的通信。
回到顶部