UNPKG

@alifd/next

Version:

A configurable component library for web built on React.

364 lines (290 loc) 13.6 kB
'use strict'; exports.__esModule = true; var _extends2 = require('babel-runtime/helpers/extends'); var _extends3 = _interopRequireDefault(_extends2); var _objectWithoutProperties2 = require('babel-runtime/helpers/objectWithoutProperties'); var _objectWithoutProperties3 = _interopRequireDefault(_objectWithoutProperties2); var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); var _inherits2 = require('babel-runtime/helpers/inherits'); var _inherits3 = _interopRequireDefault(_inherits2); exports.default = virtual; var _react = require('react'); var _react2 = _interopRequireDefault(_react); var _reactDom = require('react-dom'); var _propTypes = require('prop-types'); var _propTypes2 = _interopRequireDefault(_propTypes); var _reactLifecyclesCompat = require('react-lifecycles-compat'); var _util = require('../util'); var _body = require('./virtual/body'); var _body2 = _interopRequireDefault(_body); var _util2 = require('./util'); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var noop = function noop() {}; var THRESHOLD = 10; function virtual(BaseComponent) { var _class, _temp; var VirtualTable = (_temp = _class = function (_React$Component) { (0, _inherits3.default)(VirtualTable, _React$Component); function VirtualTable(props, context) { (0, _classCallCheck3.default)(this, VirtualTable); var _this = (0, _possibleConstructorReturn3.default)(this, _React$Component.call(this, props, context)); _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; }; var useVirtual = props.useVirtual, dataSource = props.dataSource; var hasVirtualData = useVirtual && dataSource && dataSource.length > 0; _this.state = { rowHeight: _this.props.rowHeight, scrollToRow: _this.props.scrollToRow, height: _this.props.maxBodyHeight, hasVirtualData: hasVirtualData }; return _this; } 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.getDerivedStateFromProps = function getDerivedStateFromProps(nextProps, prevState) { var state = {}; if ('maxBodyHeight' in nextProps) { if (prevState.height !== nextProps.maxBodyHeight) { state.height = nextProps.maxBodyHeight; } } if ('scrollToRow' in nextProps) { state.scrollToRow = nextProps.scrollToRow; } if (prevState.useVirtual !== nextProps.useVirtual || prevState.dataSource !== nextProps.dataSource) { state.hasVirtualData = nextProps.useVirtual && nextProps.dataSource && nextProps.dataSource.length > 0; } return state; }; VirtualTable.prototype.componentDidMount = function componentDidMount() { if (this.state.hasVirtualData && this.bodyNode) { this.lastScrollTop = this.bodyNode.scrollTop; } this.adjustScrollTop(); this.adjustSize(); this.reComputeSize(); }; VirtualTable.prototype.componentDidUpdate = function componentDidUpdate() { this.adjustScrollTop(); this.adjustSize(); this.reComputeSize(); }; VirtualTable.prototype.reComputeSize = function reComputeSize() { var _state = this.state, rowHeight = _state.rowHeight, hasVirtualData = _state.hasVirtualData; if (typeof rowHeight === 'function' && 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; } var count = 0; dataSource.forEach(function (item) { if (!item.__hidden) { count += 1; } }); return count * rowHeight; }; VirtualTable.prototype.computeInnerTop = function computeInnerTop() { var rowHeight = this.state.rowHeight; if (typeof rowHeight === 'function') { return 0; } var start = Math.max(this.start - THRESHOLD, 0); return start * rowHeight; }; VirtualTable.prototype.getVisibleRange = function getVisibleRange(ExpectStart) { var _state2 = this.state, height = _state2.height, rowHeight = _state2.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(_util.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.state.hasVirtualData && this.bodyNode) { this.bodyNode.scrollTop = this.lastScrollTop % this.state.rowHeight + this.state.rowHeight * this.state.scrollToRow; } }; VirtualTable.prototype.adjustSize = function adjustSize() { if (this.state.hasVirtualData && this.bodyNode) { var body = this.bodyNode; var virtualScrollNode = body.querySelector('div'); var clientHeight = body.clientHeight, clientWidth = body.clientWidth; var tableInc = this.tableInc; var tableNode = (0, _reactDom.findDOMNode)(tableInc); var prefix = this.props.prefix; var headerNode = tableNode.querySelector('.' + prefix + 'table-header table'); var headerClientWidth = headerNode && headerNode.clientWidth; // todo 2.0 设置宽度这个可以去掉 if (clientWidth < headerClientWidth) { _util.dom.setStyle(virtualScrollNode, 'min-width', headerClientWidth); var leftNode = this.bodyLeftNode; var rightNode = this.bodyRightNode; leftNode && _util.dom.setStyle(leftNode, 'max-height', clientHeight); rightNode && _util.dom.setStyle(rightNode, 'max-height', clientHeight); } else { _util.dom.setStyle(virtualScrollNode, 'min-width', 'auto'); } } }; 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 (0, _reactDom.findDOMNode)(this.tableInc.getRowRef(0)); } catch (error) { return null; } }; VirtualTable.prototype.render = function render() { /* eslint-disable no-unused-vars, prefer-const */ var _props = this.props, useVirtual = _props.useVirtual, components = _props.components, dataSource = _props.dataSource, fixedHeader = _props.fixedHeader, rowHeight = _props.rowHeight, scrollToRow = _props.scrollToRow, onBodyScroll = _props.onBodyScroll, others = (0, _objectWithoutProperties3.default)(_props, ['useVirtual', 'components', 'dataSource', 'fixedHeader', 'rowHeight', 'scrollToRow', 'onBodyScroll']); var entireDataSource = dataSource; var newDataSource = dataSource; this.rowSelection = this.props.rowSelection; if (this.state.hasVirtualData) { newDataSource = []; components = (0, _extends3.default)({}, components); var _getVisibleRange = this.getVisibleRange(this.state.scrollToRow), start = _getVisibleRange.start, end = _getVisibleRange.end; var count = -1; dataSource.forEach(function (current, index, record) { if (!current.__hidden) { count += 1; if (count >= Math.max(start - THRESHOLD, 0) && count < end) { newDataSource.push(current); } } current.__rowIndex = index; }); if (!components.Body) { components.Body = _body2.default; } fixedHeader = true; } return _react2.default.createElement(BaseComponent, (0, _extends3.default)({}, others, { scrollToRow: scrollToRow, dataSource: newDataSource, entireDataSource: entireDataSource, components: components, fixedHeader: fixedHeader })); }; return VirtualTable; }(_react2.default.Component), _class.VirtualBody = _body2.default, _class.propTypes = (0, _extends3.default)({ /** * 是否开启虚拟滚动 */ useVirtual: _propTypes2.default.bool, /** * 设置行高 */ rowHeight: _propTypes2.default.oneOfType([_propTypes2.default.number, _propTypes2.default.func]), maxBodyHeight: _propTypes2.default.oneOfType([_propTypes2.default.number, _propTypes2.default.string]), primaryKey: _propTypes2.default.oneOfType([_propTypes2.default.symbol, _propTypes2.default.string]), dataSource: _propTypes2.default.array, /** * 在内容区域滚动的时候触发的函数 */ onBodyScroll: _propTypes2.default.func }, BaseComponent.propTypes), _class.defaultProps = (0, _extends3.default)({}, BaseComponent.defaultProps, { primaryKey: 'id', rowHeight: noop, maxBodyHeight: 200, components: {}, prefix: 'next-', onBodyScroll: noop }), _class.childContextTypes = { onVirtualScroll: _propTypes2.default.func, bodyHeight: _propTypes2.default.number, innerTop: _propTypes2.default.number, getBodyNode: _propTypes2.default.func, getTableInstanceForVirtual: _propTypes2.default.func, rowSelection: _propTypes2.default.object }, _temp); VirtualTable.displayName = 'VirtualTable'; (0, _util2.statics)(VirtualTable, BaseComponent); return (0, _reactLifecyclesCompat.polyfill)(VirtualTable); } module.exports = exports['default'];