shineout
Version:
Shein 前端组件库
396 lines (320 loc) • 13.2 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
exports.__esModule = true;
exports.default = void 0;
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
var _inheritsLoose2 = _interopRequireDefault(require("@babel/runtime/helpers/inheritsLoose"));
var _assertThisInitialized2 = _interopRequireDefault(require("@babel/runtime/helpers/assertThisInitialized"));
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread"));
var _react = _interopRequireDefault(require("react"));
var _component = require("../component");
var _element = require("../utils/dom/element");
var _detect = require("../utils/dom/detect");
var _defaultProps = require("../utils/defaultProps");
var _func = require("../utils/func");
var _document = require("../utils/dom/document");
var _context = require("./context");
var events = ['scroll', 'pageshow', 'load'];
var supportSticky = (0, _element.cssSupport)('position', 'sticky');
var defaultZIndex = 900;
var DefaultValue = (0, _objectSpread2.default)({}, _defaultProps.defaultProps, {
css: true
});
var Sticky =
/*#__PURE__*/
function (_PureComponent) {
(0, _inheritsLoose2.default)(Sticky, _PureComponent);
function Sticky(props) {
var _this;
_this = _PureComponent.call(this, props) || this;
(0, _defineProperty2.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), "style", void 0);
(0, _defineProperty2.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), "targetElement", void 0);
(0, _defineProperty2.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), "element", void 0);
(0, _defineProperty2.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), "scrollTimer", void 0);
(0, _defineProperty2.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), "placeholder", void 0);
(0, _defineProperty2.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), "origin", void 0);
(0, _defineProperty2.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), "locked", void 0);
(0, _defineProperty2.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), "scrollCount", void 0);
_this.state = {};
_this.bindElement = _this.bindElement.bind((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)));
_this.bindOrigin = _this.bindOrigin.bind((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)));
_this.bindPlaceholder = _this.bindPlaceholder.bind((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)));
_this.handlePosition = _this.handlePosition.bind((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)));
_this.style = {};
return _this;
}
var _proto = Sticky.prototype;
_proto.componentDidMount = function componentDidMount() {
_PureComponent.prototype.componentDidMount.call(this);
var target = this.props.target;
this.targetElement = (0, _element.getParent)(this.element, target);
this.handlePosition();
if (!this.shouldUseCss) {
this.bindScroll();
}
};
_proto.componentDidUpdate = function componentDidUpdate(prevProps) {
if (!prevProps.needResetPostion && this.props.needResetPostion) {
this.setPosition();
}
};
_proto.componentWillUnmount = function componentWillUnmount() {
_PureComponent.prototype.componentWillUnmount.call(this);
this.unbindScroll();
if (this.scrollTimer) clearTimeout(this.scrollTimer);
};
_proto.getStyle = function getStyle(mode, offset, left, width) {
var _style;
var _this$props$style$zIn = this.props.style.zIndex,
zIndex = _this$props$style$zIn === void 0 ? 900 : _this$props$style$zIn;
var css = this.props.css;
var style = (_style = {
position: 'fixed',
left: left,
width: width
}, _style[mode] = offset, _style.zIndex = zIndex, _style);
if (this.targetElement) {
if (supportSticky && css) {
style.position = 'sticky';
} else {
style.position = 'absolute';
if (mode === 'top') {
style.transform = "translateY(" + (offset + this.targetElement.scrollTop) + "px)";
} else {
style.transform = "translateY(" + this.targetElement.scrollTop + "px)";
}
delete style.left;
}
}
this.triggerChange(true, style);
return style;
};
_proto.setPosition = function setPosition() {
var _this$props = this.props,
bottom = _this$props.bottom,
top = _this$props.top,
target = _this$props.target,
css = _this$props.css,
needResetPostion = _this$props.needResetPostion;
var _this$state = this.state,
mode = _this$state.mode,
scrollWidth = _this$state.scrollWidth; // If it is a hidden element, the position will not be updated
if (needResetPostion === false) return;
var selfRect = (0, _element.copyBoundingClientRect)(this.element);
if (selfRect === null) return; // If the element is hidden, the width and height will be 0
if (selfRect && selfRect.width === 0 && selfRect.height === 0) return;
var _getComputedStyle = getComputedStyle(this.element),
marginBottom = _getComputedStyle.marginBottom,
marginTop = _getComputedStyle.marginTop;
selfRect.height += parseFloat(marginBottom) + parseFloat(marginTop);
var scrollElement = this.targetElement || document.body;
var scrollRect = scrollElement.getBoundingClientRect();
var placeholderRect = this.placeholder ? (0, _element.copyBoundingClientRect)(this.placeholder) : null;
var viewHeight = _document.docSize.height;
if (this.origin) {
var _this$origin$getBound = this.origin.getBoundingClientRect(),
width = _this$origin$getBound.width;
selfRect.width = width;
if (placeholderRect) placeholderRect.width = width;
}
var placeholderStyle = {
width: selfRect.width,
// if target element is not null, set height to 0
height: target && supportSticky && css ? 0 : selfRect.height
};
var style;
var placeholder;
if (top !== undefined && mode !== 'bottom') {
var limitTop = top;
if (this.targetElement) {
var _getComputedStyle2 = getComputedStyle(scrollElement),
paddingTop = _getComputedStyle2.paddingTop;
limitTop += scrollRect.top + parseInt(paddingTop, 10);
}
if (Math.ceil(selfRect.top) < limitTop) {
this.setState({
scrollWidth: scrollRect.width,
mode: 'top'
});
style = this.getStyle('top', top, selfRect.left, selfRect.width);
placeholder = placeholderStyle;
} else if (placeholderRect && selfRect.top < placeholderRect.top) {
if (scrollRect.width !== selfRect.width) {
style = this.getStyle('top', top, selfRect.left, scrollRect.width);
}
if (!(target && selfRect.top === limitTop)) {
this.setState({
mode: ''
});
style = {};
placeholder = null;
this.triggerChange(false, style);
}
} else if (this.targetElement && placeholderRect) {
style = this.getStyle('top', top, selfRect.left, selfRect.width);
placeholder = placeholderStyle;
} else if (scrollWidth && placeholderRect && scrollWidth !== scrollRect.width) {
this.setState({
scrollWidth: scrollRect.width,
mode: 'top'
});
style = this.getStyle('top', top, placeholderRect.left, placeholderRect.width);
placeholder = placeholderStyle;
}
}
if (bottom !== undefined && mode !== 'top') {
var limitBottom = viewHeight - bottom;
if (this.targetElement) {
var _getComputedStyle3 = getComputedStyle(scrollElement),
paddingBottom = _getComputedStyle3.paddingBottom;
limitBottom = scrollRect.bottom - bottom - parseInt(paddingBottom, 10);
}
if (selfRect.bottom > limitBottom) {
this.setState({
scrollWidth: scrollRect.width,
mode: 'bottom'
});
style = this.getStyle('bottom', bottom, selfRect.left, selfRect.width);
placeholder = placeholderStyle;
} else if (placeholderRect && (this.targetElement ? scrollRect.bottom : selfRect.bottom) > placeholderRect.bottom) {
if (scrollRect.width !== selfRect.width) {
style = this.getStyle('bottom', bottom, selfRect.left, scrollRect.width);
}
if (!(target && selfRect.bottom === limitBottom)) {
this.setState({
mode: ''
});
style = {};
placeholder = null;
this.triggerChange(false, style);
}
} else if (this.targetElement && placeholderRect) {
style = this.getStyle('bottom', bottom, selfRect.left, selfRect.width);
placeholder = placeholderStyle;
} else if (scrollWidth && placeholderRect && scrollWidth !== scrollRect.width) {
this.setState({
scrollWidth: scrollRect.width,
mode: 'bottom'
});
style = this.getStyle('bottom', bottom, placeholderRect.left, placeholderRect.width);
placeholder = placeholderStyle;
}
}
if (placeholder !== undefined) {
this.setState({
placeholder: placeholder
});
}
if (style) {
this.style = style;
this.setState({
style: style
});
}
};
_proto.triggerChange = function triggerChange(flag, style) {
var onChange = this.props.onChange;
if (style.position === this.style.position) return;
if (typeof onChange === 'function') onChange(flag);
};
_proto.handlePosition = function handlePosition() {
var _this2 = this;
var css = this.props.css;
if (this.locked && css) {
this.scrollCount += 1;
return;
}
this.locked = true;
this.scrollCount = 0;
this.setPosition();
this.scrollTimer = setTimeout(function () {
_this2.locked = false;
if (_this2.scrollCount > 0) {
_this2.handlePosition();
}
}, 48);
};
_proto.bindElement = function bindElement(el) {
this.element = el;
};
_proto.bindOrigin = function bindOrigin(el) {
this.origin = el;
};
_proto.bindPlaceholder = function bindPlaceholder(el) {
this.placeholder = el;
};
_proto.bindScroll = function bindScroll() {
var _this3 = this;
if (this.targetElement) {
this.targetElement.addEventListener('scroll', this.handlePosition, _detect.eventPassive);
} else {
events.forEach(function (e) {
window.addEventListener(e, _this3.handlePosition);
});
}
window.addEventListener('resize', this.handlePosition);
};
_proto.unbindScroll = function unbindScroll() {
var _this4 = this;
if (this.targetElement) {
this.targetElement.removeEventListener('scroll', this.handlePosition);
} else {
events.forEach(function (e) {
window.removeEventListener(e, _this4.handlePosition);
});
}
window.removeEventListener('resize', this.handlePosition);
};
_proto.render = function render() {
var _this$props2 = this.props,
children = _this$props2.children,
className = _this$props2.className,
target = _this$props2.target,
css = _this$props2.css,
top = _this$props2.top,
bottom = _this$props2.bottom;
var placeholder = this.state.placeholder;
var outerStyle = this.props.style;
var innerStyle = this.state.style;
if (target && supportSticky && css) {
outerStyle = Object.assign({
zIndex: defaultZIndex
}, outerStyle, {
position: 'sticky',
top: top,
bottom: bottom
});
innerStyle = {};
}
return _react.default.createElement("div", {
style: outerStyle,
className: className
}, _react.default.createElement("div", {
ref: this.bindElement,
style: Object.assign({}, innerStyle, {
display: 'flow-root'
})
}, children), _react.default.createElement("div", {
ref: this.bindOrigin
}), placeholder && _react.default.createElement("div", {
ref: this.bindPlaceholder,
style: placeholder
}));
};
(0, _createClass2.default)(Sticky, [{
key: "shouldUseCss",
get: function get() {
var css = this.props.css;
if (css && supportSticky && this.targetElement) {
return true;
}
return false;
}
}]);
return Sticky;
}(_component.PureComponent);
(0, _defineProperty2.default)(Sticky, "displayName", 'ShineoutSticky');
(0, _defineProperty2.default)(Sticky, "defaultProps", DefaultValue);
var _default = (0, _func.compose)(_context.consumer)(Sticky);
exports.default = _default;