{"version":3,"file":"useAffix.mjs","sources":["../../../src/table/hooks/useAffix.ts"],"sourcesContent":["import isBoolean from 'lodash/isBoolean';\nimport { computed, ref, watch, onBeforeMount } from 'vue';\nimport { TdBaseTableProps } from '../type';\nimport { on, off } from '../../utils/dom';\nimport { AffixProps } from '../../affix';\n\n/**\n * 1. 表头吸顶（普通表头吸顶 和 虚拟滚动表头吸顶）\n * 2. 表尾吸底\n * 3. 底部滚动条吸底\n * 4. 分页器吸底\n */\nexport default function useAffix(props: TdBaseTableProps) {\n  const tableContentRef = ref<HTMLDivElement>();\n  // 吸顶表头\n  const affixHeaderRef = ref<HTMLDivElement>();\n  // 吸底表尾\n  const affixFooterRef = ref<HTMLDivElement>();\n  // 吸底滚动条\n  const horizontalScrollbarRef = ref<HTMLDivElement>();\n  // 吸底分页器\n  const paginationRef = ref<HTMLDivElement>();\n  // 当表格完全滚动消失在视野时，需要隐藏吸顶表头\n  const showAffixHeader = ref(true);\n  // 当表格完全滚动消失在视野时，需要隐藏吸底尾部\n  const showAffixFooter = ref(true);\n  // 当表格完全滚动消失在视野时，需要隐藏吸底分页器\n  const showAffixPagination = ref(true);\n\n  const isVirtualScroll = computed(\n    () => props.scroll && props.scroll.type === 'virtual' && (props.scroll.threshold || 100) < props.data.length,\n  );\n\n  const isAffixed = computed(\n    () => !!(props.headerAffixedTop || props.footerAffixedBottom || props.horizontalScrollAffixedBottom),\n  );\n\n  let lastScrollLeft = 0;\n  const onHorizontalScroll = (scrollElement?: HTMLElement) => {\n    if (!isAffixed.value && !isVirtualScroll.value) return;\n    let target = scrollElement;\n    if (!target && tableContentRef.value) {\n      lastScrollLeft = 0;\n      target = tableContentRef.value;\n    }\n    if (!target) return;\n    const left = target.scrollLeft;\n    // 如果 lastScrollLeft 等于 left，说明不是横向滚动，不需要更新横向滚动距离\n    if (lastScrollLeft === left) return;\n    lastScrollLeft = left;\n    // 表格内容、吸顶表头、吸底表尾、吸底横向滚动更新\n    const toUpdateScrollElement = [\n      tableContentRef.value,\n      affixHeaderRef.value,\n      affixFooterRef.value,\n      horizontalScrollbarRef.value,\n    ];\n    for (let i = 0, len = toUpdateScrollElement.length; i < len; i++) {\n      if (toUpdateScrollElement[i] && scrollElement !== toUpdateScrollElement[i]) {\n        toUpdateScrollElement[i].scrollLeft = left;\n      }\n    }\n  };\n\n  // 吸底的元素（footer、横向滚动条、分页器）是否显示\n  const isAffixedBottomElementShow = (elementRect: DOMRect, tableRect: DOMRect, headerHeight: number) =>\n    tableRect.top + headerHeight < elementRect.top && elementRect.top > elementRect.height;\n\n  const getOffsetTop = (props: boolean | AffixProps) => {\n    if (isBoolean(props)) return 0;\n    return props.offsetTop || 0;\n  };\n\n  const updateAffixHeaderOrFooter = () => {\n    if (!isAffixed.value && !isVirtualScroll.value) return;\n    const pos = tableContentRef.value?.getBoundingClientRect();\n    const headerRect = tableContentRef.value?.querySelector('thead')?.getBoundingClientRect();\n    const headerHeight = headerRect?.height || 0;\n    const footerRect = affixFooterRef.value?.getBoundingClientRect();\n    if ((props.headerAffixedTop || isVirtualScroll.value) && affixHeaderRef.value) {\n      const offsetTop = getOffsetTop(props.headerAffixProps || props.headerAffixedTop);\n      const footerHeight = footerRect?.height || 0;\n      let r = Math.abs(pos.top) < pos.height - headerHeight - offsetTop - footerHeight;\n      // 如果是虚拟滚动的表头，只要表头在可视区域内，一律永久显示（虚拟滚动表头 和 吸顶表头可能同时存在）\n      if (isVirtualScroll.value) {\n        r = pos.top > -1 * headerRect.height;\n      }\n      showAffixHeader.value = r;\n    }\n    // 底部内容吸底 和 底部滚动条吸底，不可能同时存在，二选一即可\n    if (props.footerAffixedBottom && affixFooterRef?.value) {\n      showAffixFooter.value = isAffixedBottomElementShow(footerRect, pos, headerHeight);\n    } else if (props.horizontalScrollAffixedBottom && horizontalScrollbarRef?.value) {\n      const horizontalScrollbarRect = horizontalScrollbarRef.value.getBoundingClientRect();\n      showAffixFooter.value = isAffixedBottomElementShow(horizontalScrollbarRect, pos, headerHeight);\n    }\n    if (props.paginationAffixedBottom && paginationRef.value) {\n      const pageRect = paginationRef.value.getBoundingClientRect();\n      showAffixPagination.value = isAffixedBottomElementShow(pageRect, pos, headerHeight);\n    }\n  };\n\n  const onDocumentScroll = () => {\n    updateAffixHeaderOrFooter();\n  };\n\n  const onFootScroll = () => {\n    onHorizontalScroll(affixFooterRef.value);\n  };\n\n  const onHeaderScroll = () => {\n    onHorizontalScroll(affixHeaderRef.value);\n  };\n\n  const horizontalScrollbarScroll = () => {\n    onHorizontalScroll(horizontalScrollbarRef.value);\n  };\n\n  const onTableContentScroll = () => {\n    onHorizontalScroll(tableContentRef.value);\n  };\n\n  const onFootMouseEnter = () => {\n    on(affixFooterRef.value, 'scroll', onFootScroll);\n  };\n\n  const onFootMouseLeave = () => {\n    off(affixFooterRef.value, 'scroll', onFootScroll);\n  };\n\n  const onHeaderMouseEnter = () => {\n    on(affixHeaderRef.value, 'scroll', onHeaderScroll);\n  };\n\n  const onHeaderMouseLeave = () => {\n    off(affixHeaderRef.value, 'scroll', onHeaderScroll);\n  };\n\n  const onScrollbarMouseEnter = () => {\n    on(horizontalScrollbarRef.value, 'scroll', horizontalScrollbarScroll);\n  };\n\n  const onScrollbarMouseLeave = () => {\n    off(horizontalScrollbarRef.value, 'scroll', horizontalScrollbarScroll);\n  };\n\n  const onTableContentMouseEnter = () => {\n    on(tableContentRef.value, 'scroll', onTableContentScroll);\n  };\n\n  const onTableContentMouseLeave = () => {\n    off(tableContentRef.value, 'scroll', onTableContentScroll);\n  };\n\n  const addHorizontalScrollListeners = () => {\n    if (affixHeaderRef.value) {\n      on(affixHeaderRef.value, 'mouseenter', onHeaderMouseEnter);\n      on(affixHeaderRef.value, 'mouseleave', onHeaderMouseLeave);\n    }\n\n    if (props.footerAffixedBottom && affixFooterRef.value) {\n      on(affixFooterRef.value, 'mouseenter', onFootMouseEnter);\n      on(affixFooterRef.value, 'mouseleave', onFootMouseLeave);\n    }\n\n    if (props.horizontalScrollAffixedBottom && horizontalScrollbarRef.value) {\n      on(horizontalScrollbarRef.value, 'mouseenter', onScrollbarMouseEnter);\n      on(horizontalScrollbarRef.value, 'mouseleave', onScrollbarMouseLeave);\n    }\n\n    if ((isAffixed.value || isVirtualScroll.value) && tableContentRef.value) {\n      on(tableContentRef.value, 'mouseenter', onTableContentMouseEnter);\n      on(tableContentRef.value, 'mouseleave', onTableContentMouseLeave);\n    }\n  };\n\n  const removeHorizontalScrollListeners = () => {\n    if (affixHeaderRef.value) {\n      off(affixHeaderRef.value, 'mouseenter', onHeaderMouseEnter);\n      off(affixHeaderRef.value, 'mouseleave', onHeaderMouseLeave);\n    }\n    if (affixFooterRef.value) {\n      off(affixFooterRef.value, 'mouseenter', onFootMouseEnter);\n      off(affixFooterRef.value, 'mouseleave', onFootMouseLeave);\n    }\n    if (tableContentRef.value) {\n      off(tableContentRef.value, 'mouseenter', onTableContentMouseEnter);\n      off(tableContentRef.value, 'mouseleave', onTableContentMouseLeave);\n    }\n    if (horizontalScrollbarRef.value) {\n      off(horizontalScrollbarRef.value, 'mouseenter', onScrollbarMouseEnter);\n      off(horizontalScrollbarRef.value, 'mouseleave', onScrollbarMouseLeave);\n    }\n  };\n\n  const addVerticalScrollListener = () => {\n    if (!isAffixed.value && !props.paginationAffixedBottom) return;\n    const timer = setTimeout(() => {\n      if (isAffixed.value || props.paginationAffixedBottom) {\n        on(document, 'scroll', onDocumentScroll);\n      } else {\n        off(document, 'scroll', onDocumentScroll);\n      }\n      clearTimeout(timer);\n    });\n  };\n\n  watch([affixHeaderRef, affixFooterRef, horizontalScrollbarRef, tableContentRef], () => {\n    addHorizontalScrollListeners();\n    onHorizontalScroll();\n    updateAffixHeaderOrFooter();\n  });\n\n  watch(isAffixed, addVerticalScrollListener);\n\n  watch(\n    () => [\n      props.data,\n      props.columns,\n      props.headerAffixedTop,\n      props.footerAffixedBottom,\n      props.horizontalScrollAffixedBottom,\n    ],\n    () => {\n      onHorizontalScroll();\n    },\n  );\n\n  onBeforeMount(() => {\n    off(document, 'scroll', onDocumentScroll);\n    removeHorizontalScrollListeners();\n  });\n\n  const setTableContentRef = (tableContent: HTMLDivElement) => {\n    tableContentRef.value = tableContent;\n    addVerticalScrollListener();\n  };\n\n  return {\n    showAffixHeader,\n    showAffixFooter,\n    showAffixPagination,\n    affixHeaderRef,\n    affixFooterRef,\n    horizontalScrollbarRef,\n    paginationRef,\n    onHorizontalScroll,\n    setTableContentRef,\n    updateAffixHeaderOrFooter,\n  };\n}\n"],"names":["lastScrollLeft","toUpdateScrollElement","isBoolean","updateAffixHeaderOrFooter","onHorizontalScroll","on","off","addHorizontalScrollListeners","watch","onBeforeMount","removeHorizontalScrollListeners","addVerticalScrollListener","showAffixHeader","showAffixFooter","showAffixPagination","affixHeaderRef","affixFooterRef","horizontalScrollbarRef","paginationRef","setTableContentRef"],"mappings":"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"}