@nutui/nutui-react
Version:
京东风格的轻量级移动端 React 组件库,支持一套代码生成 H5 和小程序
222 lines (221 loc) • 8.75 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "VirtualList", {
enumerable: true,
get: function() {
return VirtualList;
}
});
var _interop_require_default = require("@swc/helpers/_/_interop_require_default");
var _interop_require_wildcard = require("@swc/helpers/_/_interop_require_wildcard");
var _define_property = require("@swc/helpers/_/_define_property");
var _object_spread = require("@swc/helpers/_/_object_spread");
var _object_spread_props = require("@swc/helpers/_/_object_spread_props");
var _object_without_properties = require("@swc/helpers/_/_object_without_properties");
var _sliced_to_array = require("@swc/helpers/_/_sliced_to_array");
var _react = /*#__PURE__*/ _interop_require_wildcard._(require("react"));
var _classnames = /*#__PURE__*/ _interop_require_default._(require("classnames"));
var _utils = require("./utils");
var _typings = require("../../utils/typings");
var defaultProps = (0, _object_spread_props._)((0, _object_spread._)({}, _typings.ComponentDefaults), {
list: [],
itemHeight: 66,
itemEqual: true,
direction: 'vertical',
overscan: 2
});
var VirtualList = function VirtualList(props) {
var _ref = (0, _object_spread._)({}, defaultProps, props), list = _ref.list, itemRender = _ref.itemRender, itemEqual = _ref.itemEqual, itemHeight = _ref.itemHeight, direction = _ref.direction, overscan = _ref.overscan, key = _ref.key, onScroll = _ref.onScroll, className = _ref.className, containerHeight = _ref.containerHeight, rest = (0, _object_without_properties._)(_ref, [
"list",
"itemRender",
"itemEqual",
"itemHeight",
"direction",
"overscan",
"key",
"onScroll",
"className",
"containerHeight"
]);
var horizontal = direction === 'horizontal';
var sizeKey = horizontal ? 'width' : 'height';
var scrollKey = horizontal ? 'scrollLeft' : 'scrollTop';
var offsetKey = horizontal ? 'left' : 'top';
// 虚拟列表容器ref
var scrollRef = (0, _react.useRef)(null);
// 虚拟列表显示区域ref
var itemsRef = (0, _react.useRef)(null);
// 列表位置信息
var _useState = (0, _sliced_to_array._)((0, _react.useState)([
{
index: 0,
left: 0,
top: 0,
bottom: 0,
width: 0,
height: 0,
right: 0
}
]), 2), positions = _useState[0], setPositions = _useState[1];
// 列表总大小
var _useState1 = (0, _sliced_to_array._)((0, _react.useState)(99999999), 2), listTotalSize = _useState1[0], setListTotalSize = _useState1[1];
// 可视区域条数
var _useState2 = (0, _sliced_to_array._)((0, _react.useState)(0), 2), visibleCount = _useState2[0], setVisibleCount = _useState2[1];
var _useState3 = (0, _sliced_to_array._)((0, _react.useState)(containerHeight || 0), 2), offSetSize = _useState3[0], setOffSetSize = _useState3[1];
var _useState4 = (0, _sliced_to_array._)((0, _react.useState)({
startOffset: 0,
startIndex: 0,
overStart: 0,
endIndex: 10
}), 2), options = _useState4[0], setOptions = _useState4[1];
// 列表位置信息
(0, _react.useEffect)(function() {
var pos = (0, _utils.initPositinoCache)(itemHeight, list.length);
setPositions(pos);
var totalSize = (0, _utils.getListTotalSize)(pos, horizontal);
setListTotalSize(totalSize);
}, [
list,
itemHeight,
horizontal
]);
var getElement = (0, _react.useCallback)(function() {
var _scrollRef_current;
return ((_scrollRef_current = scrollRef.current) === null || _scrollRef_current === void 0 ? void 0 : _scrollRef_current.parentElement) || document.body;
}, []);
(0, _react.useEffect)(function() {
if (containerHeight) return;
var size = horizontal ? getElement().offsetWidth : getElement().offsetHeight;
setOffSetSize(size);
}, [
getElement,
horizontal,
containerHeight
]);
(0, _react.useEffect)(function() {
// 初始-计算visibleCount
if (offSetSize === 0) return;
var count = Math.ceil(offSetSize / itemHeight) + overscan;
setVisibleCount(count);
setOptions(function(options) {
return (0, _object_spread_props._)((0, _object_spread._)({}, options), {
endIndex: count
});
});
}, [
getElement,
horizontal,
itemHeight,
overscan,
offSetSize
]);
var updateTotalSize = (0, _react.useCallback)(function() {
if (!itemsRef.current) return;
var items = itemsRef.current.children;
if (!items.length) return;
// 更新缓存
(0, _utils.updateItemSize)(positions, items, sizeKey);
var totalSize = (0, _utils.getListTotalSize)(positions, horizontal);
setListTotalSize(totalSize);
}, [
positions,
sizeKey,
horizontal
]);
var scroll = (0, _react.useCallback)(function() {
requestAnimationFrame(function(e) {
var scrollSize = getElement()[scrollKey];
var startIndex = (0, _utils.binarySearch)(positions, horizontal, scrollSize);
var overStart = startIndex - overscan > -1 ? startIndex - overscan : 0;
// const offSetSize = horizontal ? getElement().offsetWidth : getElement().offsetHeight
if (!itemEqual) {
updateTotalSize();
}
var endIndex = (0, _utils.getEndIndex)({
list: list,
startIndex: startIndex,
visibleCount: visibleCount,
itemEqual: itemEqual,
positions: positions,
offSetSize: offSetSize,
sizeKey: sizeKey,
overscan: overscan
});
var startOffset = positions[startIndex][offsetKey];
setOptions({
startOffset: startOffset,
startIndex: startIndex,
overStart: overStart,
endIndex: endIndex
});
// 无限下滑
if (endIndex > list.length - 1) {
if (onScroll) {
onScroll();
}
}
});
}, [
positions,
getElement,
list,
visibleCount,
itemEqual,
updateTotalSize,
offsetKey,
sizeKey,
scrollKey,
horizontal,
overscan,
offSetSize
]);
(0, _react.useEffect)(function() {
var element = getElement();
element.addEventListener('scroll', scroll, false);
return function() {
element.removeEventListener('scroll', scroll, false);
};
}, [
getElement,
scroll
]);
return /*#__PURE__*/ _react.default.createElement("div", (0, _object_spread_props._)((0, _object_spread._)({
className: (0, _classnames.default)('nut-virtualList-box', className)
}, rest), {
style: (0, _define_property._)({}, sizeKey, containerHeight ? "".concat(offSetSize, "px") : '')
}), /*#__PURE__*/ _react.default.createElement("div", {
ref: scrollRef,
className: (0, _classnames.default)({
'nut-horizontal-box': horizontal,
'nut-vertical-box': !horizontal
}),
style: (0, _define_property._)({
position: 'relative'
}, sizeKey, "".concat(listTotalSize, "px"))
}, /*#__PURE__*/ _react.default.createElement("ul", {
className: (0, _classnames.default)('nut-virtuallist-items', {
'nut-horizontal-items': horizontal,
'nut-vertical-items': !horizontal
}),
ref: itemsRef,
style: {
transform: horizontal ? "translate3d(".concat(options.startOffset, "px,0,0)") : "translate3d(0,".concat(options.startOffset, "px,0)")
}
}, list.slice(options.overStart, options.endIndex).map(function(data, index) {
var startIndex = options.startIndex, overStart = options.overStart;
var dataIndex = overStart + index;
var styleVal = dataIndex < startIndex ? 'none' : 'block';
var keyVal = key && data[key] ? data[key] : dataIndex;
return /*#__PURE__*/ _react.default.createElement("li", {
"data-index": "".concat(dataIndex),
className: "nut-virtuallist-item",
key: "".concat(keyVal),
style: {
display: styleVal
}
}, itemRender ? itemRender(data, dataIndex, index) : data);
}))));
};
VirtualList.displayName = 'NutVirtualList';