因为之前的头部置顶1.0存在一些问题。当头部上方还须要置顶一些其余货色时,比方导出案件、筛选框、搜寻框、题目等等时,之前的代码不够灵便,没有设置置顶的偏移量。当页面内关上抽屉反复利用table时,也会存在问题,因为里面的滚动曾经让头部置顶了,关上抽屉时,table的head仍然在,并且会遮挡数据。
因而重写了置顶的js代码,通过监听对应dom的滚动,而不是监听window。
// 判断是否呈现滚动条function hasScrolled(el: HTMLElement, direction = 'vertical') { if (direction === 'vertical') { return el.scrollHeight > el.clientHeight; } else if (direction === 'horizontal') { return el.scrollWidth > el.clientWidth; }}// 找到有滚动条的domfunction findScrollDom(el: HTMLElement) { if (!el) return null; const isScrolled = hasScrolled(el); if (isScrolled) { return el; } const pEl = el.parentElement; if (pEl) { return findScrollDom(pEl); } else { return null; }}
function useListenerScroll() { const containerRef = ref(); const isFixed = ref(false); const width = ref('100%'); // 置顶容易的宽度 const top = ref('51px'); // 默认的定位高度,导航栏高度 const titleHeight = ref(0); // head上放的title或其余操作的容器高度 const initEvent = async () => { await nextTick(); // 如果table组件为空,递归调用 if (!containerRef.value) { initEvent(); return; } // 找到滚动容器 const scrollDom = findScrollDom(containerRef.value); if (scrollDom) { const titleDom = scrollDom.getElementsByClassName('table-title-content'); // 获取title内容高度 if (titleDom[0]) titleHeight.value = titleDom[0].clientHeight; else titleHeight.value = 0; scrollDom.addEventListener('scroll', listenerScroll); top.value = scrollDom.offsetTop + 'px'; } }; function listenerScroll(event: any) { const $el = event.target; if ($el) { const scrollTop = $el.scrollTop; const fixedDom = $el.getElementsByClassName('table-content'); if (fixedDom.length) { const dom = fixedDom[0]; const domTop = dom.offsetTop - titleHeight.value - 51; // 滚动高度大于设定高度时,置顶头部 if (scrollTop > domTop) { isFixed.value = true; } if (scrollTop < domTop) { isFixed.value = false; width.value = dom.clientWidth + 'px'; } } } } return { top, width, isFixed, containerRef, initEvent, };}
<template> <div ref="containerRef"> <div :style="fixedHeaderStyle"> <div class="table-title-content" v-if="$slots['w1-title'] || title"> <span v-if="title">{{ title }}</span> <slot name="title" /> </div> <div> <a-table :pagination="false" v-bind="$attrs" :data-source="[]" > <template #[item]="data" v-for="item in Object.keys($slots)"> <slot :name="item" v-bind="data" /> </template> </a-table> </div> </div> <a-table class="table-content" v-bind="$attrs" :dataSource="dataSource" v-loading="loading" > <template #[item]="data" v-for="item in Object.keys($slots)"> <slot :name="item" v-bind="data"> </slot> </template> </a-table> </div></template><script lang="ts"> import { computed, defineComponent, onMounted } from 'vue'; import { isFunction } from '/@/utils/is'; import useListenerScroll from './hooks/useListenerScroll'; export default defineComponent({ props: { dataSource: { type: Array, }, loading: { type: Boolean, }, title: { type: String, }, }, setup(props) { const { isFixed, containerRef, initEvent, width, top } = useListenerScroll(); const fixedHeaderStyle = computed(() => ({ position: isFixed.value ? 'fixed' : 'relative', top: isFixed.value ? top.value : 0, zIndex: isFixed.value ? 19 : 0, width: width.value, })); onMounted(() => { initEvent(); }); return { isFixed, containerRef, fixedHeaderStyle, }; }, });</script>