mirror of
https://github.com/wu736139669/ASHEBShop-h5.git
synced 2026-10-07 19:26:23 +00:00
446 lines
16 KiB
JavaScript
446 lines
16 KiB
JavaScript
'use strict';
|
|
|
|
Object.defineProperty(exports, "__esModule", {
|
|
value: true
|
|
});
|
|
exports.DEFAULT_SCROLLING_RESET_TIME_INTERVAL = undefined;
|
|
|
|
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
|
|
|
|
var _createClass = 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); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
|
|
|
|
var _react = require('react');
|
|
|
|
var _react2 = _interopRequireDefault(_react);
|
|
|
|
var _classnames = require('classnames');
|
|
|
|
var _classnames2 = _interopRequireDefault(_classnames);
|
|
|
|
var _PositionCache = require('./PositionCache');
|
|
|
|
var _PositionCache2 = _interopRequireDefault(_PositionCache);
|
|
|
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
|
|
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
|
|
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
|
|
|
|
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
|
|
|
|
/**
|
|
* Specifies the number of miliseconds during which to disable pointer events while a scroll is in progress.
|
|
* This improves performance and makes scrolling smoother.
|
|
*/
|
|
var DEFAULT_SCROLLING_RESET_TIME_INTERVAL = exports.DEFAULT_SCROLLING_RESET_TIME_INTERVAL = 150;
|
|
|
|
/**
|
|
* This component efficiently displays arbitrarily positioned cells using windowing techniques.
|
|
* Cell position is determined by an injected `cellPositioner` property.
|
|
* Windowing is vertical; this component does not support horizontal scrolling.
|
|
*
|
|
* Rendering occurs in two phases:
|
|
* 1) First pass uses estimated cell sizes (provided by the cache) to determine how many cells to measure in a batch.
|
|
* Batch size is chosen using a fast, naive layout algorithm that stacks images in order until the viewport has been filled.
|
|
* After measurement is complete (componentDidMount or componentDidUpdate) this component evaluates positioned cells
|
|
* in order to determine if another measurement pass is required (eg if actual cell sizes were less than estimated sizes).
|
|
* All measurements are permanently cached (keyed by `keyMapper`) for performance purposes.
|
|
* 2) Second pass uses the external `cellPositioner` to layout cells.
|
|
* At this time the positioner has access to cached size measurements for all cells.
|
|
* The positions it returns are cached by Masonry for fast access later.
|
|
* Phase one is repeated if the user scrolls beyond the current layout's bounds.
|
|
* If the layout is invalidated due to eg a resize, cached positions can be cleared using `recomputeCellPositions()`.
|
|
*
|
|
* Animation constraints:
|
|
* Simple animations are supported (eg translate/slide into place on initial reveal).
|
|
* More complex animations are not (eg flying from one position to another on resize).
|
|
*
|
|
* Layout constraints:
|
|
* This component supports multi-column layout.
|
|
* The height of each item may vary.
|
|
* The width of each item must not exceed the width of the column it is "in".
|
|
* The left position of all items within a column must align.
|
|
* (Items may not span multiple columns.)
|
|
*/
|
|
|
|
var Masonry = function (_PureComponent) {
|
|
_inherits(Masonry, _PureComponent);
|
|
|
|
function Masonry(props, context) {
|
|
_classCallCheck(this, Masonry);
|
|
|
|
var _this = _possibleConstructorReturn(this, (Masonry.__proto__ || Object.getPrototypeOf(Masonry)).call(this, props, context));
|
|
|
|
_this._invalidateOnUpdateStartIndex = null;
|
|
_this._invalidateOnUpdateStopIndex = null;
|
|
_this._positionCache = new _PositionCache2.default();
|
|
_this._startIndex = null;
|
|
_this._startIndexMemoized = null;
|
|
_this._stopIndex = null;
|
|
_this._stopIndexMemoized = null;
|
|
|
|
|
|
_this.state = {
|
|
isScrolling: false,
|
|
scrollTop: 0
|
|
};
|
|
|
|
_this._debounceResetIsScrollingCallback = _this._debounceResetIsScrollingCallback.bind(_this);
|
|
_this._setScrollingContainerRef = _this._setScrollingContainerRef.bind(_this);
|
|
_this._onScroll = _this._onScroll.bind(_this);
|
|
return _this;
|
|
}
|
|
|
|
_createClass(Masonry, [{
|
|
key: 'clearCellPositions',
|
|
value: function clearCellPositions() {
|
|
this._positionCache = new _PositionCache2.default();
|
|
this.forceUpdate();
|
|
}
|
|
|
|
// HACK This method signature was intended for Grid
|
|
|
|
}, {
|
|
key: 'invalidateCellSizeAfterRender',
|
|
value: function invalidateCellSizeAfterRender(_ref) {
|
|
var index = _ref.rowIndex;
|
|
|
|
if (this._invalidateOnUpdateStartIndex === null) {
|
|
this._invalidateOnUpdateStartIndex = index;
|
|
this._invalidateOnUpdateStopIndex = index;
|
|
} else {
|
|
this._invalidateOnUpdateStartIndex = Math.min(this._invalidateOnUpdateStartIndex, index);
|
|
this._invalidateOnUpdateStopIndex = Math.max(this._invalidateOnUpdateStopIndex, index);
|
|
}
|
|
}
|
|
}, {
|
|
key: 'recomputeCellPositions',
|
|
value: function recomputeCellPositions() {
|
|
var stopIndex = this._positionCache.count - 1;
|
|
|
|
this._positionCache = new _PositionCache2.default();
|
|
this._populatePositionCache(0, stopIndex);
|
|
|
|
this.forceUpdate();
|
|
}
|
|
}, {
|
|
key: 'componentDidMount',
|
|
value: function componentDidMount() {
|
|
this._checkInvalidateOnUpdate();
|
|
this._invokeOnScrollCallback();
|
|
this._invokeOnCellsRenderedCallback();
|
|
}
|
|
}, {
|
|
key: 'componentDidUpdate',
|
|
value: function componentDidUpdate(prevProps, prevState) {
|
|
this._checkInvalidateOnUpdate();
|
|
this._invokeOnScrollCallback();
|
|
this._invokeOnCellsRenderedCallback();
|
|
}
|
|
}, {
|
|
key: 'componentWillUnmount',
|
|
value: function componentWillUnmount() {
|
|
if (this._debounceResetIsScrollingId) {
|
|
clearTimeout(this._debounceResetIsScrollingId);
|
|
}
|
|
}
|
|
}, {
|
|
key: 'componentWillReceiveProps',
|
|
value: function componentWillReceiveProps(nextProps) {
|
|
var scrollTop = this.props.scrollTop;
|
|
|
|
|
|
if (scrollTop !== nextProps.scrollTop) {
|
|
this._debounceResetIsScrolling();
|
|
|
|
this.setState({
|
|
isScrolling: true,
|
|
scrollTop: nextProps.scrollTop
|
|
});
|
|
}
|
|
}
|
|
}, {
|
|
key: 'render',
|
|
value: function render() {
|
|
var _this2 = this;
|
|
|
|
var _props = this.props,
|
|
autoHeight = _props.autoHeight,
|
|
cellCount = _props.cellCount,
|
|
cellMeasurerCache = _props.cellMeasurerCache,
|
|
cellRenderer = _props.cellRenderer,
|
|
className = _props.className,
|
|
height = _props.height,
|
|
id = _props.id,
|
|
keyMapper = _props.keyMapper,
|
|
overscanByPixels = _props.overscanByPixels,
|
|
role = _props.role,
|
|
style = _props.style,
|
|
tabIndex = _props.tabIndex,
|
|
width = _props.width;
|
|
var _state = this.state,
|
|
isScrolling = _state.isScrolling,
|
|
scrollTop = _state.scrollTop;
|
|
|
|
|
|
var children = [];
|
|
|
|
var estimateTotalHeight = this._getEstimatedTotalHeight();
|
|
|
|
var shortestColumnSize = this._positionCache.shortestColumnSize;
|
|
var measuredCellCount = this._positionCache.count;
|
|
|
|
// We need to measure more cells before layout
|
|
if (shortestColumnSize < scrollTop + height + overscanByPixels && measuredCellCount < cellCount) {
|
|
var batchSize = Math.min(cellCount - measuredCellCount, Math.ceil((scrollTop + height + overscanByPixels - shortestColumnSize) / cellMeasurerCache.defaultHeight * width / cellMeasurerCache.defaultWidth));
|
|
|
|
for (var _index = measuredCellCount; _index < measuredCellCount + batchSize; _index++) {
|
|
children.push(cellRenderer({
|
|
index: _index,
|
|
isScrolling: isScrolling,
|
|
key: keyMapper(_index),
|
|
parent: this,
|
|
style: {
|
|
width: cellMeasurerCache.getWidth(_index)
|
|
}
|
|
}));
|
|
}
|
|
} else {
|
|
(function () {
|
|
var stopIndex = void 0;
|
|
var startIndex = void 0;
|
|
|
|
_this2._positionCache.range(scrollTop - overscanByPixels, height + overscanByPixels, function (index, left, top) {
|
|
if (typeof startIndex === 'undefined') {
|
|
startIndex = index;
|
|
stopIndex = index;
|
|
} else {
|
|
startIndex = Math.min(startIndex, index);
|
|
stopIndex = Math.max(stopIndex, index);
|
|
}
|
|
|
|
children.push(cellRenderer({
|
|
index: index,
|
|
isScrolling: isScrolling,
|
|
key: keyMapper(index),
|
|
parent: _this2,
|
|
style: {
|
|
height: cellMeasurerCache.getHeight(index),
|
|
left: left,
|
|
position: 'absolute',
|
|
top: top,
|
|
width: cellMeasurerCache.getWidth(index)
|
|
}
|
|
}));
|
|
|
|
_this2._startIndex = startIndex;
|
|
_this2._stopIndex = stopIndex;
|
|
});
|
|
})();
|
|
}
|
|
|
|
return _react2.default.createElement(
|
|
'div',
|
|
{
|
|
ref: this._setScrollingContainerRef,
|
|
'aria-label': this.props['aria-label'],
|
|
className: (0, _classnames2.default)('ReactVirtualized__Masonry', className),
|
|
id: id,
|
|
onScroll: this._onScroll,
|
|
role: role,
|
|
style: _extends({
|
|
boxSizing: 'border-box',
|
|
direction: 'ltr',
|
|
height: autoHeight ? 'auto' : height,
|
|
overflowX: 'hidden',
|
|
overflowY: estimateTotalHeight < height ? 'hidden' : 'auto',
|
|
position: 'relative',
|
|
width: width,
|
|
WebkitOverflowScrolling: 'touch',
|
|
willChange: 'transform'
|
|
}, style),
|
|
tabIndex: tabIndex
|
|
},
|
|
_react2.default.createElement(
|
|
'div',
|
|
{
|
|
className: 'ReactVirtualized__Masonry__innerScrollContainer',
|
|
style: {
|
|
width: '100%',
|
|
height: estimateTotalHeight,
|
|
maxWidth: '100%',
|
|
maxHeight: estimateTotalHeight,
|
|
overflow: 'hidden',
|
|
pointerEvents: isScrolling ? 'none' : '',
|
|
position: 'relative'
|
|
}
|
|
},
|
|
children
|
|
)
|
|
);
|
|
}
|
|
}, {
|
|
key: '_checkInvalidateOnUpdate',
|
|
value: function _checkInvalidateOnUpdate() {
|
|
if (typeof this._invalidateOnUpdateStartIndex === 'number') {
|
|
var _startIndex = this._invalidateOnUpdateStartIndex;
|
|
var _stopIndex = this._invalidateOnUpdateStopIndex;
|
|
|
|
this._invalidateOnUpdateStartIndex = null;
|
|
this._invalidateOnUpdateStopIndex = null;
|
|
|
|
// Query external layout logic for position of newly-measured cells
|
|
this._populatePositionCache(_startIndex, _stopIndex);
|
|
|
|
this.forceUpdate();
|
|
}
|
|
}
|
|
}, {
|
|
key: '_debounceResetIsScrolling',
|
|
value: function _debounceResetIsScrolling() {
|
|
var scrollingResetTimeInterval = this.props.scrollingResetTimeInterval;
|
|
|
|
|
|
if (this._debounceResetIsScrollingId) {
|
|
clearTimeout(this._debounceResetIsScrollingId);
|
|
}
|
|
|
|
this._debounceResetIsScrollingId = setTimeout(this._debounceResetIsScrollingCallback, scrollingResetTimeInterval);
|
|
}
|
|
}, {
|
|
key: '_debounceResetIsScrollingCallback',
|
|
value: function _debounceResetIsScrollingCallback() {
|
|
this.setState({
|
|
isScrolling: false
|
|
});
|
|
}
|
|
}, {
|
|
key: '_getEstimatedTotalHeight',
|
|
value: function _getEstimatedTotalHeight() {
|
|
var _props2 = this.props,
|
|
cellCount = _props2.cellCount,
|
|
cellMeasurerCache = _props2.cellMeasurerCache,
|
|
width = _props2.width;
|
|
|
|
|
|
var estimatedColumnCount = Math.floor(width / cellMeasurerCache.defaultWidth);
|
|
|
|
return this._positionCache.estimateTotalHeight(cellCount, estimatedColumnCount, cellMeasurerCache.defaultHeight);
|
|
}
|
|
}, {
|
|
key: '_invokeOnScrollCallback',
|
|
value: function _invokeOnScrollCallback() {
|
|
var _props3 = this.props,
|
|
height = _props3.height,
|
|
onScroll = _props3.onScroll;
|
|
var scrollTop = this.state.scrollTop;
|
|
|
|
|
|
if (this._onScrollMemoized !== scrollTop) {
|
|
onScroll({
|
|
clientHeight: height,
|
|
scrollHeight: this._getEstimatedTotalHeight(),
|
|
scrollTop: scrollTop
|
|
});
|
|
|
|
this._onScrollMemoized = scrollTop;
|
|
}
|
|
}
|
|
}, {
|
|
key: '_invokeOnCellsRenderedCallback',
|
|
value: function _invokeOnCellsRenderedCallback() {
|
|
if (this._startIndexMemoized !== this._startIndex || this._stopIndexMemoized !== this._stopIndex) {
|
|
var _onCellsRendered = this.props.onCellsRendered;
|
|
|
|
|
|
_onCellsRendered({
|
|
startIndex: this._startIndex,
|
|
stopIndex: this._stopIndex
|
|
});
|
|
|
|
this._startIndexMemoized = this._startIndex;
|
|
this._stopIndexMemoized = this._stopIndex;
|
|
}
|
|
}
|
|
}, {
|
|
key: '_populatePositionCache',
|
|
value: function _populatePositionCache(startIndex, stopIndex) {
|
|
var _props4 = this.props,
|
|
cellMeasurerCache = _props4.cellMeasurerCache,
|
|
cellPositioner = _props4.cellPositioner;
|
|
|
|
|
|
for (var _index2 = startIndex; _index2 <= stopIndex; _index2++) {
|
|
var _cellPositioner = cellPositioner(_index2),
|
|
_left = _cellPositioner.left,
|
|
_top = _cellPositioner.top;
|
|
|
|
this._positionCache.setPosition(_index2, _left, _top, cellMeasurerCache.getHeight(_index2));
|
|
}
|
|
}
|
|
}, {
|
|
key: '_setScrollingContainerRef',
|
|
value: function _setScrollingContainerRef(ref) {
|
|
this._scrollingContainer = ref;
|
|
}
|
|
}, {
|
|
key: '_onScroll',
|
|
value: function _onScroll(event) {
|
|
var height = this.props.height;
|
|
|
|
|
|
var eventScrollTop = event.target.scrollTop;
|
|
|
|
// When this component is shrunk drastically, React dispatches a series of back-to-back scroll events,
|
|
// Gradually converging on a scrollTop that is within the bounds of the new, smaller height.
|
|
// This causes a series of rapid renders that is slow for long lists.
|
|
// We can avoid that by doing some simple bounds checking to ensure that scroll offsets never exceed their bounds.
|
|
var scrollTop = Math.min(Math.max(0, this._getEstimatedTotalHeight() - height), eventScrollTop);
|
|
|
|
// On iOS, we can arrive at negative offsets by swiping past the start or end.
|
|
// Avoid re-rendering in this case as it can cause problems; see #532 for more.
|
|
if (eventScrollTop !== scrollTop) {
|
|
return;
|
|
}
|
|
|
|
// Prevent pointer events from interrupting a smooth scroll
|
|
this._debounceResetIsScrolling();
|
|
|
|
// Certain devices (like Apple touchpad) rapid-fire duplicate events.
|
|
// Don't force a re-render if this is the case.
|
|
// The mouse may move faster then the animation frame does.
|
|
// Use requestAnimationFrame to avoid over-updating.
|
|
if (this.state.scrollTop !== scrollTop) {
|
|
this.setState({
|
|
isScrolling: true,
|
|
scrollTop: scrollTop
|
|
});
|
|
}
|
|
}
|
|
}]);
|
|
|
|
return Masonry;
|
|
}(_react.PureComponent);
|
|
|
|
Masonry.defaultProps = {
|
|
autoHeight: false,
|
|
keyMapper: identity,
|
|
onCellsRendered: noop,
|
|
onScroll: noop,
|
|
overscanByPixels: 20,
|
|
role: 'grid',
|
|
scrollingResetTimeInterval: DEFAULT_SCROLLING_RESET_TIME_INTERVAL,
|
|
style: emptyObject,
|
|
tabIndex: 0
|
|
};
|
|
exports.default = Masonry;
|
|
|
|
|
|
var emptyObject = {};
|
|
|
|
function identity(value) {
|
|
return value;
|
|
}
|
|
|
|
function noop() {} |