Skip to content

Instantly share code, notes, and snippets.

@plusice
Created January 20, 2022 09:12
Show Gist options
  • Save plusice/87e3e89cbba417dfff0c990723ed55b4 to your computer and use it in GitHub Desktop.
Save plusice/87e3e89cbba417dfff0c990723ed55b4 to your computer and use it in GitHub Desktop.
前端组件
/**
* 使Ant Design Vue的Table组件支持表头sticky
* 单元格宽度必须固定
*/
import { throttle } from '../api/util';
let listenAction;
let container;
let stickyHeader = null;
let originEl = null;
let bindingConfig = {};
const originSelector = '.ant-table-content';
const scrollSelector = '.ant-table-scroll .ant-table-body';
const toRemoveSelector = '.ant-table-tbody,.ant-table-placeholder';
const getBindingConfig = (binding) => {
const params = binding.value || {};
const fixedTop = params.fixedTop || 0;
const zIndex = params.zIndex || 1000;
const bgColor = params.bgColor || '#fff';
const { disabled } = params;
// 父元素的id
const { scrollContainerId } = params;
return { fixedTop, zIndex, disabled, scrollContainerId, bgColor };
};
const unwatch = () => {
container && container.removeEventListener('scroll', listenAction);
container && container.removeEventListener('resize', resizeStickyHeader);
originEl && originEl.querySelector(scrollSelector).removeEventListener('scroll', setScrollX);
};
const watch = () => {
container && container.addEventListener('scroll', listenAction);
container && container.addEventListener('resize', resizeStickyHeader);
originEl && originEl.querySelector(scrollSelector).addEventListener('scroll', setScrollX);
};
// 根据表格实际内容修改表头内容
const adaptStickyHeader = () => {
stickyHeader.innerHTML = originEl.innerHTML;
stickyHeader.querySelector(scrollSelector).style.overflowX = 'hidden';
const tbodyList = Array.from(stickyHeader.querySelectorAll(toRemoveSelector));
tbodyList.forEach((tbody) => {
tbody.parentNode.removeChild(tbody);
});
resizeStickyHeader();
setScrollX();
};
// 根据实际内容设置宽度
const resizeStickyHeader = throttle(() => {
stickyHeader.style.width = `${originEl.getBoundingClientRect().width}px`;
});
// 根据表格横向滚动,设置sticky表头的横向位置
const setScrollX = throttle(() => {
const stickyHeaderScroller = stickyHeader.querySelector(scrollSelector);
const originScroller = originEl.querySelector(scrollSelector);
stickyHeaderScroller.scrollLeft = originScroller.scrollLeft;
});
export default {
bind(el, binding) {
originEl = el.querySelector(originSelector);
bindingConfig = getBindingConfig(binding);
const { disabled, fixedTop, zIndex, scrollContainerId, bgColor } = bindingConfig;
if (disabled) return;
container = document.getElementById(scrollContainerId) || window;
let active = false;
stickyHeader = originEl.cloneNode(true);
const stickyStyle = stickyHeader.style;
stickyStyle.cssText = `position: fixed;top: ${fixedTop}px; z-index: ${zIndex}; ${stickyStyle.cssText};background-color: ${bgColor}`;
const sticky = () => {
if (active) return;
setScrollX();
originEl.insertAdjacentElement('afterend', stickyHeader);
active = true;
};
const reset = () => {
if (!active) return;
stickyHeader.parentNode?.removeChild(stickyHeader);
active = false;
};
listenAction = throttle(() => {
const rectEl = originEl?.parentNode;
const rect = rectEl.getBoundingClientRect();
const offsetTop = rect.top;
if (offsetTop <= fixedTop) {
return sticky();
}
reset();
});
watch();
},
unbind: unwatch,
update(el, binding) {
bindingConfig = getBindingConfig(binding);
originEl = el.querySelector(originSelector);
if (bindingConfig.disabled) {
stickyHeader.parentNode?.removeChild(stickyHeader);
unwatch();
return;
}
adaptStickyHeader();
},
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment