UNPKG

12.5 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6
7var _react = require('react');
8
9var _react2 = _interopRequireDefault(_react);
10
11var _propTypes = require('prop-types');
12
13var _propTypes2 = _interopRequireDefault(_propTypes);
14
15var _util = require('./util');
16
17var _config = require('./config');
18
19var _config2 = _interopRequireDefault(_config);
20
21function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
22
23function _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; }
24
25function _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; }
26
27function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
28
29function _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; }
30
31function _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); } /**
32 * 处理滚动加载逻辑
33 */
34
35
36var InfiniteScroll = function (_Component) {
37 _inherits(InfiniteScroll, _Component);
38
39 function InfiniteScroll(props) {
40 _classCallCheck(this, InfiniteScroll);
41
42 //默认显示20条,rowsInView根据定高算的。在非固定高下,这个只是一个大概的值。
43 var _this = _possibleConstructorReturn(this, _Component.call(this, props));
44
45 _this.eventListenerOptions = function () {
46 var options = _this.props.useCapture;
47
48 if (_this.isPassiveSupported()) {
49 options = {
50 useCapture: _this.props.useCapture,
51 passive: true
52 };
53 }
54 return options;
55 };
56
57 _this.mousewheelListener = function (e) {
58 // Prevents Chrome hangups
59 // See: https://stackoverflow.com/questions/47524205/random-high-content-download-time-in-chrome/47684257#47684257
60 if (e.deltaY === 1 && !_this.isPassiveSupported()) {
61 e.preventDefault();
62 }
63 };
64
65 _this.scrollListener = function () {
66 var el = _this.scrollComponent;
67 var parentNode = _this.getParentElement(el);
68 _this.scrollTop = parentNode.scrollTop;
69 _this.handleScrollY();
70 };
71
72 _this.handleScrollY = function () {
73 var store = _this.props.store;
74
75 var parentElement = _this.getParentElement(_this.scrollComponent);
76 if (!parentElement) {
77 return;
78 }
79 var scrollEl = parentElement;
80 var scrollY = scrollEl && scrollEl.clientHeight;
81
82 var rowHeight = store.getState().rowHeight;
83 //默认显示20条,rowsInView根据定高算的。在非固定高下,这个只是一个大概的值。
84 _this.rowsInView = scrollY ? Math.floor(scrollY / rowHeight) : _config2["default"].defaultRowsInView;
85
86 var currentIndex = _this.currentIndex,
87 startIndex = _this.startIndex,
88 endIndex = _this.endIndex,
89 treeList = _this.treeList,
90 loadCount = _this.loadCount,
91 rowsInView = _this.rowsInView;
92
93 var index = 0;
94 var tempScrollTop = _this.scrollTop;
95 //根据 scrollTop 计算 currentIndex
96 while (tempScrollTop > 0) {
97 tempScrollTop -= rowHeight;
98 if (tempScrollTop > 0) {
99 index += 1;
100 }
101 }
102
103 //true 为向下滚动, false 为向上滚动
104 var isScrollDown = index - currentIndex > 0 ? true : false;
105
106 if (index < 0) index = 0;
107 //如果之前的索引和下一次的不一样则重置索引和滚动的位置
108 _this.currentIndex = currentIndex !== index ? index : currentIndex;
109
110 // 如果rowsInView 小于 缓存的数据则重新render
111 // 向下滚动 下临界值超出缓存的endIndex则重新渲染
112 if (isScrollDown && rowsInView + index > endIndex - _config2["default"].rowDiff) {
113 startIndex = index - _config2["default"].loadBuffer > 0 ? index - _config2["default"].loadBuffer : 0;
114 endIndex = startIndex + loadCount;
115 if (endIndex > treeList.length) {
116 endIndex = treeList.length;
117 }
118 if (endIndex > _this.endIndex) {
119 _this.startIndex = startIndex;
120 _this.endIndex = endIndex;
121 _this.sliceTreeList(_this.startIndex, _this.endIndex);
122 }
123 }
124 // 向上滚动,当前的index是否已经加载(currentIndex),若干上临界值小于startIndex则重新渲染
125 if (!isScrollDown && index < startIndex + _config2["default"].rowDiff) {
126 startIndex = index - _config2["default"].loadBuffer;
127 if (startIndex < 0) {
128 startIndex = 0;
129 }
130 if (startIndex <= _this.startIndex) {
131 _this.startIndex = startIndex;
132 _this.endIndex = _this.startIndex + loadCount;
133 _this.sliceTreeList(_this.startIndex, _this.endIndex);
134 }
135 }
136 };
137
138 _this.sliceTreeList = function (startIndex, endIndex) {
139 var newTreeList = []; //存储截取后的新数据
140 newTreeList = _this.treeList.slice(startIndex, endIndex);
141 _this.props.handleTreeListChange && _this.props.handleTreeListChange(newTreeList, startIndex, endIndex);
142 };
143
144 _this.rowsInView = _config2["default"].defaultRowsInView;
145 //一维数组
146 _this.treeList = props.treeList;
147 //一次加载多少数据
148 _this.loadCount = _config2["default"].loadBuffer ? _this.rowsInView + _config2["default"].loadBuffer * 2 : 16;
149 //可视区第一条数据的 index
150 _this.currentIndex = 0;
151 _this.startIndex = _this.currentIndex; //数据开始位置
152 _this.endIndex = _this.currentIndex + _this.loadCount; //数据结束位置
153 return _this;
154 }
155
156 InfiniteScroll.prototype.componentDidMount = function componentDidMount() {
157 this.options = this.eventListenerOptions();
158 this.attachScrollListener();
159 };
160
161 InfiniteScroll.prototype.componentWillReceiveProps = function componentWillReceiveProps(nextProps) {
162 var newTreeList = nextProps.treeList;
163 var oldTreeList = this.props.treeList;
164
165 if (newTreeList !== oldTreeList) {
166 this.treeList = newTreeList;
167 this.handleScrollY();
168 }
169 };
170
171 // componentDidUpdate() {
172 // const el = this.scrollComponent;
173 // const parentNode = this.getParentElement(el);
174 // parentNode.scrollTop = this.scrollTop;
175 // };
176
177 InfiniteScroll.prototype.componentWillUnmount = function componentWillUnmount() {
178 this.detachScrollListener();
179 this.detachMousewheelListener();
180 };
181
182 InfiniteScroll.prototype.isPassiveSupported = function isPassiveSupported() {
183 var passive = false;
184
185 var testOptions = {
186 get passive() {
187 passive = true;
188 }
189 };
190
191 try {
192 document.addEventListener('test', null, testOptions);
193 document.removeEventListener('test', null, testOptions);
194 } catch (e) {
195 // ignore
196 }
197 return passive;
198 };
199
200 /**
201 * 解除mousewheel事件监听
202 */
203 InfiniteScroll.prototype.detachMousewheelListener = function detachMousewheelListener() {
204 var scrollEl = window;
205 if (this.props.useWindow === false) {
206 scrollEl = this.scrollComponent.parentNode;
207 }
208
209 scrollEl.removeEventListener('mousewheel', this.mousewheelListener, this.options ? this.options : this.props.useCapture);
210 };
211 /**
212 * 解除scroll事件监听
213 */
214
215
216 InfiniteScroll.prototype.detachScrollListener = function detachScrollListener() {
217 var scrollEl = window;
218 if (this.props.useWindow === false) {
219 scrollEl = this.getParentElement(this.scrollComponent);
220 }
221
222 scrollEl.removeEventListener('scroll', this.scrollListener, this.options ? this.options : this.props.useCapture);
223 scrollEl.removeEventListener('resize', this.scrollListener, this.options ? this.options : this.props.useCapture);
224 };
225 /**
226 * 获取父组件(用户自定义父组件或者当前dom的parentNode)
227 * @param {*} el
228 */
229
230
231 InfiniteScroll.prototype.getParentElement = function getParentElement(el) {
232 var scrollParent = this.props.getScrollParent && this.props.getScrollParent();
233 if (scrollParent != null) {
234 return scrollParent;
235 }
236 return el && el.parentNode;
237 };
238
239 InfiniteScroll.prototype.filterProps = function filterProps(props) {
240 return props;
241 };
242 /**
243 * 绑定scroll事件
244 */
245
246
247 InfiniteScroll.prototype.attachScrollListener = function attachScrollListener() {
248 var store = this.props.store;
249
250 var parentElement = this.getParentElement(this.scrollComponent);
251 if (!parentElement) {
252 return;
253 }
254 var scrollEl = parentElement;
255 var scrollY = scrollEl && scrollEl.clientHeight;
256
257 var rowHeight = store.getState().rowHeight;
258 //默认显示20条,rowsInView根据定高算的。
259 this.rowsInView = scrollY ? Math.floor(scrollY / rowHeight) : _config2["default"].defaultRowsInView;
260
261 scrollEl.addEventListener('scroll', (0, _util.throttle)(this.scrollListener, 150), this.options ? this.options : this.props.useCapture);
262 scrollEl.addEventListener('resize', (0, _util.throttle)(this.scrollListener, 150), this.options ? this.options : this.props.useCapture);
263 };
264 /**
265 * 滚动事件监听
266 */
267
268
269 /**
270 * @description 根据返回的scrollTop计算当前的索引。
271 */
272
273
274 /**
275 * 根据 startIndex 和 endIndex 截取数据
276 * @param startIndex
277 * @param endIndex
278 */
279
280
281 InfiniteScroll.prototype.render = function render() {
282 var _this2 = this;
283
284 var _props = this.props,
285 children = _props.children,
286 element = _props.element,
287 ref = _props.ref,
288 getScrollParent = _props.getScrollParent,
289 treeList = _props.treeList,
290 handleTreeListChange = _props.handleTreeListChange,
291 store = _props.store,
292 props = _objectWithoutProperties(_props, ['children', 'element', 'ref', 'getScrollParent', 'treeList', 'handleTreeListChange', 'store']);
293
294 props.ref = function (node) {
295 _this2.scrollComponent = node;
296 if (ref) {
297 ref(node);
298 }
299 };
300
301 var childrenArray = [children];
302
303 return _react2["default"].createElement(element, props, childrenArray);
304 };
305
306 return InfiniteScroll;
307}(_react.Component);
308
309InfiniteScroll.propTypes = {
310 children: _propTypes2["default"].node.isRequired,
311 element: _propTypes2["default"].node,
312 ref: _propTypes2["default"].func,
313 getScrollParent: _propTypes2["default"].func,
314 treeList: _propTypes2["default"].array,
315 handleTreeListChange: _propTypes2["default"].func
316};
317InfiniteScroll.defaultProps = {
318 element: 'div',
319 ref: null,
320 getScrollParent: null,
321 treeList: [],
322 handleTreeListChange: function handleTreeListChange() {}
323};
324exports["default"] = InfiniteScroll;
325module.exports = exports['default'];
\No newline at end of file