There were some problems with the previous version 1.0. The previous code was not flexible enough to set the top offset when something else needed to be placed on top of the header, such as exporting cases, filters, search boxes, titles, and so on. There is also a problem when a drawer is opened in a page and the table is reused. Since the scrolling outside has put the head at the top, when the drawer is opened, the head of the table is still there, and the data is obscured.

So I rewrote the top JS code by listening for scrolling in the corresponding DOM instead of listening for the window.

// Roller bar function hasSrolled (el: HTMLElement, direction = 'vertical') { if (direction === 'vertical') { return el.scrollHeight > el.clientHeight; } else if (direction === 'horizontal') { return el.scrollWidth > el.clientWidth; }} function 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'); // The default height is const titleHeight = ref(0); Const initEvent = async () => {await nextTick(); // If the table component is empty, recursively call if (! containerRef.value) { initEvent(); return; } const scrollDom = findScrollDom(containerRef. Value); if (scrollDom) { const titleDom = scrollDom.getElementsByClassName('table-title-content'); If (titleDom[0]) titleHeight = 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>