UNPKG

gui-one-nutui-react-taro

Version:

京东风格的轻量级移动端 React 组件库,支持一套代码生成 H5 和小程序

525 lines (524 loc) 18.6 kB
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 };