bee-tree/build/infiniteScroll.js

325 lines
12 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _react = require('react');
var _react2 = _interopRequireDefault(_react);
var _propTypes = require('prop-types');
var _propTypes2 = _interopRequireDefault(_propTypes);
var _util = require('./util');
var _config = require('./config');
var _config2 = _interopRequireDefault(_config);
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 _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 InfiniteScroll = function (_Component) {
_inherits(InfiniteScroll, _Component);
function InfiniteScroll(props) {
_classCallCheck(this, InfiniteScroll);
//默认显示20条rowsInView根据定高算的。在非固定高下这个只是一个大概的值。
var _this = _possibleConstructorReturn(this, _Component.call(this, props));
_this.eventListenerOptions = function () {
var options = _this.props.useCapture;
if (_this.isPassiveSupported()) {
options = {
useCapture: _this.props.useCapture,
passive: true
};
}
return options;
};
_this.mousewheelListener = function (e) {
// Prevents Chrome hangups
// See: https://stackoverflow.com/questions/47524205/random-high-content-download-time-in-chrome/47684257#47684257
if (e.deltaY === 1 && !_this.isPassiveSupported()) {
e.preventDefault();
}
};
_this.scrollListener = function () {
var el = _this.scrollComponent;
var parentNode = _this.getParentElement(el);
_this.scrollTop = parentNode.scrollTop;
_this.handleScrollY();
};
_this.handleScrollY = function () {
var store = _this.props.store;
var parentElement = _this.getParentElement(_this.scrollComponent);
if (!parentElement) {
return;
}
var scrollEl = parentElement;
var scrollY = scrollEl && scrollEl.clientHeight;
var rowHeight = store.getState().rowHeight;
//默认显示20条rowsInView根据定高算的。在非固定高下这个只是一个大概的值。
_this.rowsInView = scrollY ? Math.floor(scrollY / rowHeight) : _config2["default"].defaultRowsInView;
var currentIndex = _this.currentIndex,
startIndex = _this.startIndex,
endIndex = _this.endIndex,
treeList = _this.treeList,
loadCount = _this.loadCount,
rowsInView = _this.rowsInView;
var index = 0;
var tempScrollTop = _this.scrollTop;
//根据 scrollTop 计算 currentIndex
while (tempScrollTop > 0) {
tempScrollTop -= rowHeight;
if (tempScrollTop > 0) {
index += 1;
}
}
//true 为向下滚动, false 为向上滚动
var isScrollDown = index - currentIndex > 0 ? true : false;
if (index < 0) index = 0;
//如果之前的索引和下一次的不一样则重置索引和滚动的位置
_this.currentIndex = currentIndex !== index ? index : currentIndex;
// 如果rowsInView 小于 缓存的数据则重新render
// 向下滚动 下临界值超出缓存的endIndex则重新渲染
if (isScrollDown && rowsInView + index > endIndex - _config2["default"].rowDiff) {
startIndex = index - _config2["default"].loadBuffer > 0 ? index - _config2["default"].loadBuffer : 0;
endIndex = startIndex + loadCount;
if (endIndex > treeList.length) {
endIndex = treeList.length;
}
if (endIndex > _this.endIndex) {
_this.startIndex = startIndex;
_this.endIndex = endIndex;
_this.sliceTreeList(_this.startIndex, _this.endIndex);
}
}
// 向上滚动当前的index是否已经加载currentIndex若干上临界值小于startIndex则重新渲染
if (!isScrollDown && index < startIndex + _config2["default"].rowDiff) {
startIndex = index - _config2["default"].loadBuffer;
if (startIndex < 0) {
startIndex = 0;
}
if (startIndex <= _this.startIndex) {
_this.startIndex = startIndex;
_this.endIndex = _this.startIndex + loadCount;
_this.sliceTreeList(_this.startIndex, _this.endIndex);
}
}
};
_this.sliceTreeList = function (startIndex, endIndex) {
var newTreeList = []; //存储截取后的新数据
newTreeList = _this.treeList.slice(startIndex, endIndex);
_this.props.handleTreeListChange && _this.props.handleTreeListChange(newTreeList, startIndex, endIndex);
};
_this.rowsInView = _config2["default"].defaultRowsInView;
//一维数组
_this.treeList = props.treeList;
//一次加载多少数据
_this.loadCount = _config2["default"].loadBuffer ? _this.rowsInView + _config2["default"].loadBuffer * 2 : 16;
//可视区第一条数据的 index
_this.currentIndex = 0;
_this.startIndex = _this.currentIndex; //数据开始位置
_this.endIndex = _this.currentIndex + _this.loadCount; //数据结束位置
return _this;
}
InfiniteScroll.prototype.componentDidMount = function componentDidMount() {
this.options = this.eventListenerOptions();
this.attachScrollListener();
};
InfiniteScroll.prototype.componentWillReceiveProps = function componentWillReceiveProps(nextProps) {
var newTreeList = nextProps.treeList;
var oldTreeList = this.props.treeList;
if (newTreeList !== oldTreeList) {
this.treeList = newTreeList;
this.handleScrollY();
}
};
// componentDidUpdate() {
// const el = this.scrollComponent;
// const parentNode = this.getParentElement(el);
// parentNode.scrollTop = this.scrollTop;
// };
InfiniteScroll.prototype.componentWillUnmount = function componentWillUnmount() {
this.detachScrollListener();
this.detachMousewheelListener();
};
InfiniteScroll.prototype.isPassiveSupported = function isPassiveSupported() {
var passive = false;
var testOptions = {
get passive() {
passive = true;
}
};
try {
document.addEventListener('test', null, testOptions);
document.removeEventListener('test', null, testOptions);
} catch (e) {
// ignore
}
return passive;
};
/**
* 解除mousewheel事件监听
*/
InfiniteScroll.prototype.detachMousewheelListener = function detachMousewheelListener() {
var scrollEl = window;
if (this.props.useWindow === false) {
scrollEl = this.scrollComponent.parentNode;
}
scrollEl.removeEventListener('mousewheel', this.mousewheelListener, this.options ? this.options : this.props.useCapture);
};
/**
* 解除scroll事件监听
*/
InfiniteScroll.prototype.detachScrollListener = function detachScrollListener() {
var scrollEl = window;
if (this.props.useWindow === false) {
scrollEl = this.getParentElement(this.scrollComponent);
}
scrollEl.removeEventListener('scroll', this.scrollListener, this.options ? this.options : this.props.useCapture);
scrollEl.removeEventListener('resize', this.scrollListener, this.options ? this.options : this.props.useCapture);
};
/**
* 获取父组件(用户自定义父组件或者当前dom的parentNode)
* @param {*} el
*/
InfiniteScroll.prototype.getParentElement = function getParentElement(el) {
var scrollParent = this.props.getScrollParent && this.props.getScrollParent();
if (scrollParent != null) {
return scrollParent;
}
return el && el.parentNode;
};
InfiniteScroll.prototype.filterProps = function filterProps(props) {
return props;
};
/**
* 绑定scroll事件
*/
InfiniteScroll.prototype.attachScrollListener = function attachScrollListener() {
var store = this.props.store;
var parentElement = this.getParentElement(this.scrollComponent);
if (!parentElement) {
return;
}
var scrollEl = parentElement;
var scrollY = scrollEl && scrollEl.clientHeight;
var rowHeight = store.getState().rowHeight;
//默认显示20条rowsInView根据定高算的。
this.rowsInView = scrollY ? Math.floor(scrollY / rowHeight) : _config2["default"].defaultRowsInView;
scrollEl.addEventListener('scroll', (0, _util.throttle)(this.scrollListener, 150), this.options ? this.options : this.props.useCapture);
scrollEl.addEventListener('resize', (0, _util.throttle)(this.scrollListener, 150), this.options ? this.options : this.props.useCapture);
};
/**
* 滚动事件监听
*/
/**
* @description 根据返回的scrollTop计算当前的索引。
*/
/**
* 根据 startIndex 和 endIndex 截取数据
* @param startIndex
* @param endIndex
*/
InfiniteScroll.prototype.render = function render() {
var _this2 = this;
var _props = this.props,
children = _props.children,
element = _props.element,
ref = _props.ref,
getScrollParent = _props.getScrollParent,
treeList = _props.treeList,
handleTreeListChange = _props.handleTreeListChange,
store = _props.store,
props = _objectWithoutProperties(_props, ['children', 'element', 'ref', 'getScrollParent', 'treeList', 'handleTreeListChange', 'store']);
props.ref = function (node) {
_this2.scrollComponent = node;
if (ref) {
ref(node);
}
};
var childrenArray = [children];
return _react2["default"].createElement(element, props, childrenArray);
};
return InfiniteScroll;
}(_react.Component);
InfiniteScroll.propTypes = {
children: _propTypes2["default"].node.isRequired,
element: _propTypes2["default"].node,
ref: _propTypes2["default"].func,
getScrollParent: _propTypes2["default"].func,
treeList: _propTypes2["default"].array,
handleTreeListChange: _propTypes2["default"].func
};
InfiniteScroll.defaultProps = {
element: 'div',
ref: null,
getScrollParent: null,
treeList: [],
handleTreeListChange: function handleTreeListChange() {}
};
exports["default"] = InfiniteScroll;
module.exports = exports['default'];