wot-ui FloatingPanel 浮动面板动态计算展示高度

142 阅读2分钟

最近在项目中使用到了 wot-ui 的浮动面板,这个浮动面板可以设置三个可以拉伸的高度。但在官方示例中,这个三个高度是根据屏幕高度来确定的,对于中间的高度,往往应该适应浮动面板的内容高度更符合直觉。

所以,为了准确的获得这个高度,我通过浮动面板内部元素的顶部和底部元素到屏幕顶部的距离之差,得到了更精确的高度。

前言

浮动面板默认初始化后,高度是固定在底部的,所以浮动面板中的元素到屏幕顶部的距离是固定,这也是为什么我们能够通过这种方式获得更合适的显示高度的原因。

浮动面板

浮动面板主要接收两个参数:初始显示高度 height 和包含三个位置锚点数组 anchors(最小高度,中间高度,最大高度)。所以,我们需要处理的是 anchors[1] 的值。

<template>
    <wd-floating-panel v-model:height="height" :anchors="anchors" class="panel"></wd-floating-panel>
</template>

<script lang="ts" setup>
onLoad(() => { 
    windowHeight.value = uni.getSystemInfoSync().windowHeight 
    anchors.value = [100, Math.round(0.4 * windowHeight.value), Math.round(0.8 * windowHeight.value)] 
    height.value = anchors.value[1] 
})
</script>

获取高度的距离差

获取元素高度的方法主要使用 uni.getSystemInfoSy API 完成,依次获取 windowHeight 值然后进行相减就行了。

  const query = uni.createSelectorQuery();

  let panelTop: number;
  // 获取顶部元素距离顶部的高度
  query
    .select(".panel__header")
    .boundingClientRect((footerData) => {
      panelTop = footerData.top;
    })
    .exec();

  // 获取底部元素距离顶部的高度
  query
    .select(".panel__footer")
    .boundingClientRect((submitData) => {
      // 计算高度
      let distance = submitData.top - panelTop + 100;
      // 防止溢出
      distance = distance > windowHeight.value ? windowHeight.value : distance;

      // 设置锚点
      anchors.value = [100, distance, Math.round(0.8 * windowHeight.value)];
      height.value = anchors.value[1];
    })
    .exec();
});

完整代码示例

<template>
  <wd-floating-panel v-model:height="height" :anchors="anchors" class="panel">
    <view class="panel__header">浮动面板顶部元素</view>

    <view class="panel__content">
      <wd-cell-group border>
        <wd-cell v-for="item in data" :key="item" :title="item" />
      </wd-cell-group>
    </view>

    <view class="panel__footer">浮动面板底部元素</view>
  </wd-floating-panel>
</template>

<script lang="ts" setup>
import { ref } from "vue";


const height = ref<number>(0)
const windowHeight = ref<number>(0)
const anchors = ref<number[]>([])

const data = ['A', 'B', 'C', 'D', 'E', 'F', 'G']

onLoad(() => {
  windowHeight.value = uni.getSystemInfoSync().windowHeight
})

onMounted(() => {
  const query = uni.createSelectorQuery();

  let panelTop: number;
  // 获取顶部元素距离顶部的高度
  query
    .select(".panel__header")
    .boundingClientRect((footerData) => {
      panelTop = footerData.top;
    })
    .exec();

  // 获取底部元素距离顶部的高度
  query
    .select(".panel__footer")
    .boundingClientRect((submitData) => {
      // 计算高度
      let distance = submitData.top - panelTop + 100;
      // 防止溢出
      distance = distance > windowHeight.value ? windowHeight.value : distance;

      // 设置锚点
      anchors.value = [100, distance, Math.round(0.8 * windowHeight.value)];
      height.value = anchors.value[1];
    })
    .exec();
});
</script>

<style lang="scss" scoped>
.panel {
  padding: 0 28px;
}

.panel__header,
.panel__footer {
  margin-bottom: 40rpx;
  font-size: 28rpx;
  text-align: center;
}
</style>

示例效果: