UNPKG

bee-table

Version:
589 lines (513 loc) 24.7 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; exports["default"] = bigDataX; var _react = require("react"); var _react2 = _interopRequireDefault(_react); var _propTypes = require("prop-types"); var _propTypes2 = _interopRequireDefault(_propTypes); var _utils = require("./utils"); var _Table = require("../Table"); var _Table2 = _interopRequireDefault(_Table); var _util = require("./util"); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } function _defaults(obj, defaults) { var keys = Object.getOwnPropertyNames(defaults); for (var i = 0; i < keys.length; i++) { var key = keys[i]; var value = Object.getOwnPropertyDescriptor(defaults, key); if (value && value.configurable && obj[key] === undefined) { Object.defineProperty(obj, key, value); } } return obj; } function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : _defaults(subClass, superClass); } var DEFAULT_ROW_HEIGHT = _Table2["default"].defaultProps.height || 30; //缺省的默认行高 // 确保索引不超出数据范围 function validIndex(totalCount, currentIndex) { var cursorIndex = currentIndex || 0; if (currentIndex < 0) cursorIndex = 0; //确保不小于0 if (currentIndex > totalCount - 1) cursorIndex = totalCount - 1; //确保不超出总数据行 return cursorIndex; } /** * 获取数据开始和结束的索引位置 * @param totalCount 数据总行数 * @param showCount 可视区域显示的总行数 * @param hiddenCount 单个缓冲区隐藏的行数 * @param currentIndex 可视区域显示的首行索引(游标) * @return {Array} */ function computeIndex(totalCount, showCount, hiddenCount, currentIndex) { var screenCount = showCount + hiddenCount * 2; //渲染的总行数 var startIndex = 0, endIndex = 0; var cursorIndex = validIndex(totalCount, currentIndex); if (totalCount <= screenCount) { //总数不足或刚好一屏 startIndex = 0; endIndex = totalCount > 1 ? totalCount - 1 : 1; //注意只有1行的场景 } else { //总数超过一屏 if (cursorIndex == 0) { //等于总数据顶边界 startIndex = 0; endIndex = screenCount - 1; } else if (cursorIndex == totalCount - 1) { //等于总数据底边界 endIndex = totalCount - 1; startIndex = endIndex - screenCount; } else { startIndex = cursorIndex - (hiddenCount - 1); if (startIndex < 0) startIndex = 0; //注意上行有计算出为负值的情况 endIndex = startIndex + (screenCount - 1); } if (endIndex < 0) endIndex = 0; // 确保结束位置区间不越界 //如果结束位置超过总记录数,则把超过的部分在开始位置往前移动 if (endIndex > totalCount - 1) { startIndex = startIndex - (endIndex - (totalCount - 1)); endIndex = totalCount - 1; } if (startIndex < 0) startIndex = 0; // 确保开始位置区间不越界 } return { screenCount: screenCount, startIndex: startIndex, endIndex: endIndex }; } //获取每行默认高度 function getDefaultRowHeight(nextProps) { var rowHeight = nextProps.height ? nextProps.height : DEFAULT_ROW_HEIGHT; return rowHeight; } //获取显示在可视区域的行数 function getShowCount(nextProps) { var scrollY = nextProps.scroll && nextProps.scroll.y ? parseInt(nextProps.scroll.y) : 0; //默认可视区域高度 var rowHeight = getDefaultRowHeight(nextProps); //默认每行高度 var showCount = scrollY && rowHeight ? Math.floor(scrollY / rowHeight) : 20; return showCount; } // 新重构版bigData function bigDataX(Table) { var _class, _temp, _initialiseProps; return _temp = _class = function (_Component) { _inherits(BigDataX, _Component); function BigDataX(props) { _classCallCheck(this, BigDataX); var _this2 = _possibleConstructorReturn(this, _Component.call(this, props)); _initialiseProps.call(_this2); _this2.state = { needRender: false, scrollTop: 0, showCount: getShowCount(props), treeType: _this2.checkIsTreeType(props.isTree, props.data) }; _this2.currentIndex = 0; _this2.cachedRowHeight = {}; //缓存每行的高度 var expandedRowKeys = []; var rows = [].concat(_toConsumableArray(props.data)); if (props.defaultExpandAllRows) { for (var i = 0; i < rows.length; i++) { var row = rows[i]; expandedRowKeys.push(_this2.getRowKey(row, i)); rows = rows.concat(row[props.childrenColumnName] || []); } } else { expandedRowKeys = props.expandedRowKeys || props.defaultExpandedRowKeys; } _this2.expandedRowKeys = props.expandedRowKeys || expandedRowKeys || []; //缓存展开的行键值 _this2.flatTreeKeysMap = {}; //树表,扁平结构数据的 Map 映射,方便获取各节点信息 _this2.flatTreeData = []; //深度遍历处理后的data数组,拉平的数据,包含展开的子集行(未展开的不包含) if (_this2.state.treeType) { var deep = _this2.deepTraversal(props.data, null, _this2.expandedRowKeys); _this2.flatTreeKeysMap = deep.flatTreeKeysMap; _this2.flatTreeData = deep.flatTreeData; } return _this2; } BigDataX.prototype.componentWillReceiveProps = function componentWillReceiveProps(nextProps, nextContext) { var props = this.props; var newExpandedKeys = nextProps.expandedRowKeys, newData = nextProps.data; var _this = this, dataLen = newData.length; var treeType = this.state.treeType; // if ('expandedRowKeys' in nextProps){ // this.expandedRowKeys = newExpandedKeys; // } if ('defaultExpandAllRows' in nextProps) { var defaultExpandAllRows = nextProps.defaultExpandAllRows, data = nextProps.data, expandedRowKeys = nextProps.expandedRowKeys, _nextProps$childrenCo = nextProps.childrenColumnName, childrenColumnName = _nextProps$childrenCo === undefined ? 'children' : _nextProps$childrenCo; if (defaultExpandAllRows && !expandedRowKeys) { var _expandedRowKeys = []; var rows = [].concat(_toConsumableArray(data || [])); for (var i = 0; i < rows.length; i++) { var row = rows[i]; _expandedRowKeys.push(this.getRowKey(row, i)); rows = rows.concat(row[childrenColumnName] || []); } this.expandedRowKeys = _expandedRowKeys; } else if (!defaultExpandAllRows && !expandedRowKeys) { this.expandedRowKeys = []; } } if ('expandedRowKeys' in nextProps) { this.expandedRowKeys = newExpandedKeys; } if ('isTree' in nextProps || 'data' in nextProps) { treeType = _this.checkIsTreeType(nextProps.isTree, nextProps.data); this.setState({ treeType: treeType }); } if ('height' in nextProps && nextProps.height !== props.height) { // _this.cachedRowHeight = {}; //清除缓存每行的高度 _this.cachedRowHeight = _this.setCachedRowHeight(_this.cachedRowHeight); } // 可视滚动区域变化时 if ('scroll' in nextProps && nextProps.scroll.y !== props.scroll.y) { // _this.cachedRowHeight = {}; //清除缓存每行的高度 _this.cachedRowHeight = _this.setCachedRowHeight(_this.cachedRowHeight); if (!this.props.ignoreScrollYChange) { //y不变化则无需重置currentIndex _this.currentIndex = 0; } //显示在可视区域的行数 this.setState({ showCount: getShowCount(nextProps) }); } if ('data' in nextProps) { //fix: 滚动加载场景中,数据动态改变下占位计算错误的问题(26 Jun) if (newData.toString() !== props.data.toString()) { // _this.cachedRowHeight = {}; //清除缓存每行的高度 _this.cachedRowHeight = _this.setCachedRowHeight(_this.cachedRowHeight); if (_this.state.scrollTop <= 0) { // 增加scrollTop 判断,ncc场景下滚动条不在最上层,数据变更时 会出现空白,因为重置了currentIndex没有重置滚动条 _this.currentIndex = 0; } } this.flatTreeKeysMap = {}; //树表,扁平结构数据的 Map 映射,方便获取各节点信息 this.flatTreeData = []; //深度遍历处理后的data数组 if (treeType) { var deep = this.deepTraversal(newData, null, this.expandedRowKeys); this.flatTreeKeysMap = deep.flatTreeKeysMap; this.flatTreeData = deep.flatTreeData; } } //为外部定位currentIndex提供支持,以确保currentIndex行显示在可视区域 if ('currentIndex' in nextProps) { //如果传currentIndex,会判断该条数据是否在可视区域,如果没有的话,则重新计算startIndex和endIndex if (nextProps.currentIndex !== -1) { var totalCount = this.state.treeType ? this.flatTreeData.length : dataLen; this.currentIndex = validIndex(totalCount, nextProps.currentIndex); var newScrollTop = _this.getSumHeight(0, this.currentIndex, this.state.treeType); //重新设定scrollTop值 if (newScrollTop !== this.state.scrollTop) { this.setState({ scrollTop: newScrollTop }); } } } }; /** * 深度遍历树形 data,把数据拍平,变为一维数组 * @param {*} treeData * @param {*} parentKey 标识父节点 * @param {*} arrData 排平后的数组数据 * @param {*} keyMap key与数据的关系 */ /** * 将截取后的 List 数组转换为 Tree 结构 */ //获取每行的唯一键 BigDataX.prototype.getRowKey = function getRowKey(record, index) { var rowKey = this.props.rowKey; var key = typeof rowKey === "function" ? rowKey(record, index) : record[rowKey]; return key; }; /** *判断是否是树形结构 */ BigDataX.prototype.checkIsTreeType = function checkIsTreeType(isTree, data) { if (typeof isTree == 'boolean') return isTree; var tempData = data || []; var hasChildren = tempData.some(function (item) { return item.children !== undefined; }); return hasChildren; }; BigDataX.prototype.componentWillUnmount = function componentWillUnmount() { this.cachedRowHeight = {}; //缓存每行的高度 this.expandedRowKeys = []; //缓存展开的行键值 this.flatTreeKeysMap = {}; //树表,扁平结构数据的 Map 映射,方便获取各节点信息 this.flatTreeData = []; //拉平的树表数据 }; //获取当前索引行的高度 //计算总行高 BigDataX.prototype.getSumHeight = function getSumHeight(start, end, isTreeType) { var defaultRowHeight = getDefaultRowHeight(this.props); var sumHeight = 0; for (var index = start; index < end; index++) { var currentRowHeight = this.getRowHeightByIndex(isTreeType, index, defaultRowHeight); //获取行高 sumHeight += currentRowHeight; } return sumHeight; }; //表格尺寸变化时,重新计算滚动及显示位置 /** *@description 根据返回的scrollTop计算当前的索引。此处做了两次缓存一个是根据上一次的currentIndex计算当前currentIndex。另一个是根据当前内容区的数据是否在缓存中如果在则不重新render页面 *@param 最新一次滚动的scrollTop *@param treeType是否是树状表 *@param callback表体滚动过程中触发的回调 */ //行拖拽-大数据表格下的实现 //行拖拽-大数据表格下的实现 BigDataX.prototype.render = function render() { var _this3 = this; var _props = this.props, data = _props.data, loadBuffer = _props.loadBuffer; var _state = this.state, scrollTop = _state.scrollTop, showCount = _state.showCount, treeType = _state.treeType; var expandedRowKeys = this.props.expandedRowKeys ? this.props.expandedRowKeys : this.expandedRowKeys; var totalCount = treeType ? this.flatTreeData.length : data.length; var buffer = computeIndex(totalCount, showCount, loadBuffer, this.currentIndex); //计算出缓冲区各索引值 var lazyLoad = { startIndex: buffer.startIndex, endIndex: buffer.endIndex, startParentIndex: buffer.startIndex //为树状节点做准备 }; lazyLoad.preHeight = this.getSumHeight(0, lazyLoad.startIndex, treeType); lazyLoad.sufHeight = this.getSumHeight(lazyLoad.endIndex, totalCount - 1, treeType); // console.log("AAA--->总数据:"+totalCount+"渲染总行数:"+buffer.screenCount+"缓冲区行数:"+hiddenCount+"可视区域行数:"+showCount); // console.log("AAA--->startIndex:"+buffer.startIndex+"--->endIndex:"+buffer.endIndex+"--->currentIndex:"+this.currentIndex+"-->scrollTop:"+scrollTop); var dataSource = []; // 存放截取需要显示的数据 if (treeType) { var sliceTreeList = this.flatTreeData.slice(buffer.startIndex, buffer.endIndex + 1); //从拉平的数据中截取 dataSource = this.getTreeDataFromList(sliceTreeList); //将截取的list数据重新组织成tree结构 } else { dataSource = data.slice(buffer.startIndex, buffer.endIndex + 1); } return _react2["default"].createElement(Table, _extends({}, this.props, { data: dataSource, lazyLoad: lazyLoad, ref: function ref(el) { return _this3.table = el; }, handleScrollY: this.handleScrollY, scrollTop: scrollTop, setRowHeight: this.setRowHeight // setRowParentIndex={this.setRowParentIndex} , onResize: this.handleResize, onExpand: this.onExpand, onExpandedRowsChange: this.props.onExpandedRowsChange, expandedRowKeys: expandedRowKeys, onRowDragStart: this.__onRowDragStart, onRowDragDrop: this.__onRowDragDrop // className={'lazy-table'} })); }; return BigDataX; }(_react.Component), _class.defaultProps = { data: [], loadBuffer: 50, //单个缓冲区大小,缓冲区有前后两个区,所以总缓冲区是x2 rowKey: "key", onExpand: function onExpand() {}, scroll: {}, currentIndex: -1, isTree: null, height: null, childrenColumnName: 'children' }, _class.propTypes = { loadBuffer: _propTypes2["default"].number, height: _propTypes2["default"].number, scroll: _propTypes2["default"].any, expandedRowKeys: _propTypes2["default"].string, rowKey: _propTypes2["default"].string, currentIndex: _propTypes2["default"].number, isTree: _propTypes2["default"].bool, data: _propTypes2["default"].any, onExpandedRowsChange: _propTypes2["default"].func, childrenColumnName: _propTypes2["default"].string }, _initialiseProps = function _initialiseProps() { var _this4 = this; this.setCachedRowHeight = function () { var cachedRowHeight = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; var target = {}; Object.keys(cachedRowHeight).forEach(function (key) { // 如果是展开的行,也要缓存 if (typeof key === 'string' && (key || "").includes('_expanded')) { target[key] = cachedRowHeight[key]; } }); return target; }; this.deepTraversal = function (treeData) { var parentKey = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; var expandedKeys = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : []; var arrData = arguments[3]; var keyMap = arguments[4]; var flatTreeData = arrData || [], flatTreeKeysMap = keyMap || {}, dataCopy = treeData; if (Array.isArray(dataCopy)) { for (var i = 0, l = dataCopy.length; i < l; i++) { var _dataCopy$i = dataCopy[i], children = _dataCopy$i.children, props = _objectWithoutProperties(_dataCopy$i, ["children"]), key = _this4.getRowKey(dataCopy[i], i), _isLeaf = children && children.length > 0 ? false : true, isExpanded = expandedKeys.includes(key); var dataCopyI = _extends({ key: key, isExpanded: isExpanded, parentKey: parentKey, _isLeaf: _isLeaf, //是否叶子节点 index: flatTreeData.length }, props); flatTreeData.push(dataCopyI); // 取每项数据放入一个新数组 flatTreeKeysMap[key] = dataCopyI; // 优化递归逻辑,如果当前节点是收起状态,则不遍历其子节点 if (Array.isArray(children) && children.length > 0 && isExpanded) { _this4.deepTraversal(children, key, expandedKeys, flatTreeData, flatTreeKeysMap); } } } return { flatTreeData: flatTreeData, flatTreeKeysMap: flatTreeKeysMap }; }; this.getTreeDataFromList = function (treeList) { // 属性配置设置 var attr = { id: 'key', parendId: 'parentKey', rootId: null, _isLeaf: '_isLeaf' }; var treeData = (0, _utils.convertListToTree)(treeList, attr, _this4.flatTreeKeysMap); return treeData; }; this.getRowHeightByIndex = function (isTreeType, index, defaultRowHeight) { var _props2 = _this4.props, height = _props2.height, data = _props2.data; var currentRowHeight = height; var records = isTreeType ? _this4.flatTreeData : data; if (!records.length) return 0; var record = records[index]; var key = _this4.getRowKey(record, index); if (!height) { //如果没有指定固定行高(即动态行高) var cacheRowH = _this4.cachedRowHeight[key]; if (cacheRowH !== undefined) { currentRowHeight = cacheRowH; //缓存中存在则使用缓存的行高 } else { currentRowHeight = defaultRowHeight; //如果缓存行高也不存在则使用默认行高 } } currentRowHeight = currentRowHeight + (_this4.cachedRowHeight[key + "_expanded"] || 0); return currentRowHeight; }; this.handleResize = function () { var _state2 = _this4.state, scrollTop = _state2.scrollTop, treeType = _state2.treeType; _this4.handleScrollY(scrollTop, treeType); }; this.handleScrollY = function (nextScrollTop, treeType, callback) { var defaultRowHeight = getDefaultRowHeight(_this4.props); var tempScrollTop = nextScrollTop; var data = _this4.props.data; var records = treeType ? _this4.flatTreeData : data; var index = 0; //滚动后的位置索引 while (tempScrollTop > 0 && index < records.length) { var currentRowHeight = _this4.getRowHeightByIndex(treeType, index, defaultRowHeight); //获取行高 tempScrollTop -= currentRowHeight; if (tempScrollTop > -1) { //确保scrollTop存在小数误差1px的情况也能正确取值 index += 1; } } // console.log('AAA-->newIndex****',index); //如果之前的索引和下一次的不一样则更新索引和滚动的位置 if (_this4.currentIndex !== index) { _this4.currentIndex = index; } _this4.setState({ scrollTop: nextScrollTop }); callback && callback(nextScrollTop); }; this.setRowHeight = function (height, index, rowKey, isExpandedRow) { // this.cachedRowHeight[rowKey] = height; if (isExpandedRow) { // this.cachedRowHeight[rowKey] = this.cachedRowHeight[rowKey] + height; _this4.cachedRowHeight[rowKey + "_expanded"] = height; } else { _this4.cachedRowHeight[rowKey] = height; } }; this.onExpand = function (expandState, record, index) { var _this = _this4; var _state3 = _this4.state, treeType = _state3.treeType, needRender = _state3.needRender; var _props3 = _this4.props, data = _props3.data, onExpand = _props3.onExpand; var rowKey = _this4.getRowKey(record, index); //滚动加载expandedRowKeys自己维护,否则有展开不全的问题 if (!_this4.props.expandedRowKeys) { if (expandState) { //展开 _this4.expandedRowKeys.push(rowKey); //追加折叠行key _this4.setState({ needRender: !needRender }); } else { //折叠 _this4.expandedRowKeys = _this4.expandedRowKeys.filter(function (val) { return val != rowKey; }); //移除折叠行key _this4.setState({ needRender: !needRender }); } } // expandState为true时,记录下 onExpand && onExpand(expandState, record, index); if (treeType) { //重新递归数据 var deep = _this4.deepTraversal(data, null, _this4.expandedRowKeys); _this.flatTreeData = deep.flatTreeData; _this.flatTreeKeysMap = deep.flatTreeKeysMap; } //展开/折叠由于行数据变化所以得清除缓存的行高 // this.cachedRowHeight = {}; if (!expandState) { _this4.cachedRowHeight[rowKey + "_expanded"] = 0; } }; this.__onRowDragStart = function (options) { var dragStartKey = options.dragStartKey; var data = _this4.props.data, currentIndex = void 0, record = void 0; data.forEach(function (da, i) { // tr 的唯一标识通过 data.key 或 rowKey 两种方式传进来 var trKey = da.key ? da.key : _this4.getRowKey(da, i); if (trKey == dragStartKey) { currentIndex = i; record = da; } }); _this4.props.onDragRowStart && _this4.props.onDragRowStart(record, currentIndex); }; this.__onRowDragDrop = function (options) { var dragTargetKey = options.dragTargetKey, dragTargetIndex = options.dragTargetIndex, dropTargetKey = options.dropTargetKey, dropTargetIndex = options.dropTargetIndex; var data = _this4.props.data, record = void 0; for (var i = 0; i < data.length; i++) { var da = data[i]; // tr 的唯一标识通过 data.key 或 rowKey 两种方式传进来 var trKey = da.key ? da.key : _this4.getRowKey(da, i); if (trKey == dragTargetKey) { record = da;break; //匹配到后则退出减少性能开销 } } if (dragTargetIndex > -1) { data = (0, _util.arrayMoveTo)(data, dragTargetIndex, dropTargetIndex); _this4.props.onDropRow && _this4.props.onDropRow(data, record, dropTargetIndex); _this4.setState({ needRender: !_this4.state.needRender }); } else { _this4.props.onDropRow && _this4.props.onDropRow(data, record, dropTargetIndex); } }; }, _temp; } module.exports = exports["default"];