Skip to content

弹出定位测量 useFloatingPosition

为弹出类组件提供统一测量骨架的组合式函数

该组合式函数被 SelectAutoCompleteTooltip 等弹出类组件内部使用,负责定位容器查询与矩形测量;也可独立复用。

它只负责「量」,不负责「往哪弹」:翻转算法、对齐几何、遮挡边界等定位决策因组件需求不同,刻意保留在各组件层。

Show Source Code
ts
import { ref, nextTick } from 'vue'
import type { Ref } from 'vue'
export function useFloatingPosition(
  contentRef: Ref<HTMLElement | null>,
  panelRef: Ref<HTMLElement | null>
): {
  positionedContainerRect: Ref<DOMRect | undefined>
  contentRect: Ref<DOMRect | undefined>
  measure: () => Promise<void>
} {
  const positionedContainer = ref<HTMLElement | null>(null) // 弹出框相对定位的容器元素
  const positionedContainerRect = ref<DOMRect>() // positionedContainer 元素的大小及其相对于视口的位置
  const contentRect = ref<DOMRect>() // 内容元素的大小及其相对于视口的位置

  // 获取弹出框相对定位的容器元素
  function getPositionedContainer(): void {
    let parentElement = panelRef.value?.parentElement
    while (parentElement) {
      if (parentElement === document.documentElement) {
        positionedContainer.value = document.documentElement
        return
      }
      const { position } = getComputedStyle(parentElement)
      if (position !== 'static') {
        positionedContainer.value = parentElement
        return
      }
      parentElement = parentElement.parentElement
    }
  }

  // 在 nextTick 后测量定位容器与内容元素的视口矩形
  async function measure(): Promise<void> {
    await nextTick()
    getPositionedContainer()
    positionedContainerRect.value = positionedContainer.value?.getBoundingClientRect() as DOMRect
    contentRect.value = contentRef.value?.getBoundingClientRect() as DOMRect
  }

  return { positionedContainerRect, contentRect, measure }
}

基本使用

测量弹出面板的定位容器与内容元素矩形

vue
<script setup lang="ts">
import { ref } from 'vue'
import { useFloatingPosition } from 'vue-amazing-ui'
const contentRef = ref<HTMLElement | null>(null)
const panelRef = ref<HTMLElement | null>(null)
const { positionedContainerRect, contentRect, measure } = useFloatingPosition(contentRef, panelRef)
measure()
</script>
<template>
  <div>
    <button ref="contentRef">触发器</button>
    <div ref="panelRef" class="panel">弹出面板</div>
  </div>
</template>

Params

参数说明类型默认值
contentRef触发器内容元素Ref<HTMLElement | null>undefined
panelRef弹出面板,同时作为定位容器的查询起点Ref<HTMLElement | null>undefined

Return

名称说明类型
positionedContainerRect定位容器元素的大小及其相对于视口的位置Ref<DOMRect | undefined>
contentRect内容元素的大小及其相对于视口的位置Ref<DOMRect | undefined>
measurenextTick 后测量定位容器与内容元素的视口矩形() => Promise<void>

Released under the MIT License.