import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray"; import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2"; import { createVNode as _createVNode } from "vue"; import { defineComponent, nextTick, onMounted, ref, computed, unref, getCurrentInstance } from 'vue'; import { memoize } from 'lodash'; import { Empty } from '../../../components'; var Scroll = defineComponent({ name: 'Scroll', props: { dataSource: { type: Array, default: function _default() { return []; } }, total: { type: Number, default: 0 }, windowHeight: { // 可视高度 type: Number, default: 500 }, bodyStyle: { type: Object, default: function _default() { return {}; } }, column: { type: Number, default: 4 } }, slots: ['prev'], emits: ['reachBottom'], setup: function setup(props, _ref) { var slots = _ref.slots, emit = _ref.emit; var windowRef = ref(); var innerRef = ref(); var itemRef = ref(); var columnSpan = 20; var rowSpan = 20; var windowWidth = ref(0); var _scrollTop = ref(0); var loading = ref(true); var cardWidth = ref(0); var cardHeight = ref(0); // 每排展示的卡片数量 var totalRow = computed(function () { return (props === null || props === void 0 ? void 0 : props.column) || 4; }); // computed(() => Math.floor((windowWidth.value + rowSpan) / (cardWidth.value + rowSpan))) // 总共展示的列数 var totalColumn = computed(function () { return Math.ceil(props.total / totalRow.value); }); var states = ref({ isScrolling: false, scrollTop: 0, updateRequested: false, yAxisScrollDir: 'forward' }); var useCache = function useCache() { var vm = getCurrentInstance(); return computed(function () { var _getItemStyleCache = function _getItemStyleCache(_) { return {}; }; return memoize(_getItemStyleCache); }); }; var getItemStyleCache = useCache(); /** * 计算可视区域的列 */ var getColumnsStartIndexForOffset = function getColumnsStartIndexForOffset(scrollTop) { return Math.max(0, Math.min(totalColumn.value - 1, Math.floor(scrollTop / (cardHeight.value + columnSpan)))); }; var getColumnsStopIndexForStartIndex = function getColumnsStopIndexForStartIndex(_ref2, startIndex, scrollTop) { var windowHeight = _ref2.windowHeight; var numVisibleRows = Math.ceil(windowHeight / (cardHeight.value + columnSpan)); return Math.max(0, Math.min(totalColumn.value - 1, startIndex + numVisibleRows - 1)); }; var columnsToRender = computed(function () { var _unref = unref(states), isScrolling = _unref.isScrolling, yAxisScrollDir = _unref.yAxisScrollDir, scrollTop = _unref.scrollTop; if (totalColumn.value === 0 || totalRow.value === 0) { return [0, 0, 0, 0]; } var startIndex = getColumnsStartIndexForOffset(scrollTop); var stopIndex = getColumnsStopIndexForStartIndex(props, startIndex, scrollTop); // const cacheBackward = !isScrolling || yAxisScrollDir === 'backward' ? 2 : 1 // const cacheForward = !isScrolling || yAxisScrollDir === 'forward' ? 2 : 1 return [Math.max(0, startIndex), Math.max(0, Math.min(totalColumn.value - 1, stopIndex)), startIndex, stopIndex]; }); var emitEvents = function emitEvents() { var _unref2 = unref(states), isScrolling = _unref2.isScrolling, scrollTop = _unref2.scrollTop, updateRequested = _unref2.updateRequested, yAxisScrollDir = _unref2.yAxisScrollDir; if (updateRequested && isScrolling && yAxisScrollDir === 'forward' && scrollTop > 0) { var t = scrollTop - _scrollTop.value; if (t > cardHeight.value * 2) { _scrollTop.value = scrollTop; emit('reachBottom', scrollTop); } } }; var getScrollDir = function getScrollDir(prev, cur) { return prev < cur ? 'forward' : 'backward'; }; var resetIsScrolling = function resetIsScrolling() { states.value.isScrolling = false; nextTick(function () { getItemStyleCache.value(-1, null, null); }); }; var onUpdated = function onUpdated() { var _unref3 = unref(states), scrollLeft = _unref3.scrollLeft, scrollTop = _unref3.scrollTop, updateRequested = _unref3.updateRequested; var windowElement = unref(windowRef); if (updateRequested && windowElement) { windowElement.scrollLeft = Math.max(0, scrollLeft); windowElement.scrollTop = Math.max(0, scrollTop); } }; var onScroll = function onScroll(e) { var _e$currentTarget = e.currentTarget, clientHeight = _e$currentTarget.clientHeight, clientWidth = _e$currentTarget.clientWidth, scrollHeight = _e$currentTarget.scrollHeight, scrollTop = _e$currentTarget.scrollTop, scrollWidth = _e$currentTarget.scrollWidth; var _states = unref(states); if (_states.scrollTop === scrollTop) { return; } var _scrollTop = Math.max(0, Math.min(scrollTop, scrollHeight - clientHeight)); states.value = _objectSpread(_objectSpread({}, _states), {}, { isScrolling: true, scrollTop: _scrollTop, updateRequested: true, yAxisScrollDir: getScrollDir(_states.scrollTop, scrollTop) }); nextTick(function () { return resetIsScrolling(); }); onUpdated(); emitEvents(); }; var getTopPosition = function getTopPosition(index) { return index * (cardHeight.value + columnSpan); }; var getLeftPosition = function getLeftPosition(index) { return index * (cardWidth.value + rowSpan); }; var getItemStyle = function getItemStyle(rowIndex, columnIndex) { var itemStyleCache = getItemStyleCache.value; // since there was no need to introduce an nested array into cache object // we use row,column to construct the key for indexing the map. var key = "".concat(rowIndex, ",").concat(columnIndex); if (itemStyleCache.hasOwnProperty(key)) { return itemStyleCache[key]; } else { var left = getLeftPosition(rowIndex); var top = getTopPosition(columnIndex); itemStyleCache[key] = { position: 'absolute', left: "".concat(left, "px"), top: "".concat(top, "px"), height: "".concat(cardHeight.value, "px"), width: "".concat(cardWidth.value, "px") }; return itemStyleCache[key]; } }; var renderItems = function renderItems() { var _unref4 = unref(columnsToRender), _unref5 = _slicedToArray(_unref4, 2), columnStart = _unref5[0], columnEnd = _unref5[1]; var children = []; if (totalRow.value > 0 && totalColumn.value > 0) { for (var column = columnStart; column <= columnEnd; column++) { for (var row = 0; row < totalRow.value; row++) { var _index = slots.prev ? totalRow.value * column + row - 1 : totalRow.value * column + row; children.push(_createVNode("div", { "key": "".concat(row, ":").concat(column), "style": _objectSpread({}, getItemStyle(row, column)) }, [slots.prev && row === 0 && column === 0 ? slots.prev() : props.dataSource[_index] && slots.card && slots.card(props.dataSource[_index], _index)])); } } } else if (slots.prev) { children.push(_createVNode("div", { "key": "".concat(0, ":", 0), "style": _objectSpread({}, getItemStyle(0, 0)) }, [slots.prev && slots.prev()])); } return children; }; onMounted(function () { loading.value = true; // 计算卡片的宽度和高度 if (windowRef.value) { windowWidth.value = windowRef.value.offsetWidth || 0; cardHeight.value = itemRef.value.offsetHeight || 0; cardWidth.value = Math.ceil(windowWidth.value / totalRow.value - rowSpan); loading.value = false; } }); return function () { return _createVNode("div", { "class": 'wrapper', "style": props.bodyStyle }, [_createVNode("div", { "class": 'window', "style": { position: 'relative', overflowY: 'scroll', WebkitOverflowScrolling: 'touch', willChange: 'transform', height: props.windowHeight ? "".concat(props.windowHeight, "px") : '100%', width: '100%' }, "onScroll": onScroll, "ref": function ref(el) { return windowRef.value = el; } }, [loading.value ? _createVNode("div", { "ref": function ref(el) { return itemRef.value = el; } }, [slots.card && slots.card('', 0), _createVNode("div", { "style": "clear:both; height:0;" }, null)]) : props.dataSource.length || slots.prev ? _createVNode("div", { "ref": function ref(el) { return innerRef.value = el; }, "style": { width: '100%', height: "".concat(totalColumn.value * (cardHeight.value + columnSpan) - columnSpan, "px") } }, [renderItems()]) : _createVNode(Empty, null, null)])]); }; } }); export default Scroll;