UNPKG

@nutui/nutui-react

Version:

京东风格的轻量级移动端 React 组件库,支持一套代码生成 H5 和小程序

222 lines (221 loc) 8.75 kB
"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';