323 lines
12 KiB
JavaScript

import _extends from 'babel-runtime/helpers/extends';
import _objectWithoutProperties from 'babel-runtime/helpers/objectWithoutProperties';
import _classCallCheck from 'babel-runtime/helpers/classCallCheck';
import _possibleConstructorReturn from 'babel-runtime/helpers/possibleConstructorReturn';
import _inherits from 'babel-runtime/helpers/inherits';
import React from 'react';
import { findDOMNode } from 'react-dom';
import PropTypes from 'prop-types';
import { dom } from '../util';
import VirtualBody from './virtual/body';
import { statics } from './util';
var noop = function noop() {};
export default function virtual(BaseComponent) {
var _class, _temp2;
var VirtualTable = (_temp2 = _class = function (_React$Component) {
_inherits(VirtualTable, _React$Component);
function VirtualTable() {
var _temp, _this, _ret;
_classCallCheck(this, VirtualTable);
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
return _ret = (_temp = (_this = _possibleConstructorReturn(this, _React$Component.call.apply(_React$Component, [this].concat(args))), _this), _this.state = {
rowHeight: _this.props.rowHeight,
scrollToRow: _this.props.scrollToRow,
height: _this.props.maxBodyHeight
}, _this.onScroll = function () {
// 避免横向滚动带来的性能问题
var scrollTop = _this.bodyNode.scrollTop;
if (scrollTop === _this.lastScrollTop) {
return;
}
var start = _this.computeScrollToRow(scrollTop);
if (!('scrollToRow' in _this.props)) {
_this.setState({
scrollToRow: start
});
}
_this.props.onBodyScroll(start);
_this.lastScrollTop = scrollTop;
}, _this.getBodyNode = function (node, lockType) {
lockType = lockType ? lockType.charAt(0).toUpperCase() + lockType.substr(1) : '';
_this['body' + lockType + 'Node'] = node;
}, _this.getTableInstance = function (type, instance) {
type = type ? type.charAt(0).toUpperCase() + type.substr(1) : '';
_this['table' + type + 'Inc'] = instance;
}, _temp), _possibleConstructorReturn(_this, _ret);
}
VirtualTable.prototype.getChildContext = function getChildContext() {
return {
onVirtualScroll: this.onScroll,
bodyHeight: this.computeBodyHeight(),
innerTop: this.computeInnerTop(),
getBodyNode: this.getBodyNode,
getTableInstanceForVirtual: this.getTableInstance,
rowSelection: this.rowSelection
};
};
VirtualTable.prototype.componentWillMount = function componentWillMount() {
var _props = this.props,
useVirtual = _props.useVirtual,
dataSource = _props.dataSource;
this.hasVirtualData = useVirtual && dataSource && dataSource.length > 0;
};
VirtualTable.prototype.componentDidMount = function componentDidMount() {
if (this.hasVirtualData) {
this.lastScrollTop = this.bodyNode.scrollTop;
}
this.adjustScrollTop();
this.adjustSize();
this.reComputeSize();
};
VirtualTable.prototype.componentWillReceiveProps = function componentWillReceiveProps(nextProps) {
var useVirtual = nextProps.useVirtual,
dataSource = nextProps.dataSource;
this.hasVirtualData = useVirtual && dataSource && dataSource.length > 0;
if ('maxBodyHeight' in nextProps) {
if (this.state.height !== nextProps.maxBodyHeight) {
this.setState({
height: nextProps.maxBodyHeight
});
}
}
if ('scrollToRow' in nextProps) {
this.setState({
scrollToRow: nextProps.scrollToRow
});
}
if (this.state.rowHeight && 'rowHeight' in nextProps) {
var row = this.getRowNode();
var rowClientHeight = row && row.clientHeight;
if (rowClientHeight && rowClientHeight !== this.state.rowHeight) {
this.setState({
rowHeight: rowClientHeight
});
}
}
};
VirtualTable.prototype.componentDidUpdate = function componentDidUpdate() {
this.adjustScrollTop();
this.adjustSize();
this.reComputeSize();
};
VirtualTable.prototype.reComputeSize = function reComputeSize() {
var rowHeight = this.state.rowHeight;
if (typeof rowHeight === 'function' && this.hasVirtualData) {
var row = this.getRowNode();
var rowClientHeight = row && row.clientHeight;
if (rowClientHeight !== this.state.rowHeight) {
this.setState({
rowHeight: rowClientHeight
});
}
}
};
VirtualTable.prototype.computeBodyHeight = function computeBodyHeight() {
var rowHeight = this.state.rowHeight;
var dataSource = this.props.dataSource;
if (typeof rowHeight === 'function') {
return 0;
}
return dataSource.length * rowHeight;
};
VirtualTable.prototype.computeInnerTop = function computeInnerTop() {
var rowHeight = this.state.rowHeight;
if (typeof rowHeight === 'function') {
return 0;
}
return this.start * rowHeight;
};
VirtualTable.prototype.getVisibleRange = function getVisibleRange(ExpectStart) {
var _state = this.state,
height = _state.height,
rowHeight = _state.rowHeight;
var len = this.props.dataSource.length;
var end = void 0,
visibleCount = 0;
var start = 0;
if (typeof rowHeight === 'function') {
// try get cell height;
end = 1;
} else {
visibleCount = parseInt(dom.getPixels(height) / rowHeight, 10);
if ('number' === typeof ExpectStart) {
start = ExpectStart < len ? ExpectStart : 0;
}
end = Math.min(+start + 1 + visibleCount + 10, len);
}
this.end = end;
this.visibleCount = visibleCount;
return {
start: start,
end: end
};
};
VirtualTable.prototype.adjustScrollTop = function adjustScrollTop() {
if (this.hasVirtualData) {
this.bodyNode.scrollTop = this.lastScrollTop % this.state.rowHeight + this.state.rowHeight * this.state.scrollToRow;
}
};
VirtualTable.prototype.adjustSize = function adjustSize() {
if (this.hasVirtualData) {
var body = this.bodyNode;
var virtualScrollNode = body.querySelector('div');
var clientHeight = body.clientHeight,
clientWidth = body.clientWidth;
var tableInc = this.tableInc;
var tableNode = findDOMNode(tableInc);
var prefix = this.props.prefix;
var headerNode = tableNode.querySelector('.' + prefix + 'table-header table');
var headerClientWidth = headerNode && headerNode.clientWidth;
if (clientWidth < headerClientWidth) {
dom.setStyle(virtualScrollNode, 'min-width', headerClientWidth);
var leftNode = this.bodyLeftNode;
var rightNode = this.bodyRightNode;
leftNode && dom.setStyle(leftNode, 'max-height', clientHeight);
rightNode && dom.setStyle(rightNode, 'max-height', clientHeight);
this.hasScrollbar = true;
} else {
dom.setStyle(virtualScrollNode, 'min-width', 'auto');
this.hasScrollbar = false;
}
}
};
VirtualTable.prototype.computeScrollToRow = function computeScrollToRow(offset) {
var rowHeight = this.state.rowHeight;
var start = parseInt(offset / rowHeight);
this.start = start;
return start;
};
VirtualTable.prototype.getRowNode = function getRowNode() {
try {
// in case of finding an unmounted component due to cached data
// need to clear refs of this.tableInc when dataSource Changed
// use try catch for temporary
return findDOMNode(this.tableInc.getRowRef(0));
} catch (error) {
return null;
}
};
VirtualTable.prototype.render = function render() {
/* eslint-disable no-unused-vars, prefer-const */
var _props2 = this.props,
useVirtual = _props2.useVirtual,
components = _props2.components,
dataSource = _props2.dataSource,
fixedHeader = _props2.fixedHeader,
rowHeight = _props2.rowHeight,
scrollToRow = _props2.scrollToRow,
onBodyScroll = _props2.onBodyScroll,
others = _objectWithoutProperties(_props2, ['useVirtual', 'components', 'dataSource', 'fixedHeader', 'rowHeight', 'scrollToRow', 'onBodyScroll']);
var entireDataSource = dataSource;
var newDataSource = dataSource;
this.rowSelection = this.props.rowSelection;
if (this.hasVirtualData) {
newDataSource = [];
components = _extends({}, components);
var _getVisibleRange = this.getVisibleRange(this.state.scrollToRow),
start = _getVisibleRange.start,
end = _getVisibleRange.end;
dataSource.forEach(function (current, index, record) {
if (index >= start && index < end) {
current.__rowIndex = index;
newDataSource.push(current);
}
});
if (!components.Body) {
components.Body = VirtualBody;
}
fixedHeader = true;
}
return React.createElement(BaseComponent, _extends({}, others, {
dataSource: newDataSource,
entireDataSource: entireDataSource,
components: components,
fixedHeader: fixedHeader
}));
};
return VirtualTable;
}(React.Component), _class.VirtualBody = VirtualBody, _class.propTypes = _extends({
/**
* 是否开启虚拟滚动
*/
useVirtual: PropTypes.bool,
/**
* 设置行高
*/
rowHeight: PropTypes.oneOfType([PropTypes.number, PropTypes.func]),
maxBodyHeight: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
primaryKey: PropTypes.string,
dataSource: PropTypes.array,
/**
* 在内容区域滚动的时候触发的函数
*/
onBodyScroll: PropTypes.func
}, BaseComponent.propTypes), _class.defaultProps = _extends({}, BaseComponent.defaultProps, {
primaryKey: 'id',
rowHeight: noop,
maxBodyHeight: 200,
components: {},
prefix: 'next-',
onBodyScroll: noop
}), _class.childContextTypes = {
onVirtualScroll: PropTypes.func,
bodyHeight: PropTypes.number,
innerTop: PropTypes.number,
getBodyNode: PropTypes.func,
getTableInstanceForVirtual: PropTypes.func,
rowSelection: PropTypes.object
}, _temp2);
VirtualTable.displayName = 'VirtualTable';
statics(VirtualTable, BaseComponent);
return VirtualTable;
}