| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131 |
- import type { Ref } from 'vue'
- export function useTableScroll(
- elScrollBarH: Ref<HTMLElement | null>,
- tableContent: Ref<HTMLElement | null>,
- tableContainer: Ref<HTMLElement | null>,
- tableHeaderRef: Ref<HTMLElement | null>,
- isFixed: Ref<boolean>,
- ) {
- /**
- * @description: 设置滚动条的位置
- * 这里调整的是滚动条的包裹容器,他相对于表格容器来定位,
- * 而内部的实际的滚动条相对于这个容器使用tranlate来调整位置
- * 所以在调回的时候,直接把left设置为0,仍然能保持滚动条的相对位置
- * @param {*} state true:固定在可视区域,false:固定在表格容器内
- * @return {*}
- */
- const setScrollPos = (state: boolean) => {
- if (state) {
- if (!elScrollBarH.value || !tableContent.value) return
- elScrollBarH.value.style.position = 'fixed'
- // 这里去找表格的content区域,把他相对于视口的left值设置给滚动条的容器
- elScrollBarH.value.style.left =
- tableContent.value?.getBoundingClientRect().left + 'px'
- } else {
- elScrollBarH.value!.style.left = 0 + 'px'
- elScrollBarH.value!.style.position = 'absolute'
- }
- }
- /**
- * @description: 观察表格是否在可视区域,设置滚动条的对应位置
- * @param {*} entries 观察实例,包含当前观察的元素的状态
- * @return {*}
- */
- const obScroll = (entries: IntersectionObserverEntry[]) => {
- setScrollPos(entries[0].intersectionRatio > 0)
- }
- /**
- * @description: 判定当前横向滑动条是否在表格内
- * 滑动距离加可见区域高度不大于表格总高度,则说明在表格内
- * @return 是否在表格内
- */
- const isInTable = () => {
- if (!tableContent.value || !tableContainer.value) return false
- const { scrollTop, offsetHeight, scrollHeight } =
- tableContainer.value as HTMLElement
- let result = scrollTop + offsetHeight < scrollHeight
- isFixed.value = result
- return result
- }
- /**
- * @description: 初始化滑动条
- */
- const initScroll = () => {
- let sc = document.querySelector('.el-scrollbar__bar') as HTMLElement
- let header = document.querySelector('.el-table__header-wrapper')
- if (sc) {
- elScrollBarH.value = sc
- }
- if (header) {
- tableHeaderRef.value = header as HTMLElement
- }
- }
- /**
- * @description: 设置横向滑动条的位置和表头的位置
- * 只有滑动位置到达表格内部时,才需要固定横向滑动条,否则让滚动条回到原来的初始位置,即表格的底部
- * 只有滚动条超出表头的原本位置时,才固定表头
- */
- const setScrollAndHeader = () => {
- setScrollPos(isInTable())
- if (tableHeaderRef.value) {
- const { scrollTop } = tableContainer.value as HTMLElement
- let contentOffsetTop = tableContent.value!.offsetTop // 父容器距离顶部的高度
- let contentScrollHeight = tableContent.value!.scrollHeight // 整个父容器的高度
- // 超出表头原本位置时且小于整个表的高度,则固定表头
- if (
- scrollTop >= contentOffsetTop &&
- scrollTop <= contentOffsetTop + contentScrollHeight
- ) {
- tableHeaderRef.value.style.position = 'fixed'
- tableHeaderRef.value.style.top = `${tableContainer.value?.getBoundingClientRect().top}px`
- tableHeaderRef.value.style.zIndex = '666'
- } else {
- // 还原
- // 不设置top是因为在static下,top无效
- tableHeaderRef.value.style.position = 'static'
- tableHeaderRef.value.style.zIndex = '1'
- }
- }
- }
- const findScrollParent = (el: HTMLElement): HTMLElement | Window => {
- let parent = el.parentElement
- while (parent) {
- const style = window.getComputedStyle(parent)
- const overflowY = style.overflowY
- // 判断标准:
- // 1. 是可见容器(高度不为0)
- // 2. 包含滚动条(内容溢出或强制显示)
- if (
- parent.clientHeight > 0 &&
- (overflowY === 'scroll' ||
- overflowY === 'auto' ||
- (overflowY === 'visible' &&
- parent.scrollHeight > parent.clientHeight))
- ) {
- return parent
- }
- parent = parent.parentElement
- }
- // 未找到则返回window
- return window
- }
- return {
- initScroll,
- setScrollAndHeader,
- obScroll,
- setScrollPos,
- findScrollParent,
- }
- }
|