//@ts-nocheck import { defineComponent, inject } from "vue"; import { xU } from "../../ventoseUtils"; import { usefnObserveDomResize } from "../../compositionAPI/useDomResize"; import { xVirTableTd } from "./xVirTableTd"; export type t_rowPayload = { rowIndex: number; rowData: object; }; export const xVirTableBody = defineComponent({ props: ["columnOrder", "columns", "rowHeight", "selectedConfigs", "selected"], emits: ["selectedChange", "update:scrollHeight", "scroll"], inject: ["xVirTable"], components: { xVirTableTd }, setup() { const { fnObserveDomResize, fnUnobserveDomResize } = usefnObserveDomResize(); return { uniqBy: inject("uniqBy"), configs: inject("configs"), rowCache: {}, fnObserveDomResize, fnUnobserveDomResize }; }, data(vm) { this.debounceSetPerBlockHeight = xU.debounce(function ( viewportHeight: number ) { this.viewportHeight = viewportHeight; this.perBlockRowCount = Math.ceil(viewportHeight / this.rowHeight); this.perBlockHeight = this.perBlockRowCount * this.rowHeight; this.setHeight(); }, 64); return { isLoading: false, perBlockHeight: 1, perBlockRowCount: 0, blockInViewCount: 0, styleWrapperAll: { height: 0, position: "relative" }, virs1: [], virs2: [], virs3: [] }; }, mounted() { /* 监听body高度变化 */ this.fnObserveDomResize(this.$refs.wrapper, () => { this.xVirTable.layoutDebounce(); this.debounceSetPerBlockHeight(this.$refs.wrapper.offsetHeight); }); this.$watch( () => { return `${this.configs.dataSource.length}_${this.perBlockHeight}_${this.perBlockRowCount}_${this.styleWrapper1}_${this.styleWrapper2}_${this.styleWrapper3}`; }, () => { this.updateCell(); } ); }, beforeUnmount() { this.fnUnobserveDomResize(this.$refs.wrapper); }, computed: { fnIsSelected() { const { isSelect, prop } = this.selectedConfigs || {}; if (xU.isFunction(isSelect)) { return rowInfo => { return isSelect.call(this, { ...rowInfo, selected: this.selected }); }; } else { /* 默认处理方式 */ return ({ rowData }) => { const id = rowData[prop]; return this.selected.includes(id); }; } }, fnIsDisabled() { const { isDisabled } = this.selectedConfigs || {}; if (xU.isFunction(isDisabled)) { return (...args) => { return isDisabled.apply(this, args); }; } else { return () => { return false; }; } }, positionBlock() { return this.blockInViewCount % 3; }, /* style */ styleWrapper1() { if (this.positionBlock === 0) { return `transform:translateY(${ this.blockInViewCount * this.perBlockHeight }px)`; } if (this.positionBlock === 1) { return `transform:translateY(${ (this.blockInViewCount + 2) * this.perBlockHeight }px)`; } return `transform:translateY(${ (this.blockInViewCount + 1) * this.perBlockHeight }px)`; }, styleWrapper2() { if (this.positionBlock === 0) { return `transform:translateY(${ (this.blockInViewCount + 1) * this.perBlockHeight }px)`; } if (this.positionBlock === 1) { return `transform:translateY(${ this.blockInViewCount * this.perBlockHeight }px)`; } return `transform:translateY(${ (this.blockInViewCount - 1) * this.perBlockHeight }px)`; }, styleWrapper3() { if (this.positionBlock === 0) { return `transform:translateY(${ (this.blockInViewCount + 2) * this.perBlockHeight }px)`; } if (this.positionBlock === 1) { return `transform:translateY(${ (this.blockInViewCount + 1) * this.perBlockHeight }px)`; } return `transform:translateY(${ this.blockInViewCount * this.perBlockHeight }px)`; }, vDomBodyTr1() { return this.genTr(this.virs1); }, vDomBodyTr2() { return this.genTr(this.virs2); }, vDomBodyTr3() { return this.genTr(this.virs3); } }, methods: { clearCacheRow() { const props = xU.filter(this.rowCache, (value, prop) => /^blockId/.test(prop) ); xU.each(props, prop => delete this.rowCache[prop]); }, onClickRow(payload: t_rowPayload) { if (this?.configs?.onClickRow) { this.configs.onClickRow(payload); } }, genTr(rows) { const vDomBlock = (() => { if (!this.uniqBy) { return xU.map(rows, (data: object, rowIndex: number) => { const { __virRowIndex } = data; const payload = { rowIndex: __virRowIndex, rowData: data }; return (
this.onClickRow(payload)}> {this.genSelectedVDom(payload)} {xU.map(this.columnOrder, (prop: string, index: number) => { return ( ); })}
); }); } else { const blockId = xU.reduce( rows, (id, row) => { id += row[this.uniqBy]; return id; }, "blockId" ); if (!this.rowCache[blockId]) { this.rowCache[blockId] = xU.map( rows, (data: object, rowIndex: number) => { if (!this.rowCache[data[this.uniqBy]]) { const { __virRowIndex } = data; this.rowCache[data[this.uniqBy]] = (
{this.genSelectedVDom({ rowIndex: __virRowIndex, rowData: data })} {xU.map( this.columnOrder, (prop: string, index: number) => { return ( ); } )}
); } return this.rowCache[data._id]; } ); } return this.rowCache[blockId]; } })(); return vDomBlock; }, updateCell() { xU("updateCell"); this.setVirs1(); this.setVirs2(); this.setVirs3(); }, setVirs1() { const position = Number(this.styleWrapper1.match(/(\d)/g).join("")) / this.perBlockHeight; const start = position * this.perBlockRowCount; const end = start + this.perBlockRowCount; this.virs1 = this.fragment(start, end); }, setVirs2() { const position = Number(this.styleWrapper2.match(/(\d)/g).join("")) / this.perBlockHeight; const start = position * this.perBlockRowCount; const end = start + this.perBlockRowCount; this.virs2 = this.fragment(start, end); }, setVirs3() { const position = Number(this.styleWrapper3.match(/(\d)/g).join("")) / this.perBlockHeight; const start = position * this.perBlockRowCount; const end = start + this.perBlockRowCount; this.virs3 = this.fragment(start, end); }, fragment(start: number, end: number): any { const targetRecords = this.configs.dataSource .slice(start, end) .map((i, index) => { /* 改行数据在DataSource中的实际下标 */ i.__virRowIndex = start + index; return i; }); return targetRecords; }, genSelectedVDom(rowInfo) { if (!this.selectedConfigs) { return null; } const isSelected = this.fnIsSelected(rowInfo); let isDisabled = this.fnIsDisabled(rowInfo); const handleChange = e => { const { prop } = this.selectedConfigs; this.emitSelectedChange(e.target.checked, rowInfo.rowData[prop]); }; let vDomChecked; if (xU.isString(isDisabled)) { isDisabled = true; const uiPopoverConfigs = { content: isDisabled }; vDomChecked = ( ); } else { vDomChecked = ( ); } return (
{vDomChecked}
); }, emitSelectedChange(checked, id) { this.$emit("selectedChange", { checked, id }); }, setTop: xU.debounce(function () { if (this.$refs.refWrapper) { this.$refs.refWrapper.scrollTo({ top: this.top, behavior: "smooth" }); } }, 1000), updateTop(event: any) { if (event) { /* @ts-ignore */ const top: number = event.target.scrollTop; const left: number = event.target.scrollLeft; /* 与header同步srollLeft */ this.$emit("scroll", left); this.blockInViewCount = Math.floor(top / this.perBlockHeight); } }, setHeight() { const height = this.configs.dataSource.length * this.rowHeight; if (!height) { delete this.styleWrapperAll.width; } else if (this.viewportHeight && height < this.viewportHeight) { /* @ts-ignore */ this.styleWrapperAll.width = `calc(100% - 6px)`; } else { delete this.styleWrapperAll.width; } /* @ts-ignore */ this.styleWrapperAll.height = `${height}px`; if (this.$refs.wrapper) { this.$nextTick(() => { if (this.$refs.wrapper.scrollTop > 1) { this.$refs.wrapper.scrollTop--; } else { this.$refs.wrapper.scrollTop++; } }); } } }, watch: { rowHeight: { immediate: true, async handler() { await xU.ensureValueDone(() => this.$refs?.wrapper?.offsetHeight); this.debounceSetPerBlockHeight(this.$refs.wrapper.offsetHeight); } }, top() { this.setTop(); }, "configs.dataSource": { immediate: true, async handler() { await xU.ensureValueDone(() => this.perBlockHeight); this.updateCell(); this.clearCacheRow(); this.updateTop(false); this.setHeight(); } } }, render() { const vDomTableBody = (
{/* 虚拟列表 start*/}
{this.vDomBodyTr1}
{this.vDomBodyTr2}
{this.vDomBodyTr3}
{/* 虚拟列表 end */}
); return vDomTableBody; } });