diff --git a/README.md b/README.md index 5a2e74a..5991d42 100644 --- a/README.md +++ b/README.md @@ -77,7 +77,7 @@ function Example(): JSX.Element { const vComponents = useMemo(() => { // 使用VList 即可有虚拟列表的效果 return VList({ - height: 1000 // 此值和scrollY值相同. 必传. (required). same value for scrolly + height: 1000 // 此值和scrollY值相同 (不传或者传string类型会自动计算表格高度) same value for scrolly }) }, []) @@ -102,7 +102,7 @@ ReactDom.render(, dom) ```tsx VList({ - height: number | string, // (必填) 对应scrollY. + height: number | string, // (可选) 对应scrollY. (not required, if not set, will auto calculate table height) onReachEnd: () => void, // (可选) 滚动条滚到底部触发api. (scrollbar to the end) onScroll: () => void, // (可选) 滚动时触发的api. (triggered by scrolling) vid: string, // (可选, 如果同一页面存在多个虚拟表格时必填.) 唯一标识. (unique vid, required when exist more vitual table on a page) diff --git a/docs/demo/AutoHeightTable.md b/docs/demo/AutoHeightTable.md new file mode 100644 index 0000000..38f6a2a --- /dev/null +++ b/docs/demo/AutoHeightTable.md @@ -0,0 +1,3 @@ +## AutoHeightTable + + \ No newline at end of file diff --git a/docs/examples/AutoHeightTable.tsx b/docs/examples/AutoHeightTable.tsx new file mode 100644 index 0000000..7909769 --- /dev/null +++ b/docs/examples/AutoHeightTable.tsx @@ -0,0 +1,69 @@ +import React, { useState, useEffect, useMemo } from 'react'; +import { Table } from 'antd'; +import { VList } from '../../src/index'; +import 'antd/dist/antd.css'; + +type DataSourceType = { [key: string]: string } +function AutoHeightTable() { + const [dataSource, setDataSource] = useState([]); + + useEffect(() => { + const tempDataSource: DataSourceType[] = []; + for (let i = 0; i < 1000; i += 1) { + tempDataSource.push({ + company_name: `aaa${i} 富士山下的你好美 你知道吗 aaa${i} 富士山下的你好美 你知道吗 aaa${i} 富士山下的你好美 你知道吗`, + company_name1: `aaa${i} index index index index`, + company_name2: `aaa${i} company index index index`, + + company_name3: `aaa${i} company company index index`, + company_name4: `aaa${i} company company company index`, + company_name5: `aaa${i} company company company company`, + company_name6: `aaa${i} company index index company`, + }); + } + + setDataSource(tempDataSource); + }, []); + + const columns: any[] = [ + { + title: '序号', + key: 'id', + fixed: 'left', + render(text, record, index) { + return index + 1; + }, + width: 100, + }, + { + title: '公司', + dataIndex: 'company_name', + width: 200, + }, + { + title: '公司1', + dataIndex: 'company_name1', + width: 200, + }, + { + title: '公司2', + dataIndex: 'company_name2', + width: 200, + }, + ]; + + const vc1 = useMemo(() => VList({ }), []); + + + return + ; +} + +export default AutoHeightTable; diff --git a/src/index.tsx b/src/index.tsx index eecb525..b9e35d0 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -8,7 +8,7 @@ import React, { useState, useMemo, } from 'react' -import { throttle, debounce } from 'lodash-es' +import { throttle, debounce, isNumber } from 'lodash-es' import './style.css' @@ -27,6 +27,52 @@ const initialState = { totalLen: 0, } +/** + * @description: 10 -> 10, + * @description: 10px -> 10, + * @description: 90% -> height * 0.9 + * @description: calc(100% - 32px) -> height * 1 - 32 + * @description: calc(100vh - 32px) -> documentHeight * 1 - 32 + * @param {*} ele + * @param {string & number} maxWidth + * @return {*} + */ +const transitionHeight = (parentHeight: number, height: string | number) => { + const documentHeight = document.documentElement.offsetHeight; + if (!height) return parentHeight; + + if (typeof height === 'number') { + return height; // 如果父元素的宽度小于传入的最大宽度,返回父元素的宽度 + } + + const numMatch = height.match(/^(\d+)(px)?$/); + if (numMatch) { + return +numMatch[1]; // 如果父元素的宽度小于传入的最大宽度,返回父元素的宽度 + } + + const percentMatch = height.match(/^(\d+)%$/); + if (percentMatch) { + return parentHeight * (parseInt(percentMatch[1]) / 100); + } + + const vhMatch = height.match(/^(\d+)(vh)?$/); + if (vhMatch) { + return documentHeight * (parseInt(vhMatch[1]) / 100); + } + + const relativeMatch = height.match(/^calc\((\d+)% - (\d+)px\)$/); + if (relativeMatch) { + return parentHeight * (parseInt(relativeMatch[1]) / 100) - parseInt(relativeMatch[2]); + } + + const absoluteMatch = height.match(/^calc\((\d+)vh - (\d+)px\)$/); + if (absoluteMatch) { + return documentHeight * (parseInt(absoluteMatch[1]) / 100) - parseInt(absoluteMatch[2]); + } + + return parentHeight; +}; + function reducer(state, action) { const { curScrollTop, rowHeight, totalLen, ifScrollTopClear } = action @@ -219,20 +265,41 @@ function VTable(props: any, otherParams): JSX.Element { return temp }, [state.rowHeight, totalLen]) + const [parentHeight, setParentHeight] = useState() + useEffect(() => { + const parentElement = wrap_tableRef.current?.parentElement + const updateContainerHeight = () => { + if (!parentElement) return; + const containerHeight = parentElement.getBoundingClientRect()?.height; + + setParentHeight(containerHeight); + }; + + setTimeout(() => { + updateContainerHeight() + }) + // 在height为固定高度的时候不进行监听 + if (isNumber(scrollY) || /^\b\d+px\b$/.test(scrollY)) return; + + const ResizeObserverImpl = + typeof window !== 'undefined' && 'ResizeObserver' in window + ? window['ResizeObserver'] + : null; + if (!ResizeObserverImpl) { + console.warn('ResizeObserver is not supported in this environment.'); + return; + } + const resizeObserver = new ResizeObserverImpl(updateContainerHeight); + resizeObserver.observe(parentElement); + return () => resizeObserver.disconnect(); + }, []) + // table的scrollY值 const [tableScrollY, setTableScrollY] = useState(0) // tableScrollY 随scrollY / tableHeight 进行变更 useEffect(() => { - let temp = 0 - - if (typeof scrollY === 'string') { - temp = - (wrap_tableRef.current?.parentNode as HTMLElement) - ?.offsetHeight ?? 0 - } else { - temp = scrollY - } + let temp = transitionHeight(parentHeight ?? 0, scrollY) ?? 0 // if (isNumber(tableHeight) && tableHeight < temp) { // temp = tableHeight; @@ -244,7 +311,7 @@ function VTable(props: any, otherParams): JSX.Element { } setTableScrollY(temp) - }, [scrollY, tableHeight]) + }, [scrollY, tableHeight, parentHeight]) // 渲染的条数 const renderLen = useMemo(() => { @@ -397,7 +464,7 @@ function VTable(props: any, otherParams): JSX.Element { // ================导出=================== export function VList(props: { - height: number | string + height?: number | string // 到底的回调函数 onReachEnd?: () => void onScroll?: () => void