like-scene-ui
Version:
315 lines (253 loc) • 11.7 kB
JavaScript
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;