UNPKG

@nutui/nutui-react-taro

Version:

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

185 lines (184 loc) 7.37 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 _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 _components = require("@tarojs/components"); var _classnames = /*#__PURE__*/ _interop_require_default._(require("classnames")); var _getsysteminfo = require("../../utils/taro/get-system-info"); var _utils = require("./utils"); var _typings = require("../../utils/typings"); var defaultProps = (0, _object_spread_props._)((0, _object_spread._)({}, _typings.ComponentDefaults), { list: [], itemHeight: 66, margin: 10, itemEqual: true, overscan: 2 }); var VirtualList = function VirtualList(props) { var _ref = (0, _object_spread._)({}, defaultProps, props), list = _ref.list, itemRender = _ref.itemRender, itemHeight = _ref.itemHeight, margin = _ref.margin, itemEqual = _ref.itemEqual, overscan = _ref.overscan, key = _ref.key, onScroll = _ref.onScroll, className = _ref.className, origContainerHeight = _ref.containerHeight, rest = (0, _object_without_properties._)(_ref, [ "list", "itemRender", "itemHeight", "margin", "itemEqual", "overscan", "key", "onScroll", "className", "containerHeight" ]); var clientHeight = (0, _react.useMemo)(function() { return (0, _getsysteminfo.getWindowInfo)().windowHeight - 5 || 667; }, []); var containerHeight = (0, _react.useMemo)(function() { return origContainerHeight !== null && origContainerHeight !== void 0 ? origContainerHeight : clientHeight; }, [ origContainerHeight, clientHeight ]); var _useState = (0, _sliced_to_array._)((0, _react.useState)(0), 2), startOffset = _useState[0], setStartOffset = _useState[1]; var start = (0, _react.useRef)(0); // 虚拟列表容器ref var scrollRef = (0, _react.useRef)(null); // 虚拟列表显示区域ref var itemsRef = (0, _react.useRef)(null); // 列表位置信息 var _useState1 = (0, _sliced_to_array._)((0, _react.useState)([ { index: 0, left: 0, top: 0, bottom: 0, width: 0, height: 0, right: 0 } ]), 2), positions = _useState1[0], setPositions = _useState1[1]; var _useState2 = (0, _sliced_to_array._)((0, _react.useState)(containerHeight || 0), 2), offSetSize = _useState2[0], setOffSetSize = _useState2[1]; // 初始计算可视区域展示数量 (0, _react.useEffect)(function() { setPositions(function(options) { return (0, _object_spread_props._)((0, _object_spread._)({}, options), { endIndex: visibleCount() }); }); }, [ itemHeight, overscan, offSetSize ]); (0, _react.useEffect)(function() { if (containerHeight) return; setOffSetSize(getContainerHeight()); }, [ containerHeight ]); (0, _react.useEffect)(function() { var pos = (0, _utils.initPositinoCache)(itemHeight + margin, list.length); setPositions(pos); }, [ itemHeight, list ]); // 可视区域总高度 var getContainerHeight = function getContainerHeight() { // 初始首页列表高度 var initH = (itemHeight + margin) * list.length; // 未设置containerHeight高度,判断首页高度小于设备高度时,滚动容器高度为首页数据高度,减5为分页触发的偏移量 return initH < clientHeight ? initH + overscan * (itemHeight + margin) - 5 : Math.min(containerHeight, clientHeight) // Math.min(containerHeight, clientHeight) ; }; // 可视区域条数 var visibleCount = function visibleCount() { return Math.ceil(getContainerHeight() / (itemHeight + margin)) + overscan; }; var end = function end() { return start.current + visibleCount(); }; var listHeight = function listHeight() { return list.length * (itemHeight + margin); }; var visibleData = function visibleData() { return list.slice(start.current, Math.min(end(), list.length)); }; var updateTotalSize = (0, _react.useCallback)(function() { if (!itemsRef.current) return; var items = itemsRef.current.children; if (!items.length) return; // 更新缓存 (0, _utils.updateItemSize)(positions, items, 'height', margin); }, [ positions ]); // 滚动监听 var listScroll = function listScroll(e) { var scrollTop = e.target.scrollTop; if (scrollTop <= 0) { e.target.scrollTop = 0; return setStartOffset(0); } if (!itemEqual) { updateTotalSize(); } start.current = Math.floor(scrollTop / (itemHeight + margin)); setStartOffset(scrollTop - scrollTop % (itemHeight + margin)); var endIndex = end(); // list 变动说明触底 if (endIndex > list.length - 1) { onScroll && onScroll(); } }; return /*#__PURE__*/ _react.default.createElement(_components.View, (0, _object_spread_props._)((0, _object_spread._)({ className: (0, _classnames.default)('nut-virtualList-box', className) }, rest), { style: { height: containerHeight ? "".concat(offSetSize, "px") : '' } }), /*#__PURE__*/ _react.default.createElement(_components.ScrollView, { scrollY: true, bounces: false, type: "list", ref: scrollRef, className: "nut-virtuallist", style: { height: "".concat(getContainerHeight(), "px") }, onScroll: listScroll }, /*#__PURE__*/ _react.default.createElement(_components.View, { className: "nut-virtuallist-phantom", style: { height: "".concat(listHeight(), "px") } }), /*#__PURE__*/ _react.default.createElement(_components.View, { className: "nut-virtuallist-container", ref: itemsRef, style: { transform: "translate3d(0, ".concat(startOffset, "px, 0)") } }, visibleData().map(function(data, index) { var dataIndex = start.current + index; var keyVal = key && data[key] ? data[key] : dataIndex; return /*#__PURE__*/ _react.default.createElement(_components.View, { "data-index": "".concat(dataIndex), className: "nut-virtuallist-item", key: "".concat(keyVal), style: { height: "".concat(itemEqual ? "".concat(itemHeight, "px") : 'auto') } }, itemRender ? itemRender(data, dataIndex, index) : data); })))); }; VirtualList.displayName = 'NutVirtualList';