gui-one-nutui-react-taro
Version:
京东风格的轻量级移动端 React 组件库,支持一套代码生成 H5 和小程序
525 lines (524 loc) • 18.6 kB
JavaScript
import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties";
import _defineProperty from "@babel/runtime/helpers/defineProperty";
import _typeof from "@babel/runtime/helpers/typeof";
var _excluded = ["children", "direction", "className", "pageContent", "onChange", "initPage", "paginationColor", "paginationVisible", "touchable", "isPreventDefault", "isStopPropagation", "autoPlay", "isCenter"];
import _regeneratorRuntime from "@babel/runtime/regenerator";
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
import React__default, { useRef, useState, useMemo, useEffect } from 'react';
import classNames from 'classnames';
import { nextTick, useReady, createSelectorQuery } from '@tarojs/taro';
import { D as DataContext } from './UserContext-b4181162.js';
import { c as cn } from './bem-893ad28d.js';
var defaultProps = {
width: (typeof window === "undefined" ? "undefined" : _typeof(window)) === 'object' ? window.innerWidth : 375,
height: 0,
duration: 500,
initPage: 0,
autoPlay: 0,
direction: 'horizontal',
paginationColor: '#fff',
paginationVisible: false,
loop: true,
touchable: true,
isPreventDefault: true,
isStopPropagation: true,
isCenter: false,
className: ''
};
var DISTANCE = 5;
var Swiper = React__default.forwardRef(function (props, ref) {
var _classNames, _classNames2;
var propSwiper = _objectSpread(_objectSpread({}, defaultProps), props);
var children = propSwiper.children,
direction = propSwiper.direction,
className = propSwiper.className,
pageContent = propSwiper.pageContent,
onChange = propSwiper.onChange,
initPage = propSwiper.initPage,
paginationColor = propSwiper.paginationColor,
paginationVisible = propSwiper.paginationVisible,
touchable = propSwiper.touchable,
isPreventDefault = propSwiper.isPreventDefault,
isStopPropagation = propSwiper.isStopPropagation,
autoPlay = propSwiper.autoPlay,
isCenter = propSwiper.isCenter,
rest = _objectWithoutProperties(propSwiper, _excluded);
var container = useRef(null);
var innerRef = useRef(null);
var _swiper = useRef({
moving: false,
autoplayTimer: null,
width: 0,
height: 0,
offset: 0,
size: 0
});
var _useState = useState(Math.random().toString(36).slice(-8)),
_useState2 = _slicedToArray(_useState, 1),
refRandomId = _useState2[0];
var isVertical = direction === 'vertical';
var _useState3 = useState(null),
_useState4 = _slicedToArray(_useState3, 2),
rect = _useState4[0],
setRect = _useState4[1];
// eslint-disable-next-line prefer-const
var _useState5 = useState(0),
_useState6 = _slicedToArray(_useState5, 2),
active = _useState6[0],
setActive = _useState6[1];
var _useState7 = useState(0),
_useState8 = _slicedToArray(_useState7, 2),
width = _useState8[0],
setWidth = _useState8[1];
var _useState9 = useState(0),
_useState10 = _slicedToArray(_useState9, 2),
height = _useState10[0],
setHeight = _useState10[1];
var _useState11 = useState(0),
_useState12 = _slicedToArray(_useState11, 2),
offset = _useState12[0],
setOffset = _useState12[1];
var _useState13 = useState([]),
_useState14 = _slicedToArray(_useState13, 2),
childOffset = _useState14[0],
setChildOffset = _useState14[1];
var _useState15 = useState(false),
_useState16 = _slicedToArray(_useState15, 2),
ready = _useState16[0],
setReady = _useState16[1];
var size = isVertical ? height : width;
var _useState17 = useState({
startX: 0,
startY: 0,
deltaX: 0,
deltaY: 0,
offsetX: 0,
offsetY: 0,
stateDirection: '',
delta: 0,
touchTime: 0
}),
_useState18 = _slicedToArray(_useState17, 2),
touch = _useState18[0],
setTouch = _useState18[1];
var _useMemo = useMemo(function () {
var childCount = 0;
var childs = React__default.Children.map(props.children, function (child) {
if (!React__default.isValidElement(child)) return null;
childCount++;
return child;
});
return {
childs: childs,
childCount: childCount
};
}, [props.children]),
childs = _useMemo.childs,
childCount = _useMemo.childCount;
var trackSize = childCount * Number(size);
// 父组件参数传入子组件item
var parent = {
propSwiper: propSwiper,
size: size
};
var minOffset = function () {
if (rect) {
var base = isVertical ? rect === null || rect === void 0 ? void 0 : rect.height : rect === null || rect === void 0 ? void 0 : rect.width;
return base - Number(size) * childCount;
}
return 0;
}();
// 清除定时器
var stopAutoPlay = function stopAutoPlay() {
clearTimeout(_swiper.current.autoplayTimer);
_swiper.current.autoplayTimer = null;
};
// 定时轮播
var autoplay = function autoplay() {
if (propSwiper.autoPlay <= 0 || childCount <= 1) return;
stopAutoPlay();
_swiper.current.autoplayTimer = setTimeout(function () {
next();
autoplay();
}, Number(propSwiper.autoPlay));
};
// 重置首尾位置信息
var resettPosition = function resettPosition() {
_swiper.current.moving = true;
if (active <= -1) {
move({
pace: childCount
});
}
if (active >= childCount) {
move({
pace: -childCount
});
}
};
// 上一页
var prev = function prev() {
resettPosition();
touchReset();
requestFrame(function () {
requestFrame(function () {
_swiper.current.moving = false;
move({
pace: -1,
isEmit: true
});
});
});
};
// 下一页
var next = function next() {
resettPosition();
touchReset();
requestFrame(function () {
requestFrame(function () {
_swiper.current.moving = false;
move({
pace: 1,
isEmit: true
});
});
});
};
// 前往指定页
var to = function to(index) {
resettPosition();
touchReset();
requestFrame(function () {
requestFrame(function () {
_swiper.current.moving = false;
var targetIndex;
if (props.loop && childCount === index) {
targetIndex = active === 0 ? 0 : index;
} else {
targetIndex = index % childCount;
}
move({
pace: targetIndex - active,
isEmit: true
});
});
});
};
// 切换方法
var move = function move(_ref) {
var _ref$pace = _ref.pace,
pace = _ref$pace === void 0 ? 0 : _ref$pace,
_ref$offset = _ref.offset,
offset = _ref$offset === void 0 ? 0 : _ref$offset,
_ref$isEmit = _ref.isEmit,
isEmit = _ref$isEmit === void 0 ? false : _ref$isEmit,
_ref$movingStatus = _ref.movingStatus,
movingStatus = _ref$movingStatus === void 0 ? false : _ref$movingStatus;
if (childCount <= 1) return;
var targetActive = getActive(pace);
// 父级容器偏移量
var targetOffset = getOffset(targetActive, offset);
// 如果循环,调整开头结尾图片位置
if (props.loop) {
if (Array.isArray(children) && children[0] && targetOffset !== minOffset) {
var rightBound = targetOffset < minOffset;
childOffset[0] = rightBound ? trackSize : 0;
}
if (Array.isArray(children) && children[childCount - 1] && targetOffset !== 0) {
var leftBound = targetOffset > 0;
childOffset[childCount - 1] = leftBound ? -trackSize : 0;
}
setChildOffset(childOffset);
}
if (isEmit && active !== targetActive) {
props.onChange && props.onChange((targetActive + childCount) % childCount);
}
active = targetActive;
setActive(targetActive);
setOffset(targetOffset);
getStyle(targetOffset);
};
// 确定当前active 元素
var getActive = function getActive(pace) {
if (pace) {
var _active = active + pace;
if (props.loop) {
return range(_active, -1, childCount);
}
return range(_active, 0, childCount - 1);
}
return active;
};
// 计算位移
var getOffset = function getOffset(active) {
var offset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
var currentPosition = active * Number(size);
if (!props.loop) {
currentPosition = Math.min(currentPosition, -minOffset);
}
var targetOffset = offset - currentPosition;
if (!props.loop) {
targetOffset = range(targetOffset, minOffset, 0);
}
return targetOffset;
};
// 浏览器 帧 事件
var requestFrame = function requestFrame(fn) {
window.requestAnimationFrame.call(window, fn);
};
// 取值 方法
var range = function range(num, min, max) {
return Math.min(Math.max(num, min), max);
};
var getDirection = function getDirection(x, y) {
if (x > y && x > DISTANCE) return 'horizontal';
if (y > x && y > DISTANCE) return 'vertical';
return '';
};
// 重置 全部位移信息
var touchReset = function touchReset() {
touch.startX = 0;
touch.startY = 0;
touch.deltaX = 0;
touch.deltaY = 0;
touch.offsetX = 0;
touch.offsetY = 0;
touch.delta = 0;
touch.stateDirection = '';
touch.touchTime = 0;
};
// 触摸事件开始
var touchStart = function touchStart(e) {
touchReset();
touch.startX = e.touches[0].clientX;
touch.startY = e.touches[0].clientY;
};
// 触摸事件移动
var touchMove = function touchMove(e) {
touch.deltaX = e.touches[0].clientX - touch.startX;
touch.deltaY = e.touches[0].clientY - touch.startY;
touch.offsetX = Math.abs(touch.deltaX);
touch.offsetY = Math.abs(touch.deltaY);
touch.delta = isVertical ? touch.deltaY : touch.deltaX;
if (!touch.stateDirection) {
touch.stateDirection = getDirection(touch.offsetX, touch.offsetY);
}
};
var b = cn('swiper');
var classes = classNames(b(''));
var contentClass = classNames((_classNames = {}, _defineProperty(_classNames, "".concat(b('inner')), true), _defineProperty(_classNames, "".concat(b('vertical')), isVertical), _classNames));
var getStyle = function getStyle() {
var moveOffset = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : offset;
var target = innerRef.current;
var _offset = 0;
if (!isCenter) {
_offset = moveOffset;
} else {
var _size = isVertical ? height : width;
var val = isVertical ? (rect === null || rect === void 0 ? void 0 : rect.height) - _size : (rect === null || rect === void 0 ? void 0 : rect.width) - _size;
_offset = moveOffset + (active === childCount - 1 && !props.loop ? -val / 2 : val / 2);
}
target.style.transitionDuration = "".concat(_swiper.current.moving ? 0 : props.duration, "ms");
target.style[isVertical ? 'height' : 'width'] = "".concat(Number(size) * childCount, "px");
target.style[isVertical ? 'width' : 'height'] = "".concat(isVertical ? width : height, "px");
target.style.transform = "translate3D".concat(!isVertical ? "(".concat(_offset, "px,0,0)") : "(0,".concat(_offset, "px,0)"));
};
var onTouchStart = function onTouchStart(e) {
if (props.isPreventDefault) e.preventDefault();
if (props.isStopPropagation) e.stopPropagation();
if (!props.touchable) return;
touchStart(e);
touch.touchTime = Date.now();
stopAutoPlay();
resettPosition();
};
var onTouchMove = function onTouchMove(e) {
if (props.touchable && _swiper.current.moving) {
touchMove(e);
if (touch.stateDirection === props.direction) {
move({
offset: touch.delta
});
}
}
};
var onTouchEnd = function onTouchEnd(e) {
if (!props.touchable || !_swiper.current.moving) return;
var speed = touch.delta / (Date.now() - touch.touchTime);
var isShouldMove = Math.abs(speed) > 0.3 || Math.abs(touch.delta) > +(size / 2).toFixed(2);
var pace = 0;
_swiper.current.moving = false;
if (isShouldMove && touch.stateDirection === props.direction) {
var _offset2 = isVertical ? touch.offsetY : touch.offsetX;
if (props.loop) {
if (_offset2 > 0) {
pace = touch.delta > 0 ? -1 : 1;
} else {
pace = 0;
}
} else {
pace = -Math[touch.delta > 0 ? 'ceil' : 'floor'](touch.delta / size);
}
move({
pace: pace,
isEmit: true
});
} else if (touch.delta) {
move({
pace: 0
});
} else {
getStyle();
}
autoplay();
};
useEffect(function () {
_swiper.current.activePagination = (active + childCount) % childCount;
}, [active]);
var queryRect = function queryRect(element) {
return new Promise(function (resolve) {
var query = createSelectorQuery();
query.select("#".concat(element.id)) && query.select("#".concat(element.id)).boundingClientRect();
query.exec(function (res) {
resolve(res[0]);
});
});
};
var init = /*#__PURE__*/function () {
var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
var active,
rect,
_active,
_width,
_height,
targetOffset,
_args = arguments;
return _regeneratorRuntime.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
active = _args.length > 0 && _args[0] !== undefined ? _args[0] : +propSwiper.initPage;
_context.next = 3;
return queryRect(container.current);
case 3:
rect = _context.sent;
_active = Math.max(Math.min(childCount - 1, active), 0);
_width = propSwiper.width ? +propSwiper.width : rect === null || rect === void 0 ? void 0 : rect.width;
_height = propSwiper.height ? +propSwiper.height : rect === null || rect === void 0 ? void 0 : rect.height;
size = isVertical ? _height : _width;
trackSize = childCount * Number(size);
targetOffset = getOffset(_active);
_swiper.current.moving = true;
if (ready) {
_swiper.current.moving = false;
}
setRect(rect);
setActive(_active);
setWidth(_width);
setHeight(_height);
setOffset(targetOffset);
setReady(true);
case 18:
case "end":
return _context.stop();
}
}
}, _callee);
}));
return function init() {
return _ref2.apply(this, arguments);
};
}();
useEffect(function () {
if (ready) {
getStyle();
}
}, [isVertical, width, height, offset, ready]);
useEffect(function () {
if (ready) {
stopAutoPlay();
autoplay();
}
return function () {
setReady(false);
};
}, [ready]);
useEffect(function () {
stopAutoPlay();
autoplay();
}, [children]);
useEffect(function () {
nextTick(function () {
init();
});
}, [propSwiper.initPage]);
useEffect(function () {
return function () {
stopAutoPlay();
};
}, []);
useReady(function () {
nextTick(function () {
init();
});
});
var itemStyle = function itemStyle(index) {
var style = {};
var _direction = propSwiper.direction || direction;
var _size = size;
if (_size) {
style[_direction === 'horizontal' ? 'width' : 'height'] = "".concat(_size, "px");
}
var offset = childOffset[index];
if (offset) {
style.transform = "translate3D".concat(_direction === 'horizontal' ? "(".concat(offset, "px,0,0)") : "(0,".concat(offset, "px,0)"));
}
return style;
};
React__default.useImperativeHandle(ref, function () {
return {
to: to,
next: next,
prev: prev
};
});
return React__default.createElement(DataContext.Provider, {
value: parent
}, React__default.createElement("view", _objectSpread(_objectSpread({
className: "".concat(classes, " ").concat(className),
ref: container
}, rest), {}, {
id: "container-".concat(refRandomId),
onTouchStart: onTouchStart,
onTouchMove: onTouchMove,
onTouchEnd: onTouchEnd,
// @ts-ignore
catchMove: isVertical
}), React__default.createElement("div", {
className: contentClass,
ref: innerRef
}, React__default.Children.map(childs, function (child, index) {
return React__default.createElement("div", {
className: b('item-wrapper'),
style: itemStyle(index),
key: index
}, child);
})), propSwiper.paginationVisible && !('pageContent' in propSwiper) ? React__default.createElement("div", {
className: classNames((_classNames2 = {}, _defineProperty(_classNames2, "".concat(b('pagination')), true), _defineProperty(_classNames2, "".concat(b('pagination-vertical')), isVertical), _classNames2))
}, React__default.Children.map(childs, function (item, index) {
var _classNames3;
return React__default.createElement("i", {
style: (active + childCount) % childCount === index ? {
backgroundColor: propSwiper.paginationColor
} : undefined,
className: classNames((_classNames3 = {}, _defineProperty(_classNames3, "".concat(b('pagination-item')), true), _defineProperty(_classNames3, "active", (active + childCount) % childCount === index), _classNames3)),
key: index
});
})) : React__default.createElement("div", null, pageContent)));
});
Swiper.defaultProps = defaultProps;
Swiper.displayName = 'NutSwiper';
export { Swiper as S };