UNPKG

like-scene-ui

Version:
315 lines (253 loc) 11.7 kB
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); } function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _iterableToArrayLimit(arr, i) { var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"]; if (_i == null) return; var _arr = []; var _n = true; var _d = false; var _s, _e; try { for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); } function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); } function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; } import React from 'react'; import { useState, useEffect, useRef, useLayoutEffect, useMemo } from 'react'; // import "./app.css" var ObserveTool = /*#__PURE__*/function () { function ObserveTool() { var _this = this; var moreHeight = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : "20px"; _classCallCheck(this, ObserveTool); this.map = void 0; this.observer = void 0; this.map = new Map(); this.observer = new IntersectionObserver(function (entries) { entries.forEach(function (entry) { if (entry.isIntersecting && !entry.target.__visible__) { entry.target.__visible__ = true; var cb = _this.map.get(entry.target); if (typeof cb === "function") { cb(true); } } if (!entry.isIntersecting && entry.target.__visible__) { entry.target.__visible__ = false; var _cb = _this.map.get(entry.target); if (typeof _cb === "function") { _cb(false); } } }); }, { rootMargin: "0px 0px ".concat(moreHeight, " 0px"), threshold: 0 }); } _createClass(ObserveTool, [{ key: "add", value: function add(ele, callback) { // 存在的话, 就更新 if (this.map.has(ele)) { this.map.set(ele, callback); return; } this.observer.observe(ele); this.map.set(ele, callback); } }, { key: "remove", value: function remove(ele) { this.observer.unobserve(ele); this.map.delete(ele); } }, { key: "removeAll", value: function removeAll() { var _this2 = this; _toConsumableArray(this.map.keys()).forEach(function (key) { _this2.observer.unobserve(key); }); this.map.clear(); } }, { key: "getAllObserveElements", value: function getAllObserveElements() { return _toConsumableArray(this.map.keys()); } }, { key: "disconnect", value: function disconnect() { this.observer.disconnect(); } }]); return ObserveTool; }(); // initPageCount 初始页大小, 为0代表自动调整 var VirsualList = function VirsualList(_ref) { var _ref$data = _ref.data, data = _ref$data === void 0 ? [] : _ref$data, children = _ref.children, _ref$initPageCount = _ref.initPageCount, initPageCount = _ref$initPageCount === void 0 ? 10 : _ref$initPageCount, _ref$height = _ref.height, height = _ref$height === void 0 ? "50vh" : _ref$height, _ref$autoAdjustPageCo = _ref.autoAdjustPageCount, autoAdjustPageCount = _ref$autoAdjustPageCo === void 0 ? true : _ref$autoAdjustPageCo; var _useState = useState(data), _useState2 = _slicedToArray(_useState, 2), totalList = _useState2[0], setTotalList = _useState2[1]; var _useState3 = useState(0), _useState4 = _slicedToArray(_useState3, 2), currentPage = _useState4[0], setCurrentPage = _useState4[1]; var _useState5 = useState([]), _useState6 = _slicedToArray(_useState5, 2), renderList = _useState6[0], setRenderList = _useState6[1]; var _useState7 = useState(false), _useState8 = _slicedToArray(_useState7, 2), resetFlag = _useState8[0], setResetFlag = _useState8[1]; var globalObserver = useMemo(function () { return new ObserveTool(); }, []); var topRef = useRef(null); var midRef = useRef(null); var bottomRef = useRef(null); var rootRef = useRef(null); var contentRef = useRef(null); var dataRef = useRef({ placeholdHeight: 0, contentTopBorderWidth: 0, pageCount: initPageCount, lastPage: 0, pageHeightInfo: {}, currentTop: 0 // 记录偏移top 值 }); // 数据变更,设置状态 useEffect(function () { dataRef.current.pageCount <= 0 ? dataRef.current.pageCount = 1 : null; setTotalList(data); }, [data]); // 监听页码改变 useLayoutEffect(function () { var pageCount = dataRef.current.pageCount; var start = currentPage * pageCount; var end = start + pageCount * 2; // 每次加载2页数据 var temp = totalList.slice(start, end); if (temp.length > 0) { var topIndex = 0; temp.splice(topIndex, 0, { __tag__: "__top__" }); } if (temp.length >= pageCount + 1) { var midIndex = pageCount + 1; temp.splice(midIndex, 0, { __tag__: "__mid__" }); } if (temp.length === pageCount * 2 + 2) { var bottomIndex = temp.length; temp.splice(bottomIndex, 0, { __tag__: "__bottom__" }); } // 下一页的滚动偏移 var transformY = 0; if (currentPage > dataRef.current.lastPage) { var _dataRef$current$page; // 下一页偏移 dataRef.current.currentTop += (_dataRef$current$page = dataRef.current.pageHeightInfo[currentPage - 1]) !== null && _dataRef$current$page !== void 0 ? _dataRef$current$page : 0; } else if (currentPage < dataRef.current.lastPage) { var _dataRef$current$page2; // 上一页滚动偏移 dataRef.current.currentTop -= (_dataRef$current$page2 = dataRef.current.pageHeightInfo[currentPage]) !== null && _dataRef$current$page2 !== void 0 ? _dataRef$current$page2 : 0; } transformY = dataRef.current.currentTop; // contentRef.current.style.transform = `translate(0, ${transformY}px)` contentRef.current && (contentRef.current.style.top = "".concat(transformY, "px")); // console.log(dataRef.current.pageHeightInfo) setRenderList(temp); // 记录上一页 dataRef.current.lastPage = currentPage; }, [currentPage, totalList, resetFlag]); // 监听上一页 / 下一页触发 useEffect(function () { // 列表改变, 重新监测两个dom的状态 if (topRef.current && bottomRef.current) { globalObserver.removeAll(); globalObserver.add(topRef.current, function (v) { // 顶部显示, 且为下拉 if (v && currentPage !== 0) { if (currentPage === 0) { return; } setCurrentPage(currentPage - 1); } }); globalObserver.add(bottomRef.current, function (v) { if (v) { if (currentPage >= Math.ceil(totalList.length / dataRef.current.pageCount) - 2) { return; } setCurrentPage(currentPage + 1); } }); } }, [renderList, currentPage, dataRef.current.pageCount]); // 缓存每一页高度, 用于后续计算; (自动调整页大小:小: 一页不够一屏, 大: 一页大于3屏) useEffect(function () { if (!topRef.current || !midRef.current || !bottomRef.current || !rootRef.current) return; dataRef.current.pageHeightInfo[currentPage] = midRef.current.offsetTop - topRef.current.offsetTop - topRef.current.offsetHeight; dataRef.current.pageHeightInfo[currentPage + 1] = bottomRef.current.offsetTop - midRef.current.offsetTop - midRef.current.offsetHeight; // 自动修正外界传递错误的页大小 if (dataRef.current.pageCount <= 0 || dataRef.current.pageHeightInfo[currentPage] < rootRef.current.offsetHeight) { if (autoAdjustPageCount) { // 因为支持不定长cell; 无法通过比例推算出大小, 会导致过大情况, 所以选择累加计算操作 console.log("%c自动调整页大小(+1)...", "color: green"); dataRef.current.pageCount += 1; setResetFlag(!resetFlag); } else { console.warn("pageCount太小, 会导致闪屏现象! 请手动调整大小,或设置 autoAdjustPageCount = true 自动调整!"); } } }, [renderList, dataRef.current.pageCount]); return /*#__PURE__*/React.createElement("div", { ref: rootRef, style: { height: height, overflowY: "auto", backgroundColor: "grey", position: "relative" } }, /*#__PURE__*/React.createElement("div", { ref: contentRef, style: { position: "absolute", left: 0, top: 0, width: "100%" } }, renderList.map(function (item) { if (item.__tag__) { var ref; switch (item.__tag__) { case "__top__": ref = topRef; break; case "__mid__": ref = midRef; break; case "__bottom__": ref = bottomRef; break; } return /*#__PURE__*/React.createElement("div", { id: item.__tag__, ref: ref, key: item.__tag__, style: { height: "".concat(dataRef.current.placeholdHeight, "px"), backgroundColor: "transparent" } }); } if (typeof children === "function") { return children(item); } return children; }))); }; export default VirsualList;