| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110 |
- // 工具函数:获取 .el-table__body-wrapper 下的滚动容器
- function getBodyWrapper(el) {
- return el.querySelector('.el-table__body-wrapper');
- }
- // 创建滚动条并绑定事件,返回清理函数
- function setupScrollSync(el) {
- const table = el; // el 就是容器元素
- if (!table) return null;
- const outerWidth = table.offsetWidth;
- // 取第一个内部 table 的宽度作为内容宽度
- const innerTable = table.querySelector('table');
- const contentWidth = innerTable ? innerTable.offsetWidth : outerWidth;
- const bodyWrapper = getBodyWrapper(table);
- if (!bodyWrapper) {
- console.warn('未找到 .el-table__body-wrapper,无法创建滚动同步');
- return null;
- }
- // 隐藏原生横向滚动条,但保留纵向滚动条
- bodyWrapper.style.overflowX = 'hidden';
- bodyWrapper.style.overflowY = 'auto';
-
- // 创建自定义样式标签来隐藏横向滚动条
- const styleId = 'v-scroll-sync-hide-x-scrollbar';
- let styleEl = document.getElementById(styleId);
- if (!styleEl) {
- styleEl = document.createElement('style');
- styleEl.id = styleId;
- styleEl.textContent = `
- .el-table__body-wrapper.v-scroll-sync-hide-x::-webkit-scrollbar {
- width: 6px;
- height: 0;
- }
- .el-table__body-wrapper.v-scroll-sync-hide-x::-webkit-scrollbar-track {
- background: transparent;
- }
- .el-table__body-wrapper.v-scroll-sync-hide-x::-webkit-scrollbar-thumb {
- background: #d9d9d9;
- border-radius: 3px;
- }
- `;
- document.head.appendChild(styleEl);
- }
- bodyWrapper.classList.add('v-scroll-sync-hide-x');
- // 避免重复创建
- const existingDiv = table.querySelector('.v-scroll-sync-bar');
- if (existingDiv) existingDiv.remove();
- const div = document.createElement('div');
- div.className = 'v-scroll-sync-bar';
- div.style.width = outerWidth + 'px';
- div.style.height = '12px';
- div.style.overflowX = 'auto';
- div.innerHTML = `<div style="width:${contentWidth}px; height:1px;"></div>`;
- const onScroll = () => {
- bodyWrapper.scrollLeft = div.scrollLeft;
- };
- div.addEventListener('scroll', onScroll);
- const tableContainer = table.querySelector('.el-table');
- // 在tableContainer后面插入div(作为兄弟元素)
- tableContainer.insertAdjacentElement('afterend', div);
- // table.appendChild(div);
- // 返回清理函数和事件引用
- return {
- div,
- bodyWrapper,
- handler: onScroll,
- destroy() {
- div.removeEventListener('scroll', onScroll);
- if (div.parentNode) div.parentNode.removeChild(div);
- // 移除添加的class
- bodyWrapper.classList.remove('v-scroll-sync-hide-x');
- }
- };
- }
- // Vue 2 自定义指令
- const tableScrollSync = {
- bind(el) {
- // bind 时可能未插入文档,先不做操作,统一在 inserted 中处理
- el._scrollSyncData = null;
- },
- inserted(el) {
- // 元素插入 DOM 后初始化
- el._scrollSyncData = setupScrollSync(el);
- },
- update(el) {
- // 当表格数据变化导致内容宽度改变时(如切换分页、动态列),重新初始化
- if (el._scrollSyncData) {
- el._scrollSyncData.destroy();
- }
- el._scrollSyncData = setupScrollSync(el);
- },
- unbind(el) {
- // 指令解绑时销毁
- if (el._scrollSyncData) {
- el._scrollSyncData.destroy();
- el._scrollSyncData = null;
- }
- }
- };
- export default tableScrollSync;
|