vantui-edit
Version:
一套适用于Taro3及React的vantui组件库
602 lines (517 loc) • 21.5 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", "style"];
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; }
/* eslint-disable @typescript-eslint/no-unused-vars */
import React, { useState, useEffect, useRef, useMemo, Children, forwardRef, useImperativeHandle, isValidElement, useCallback } from 'react';
import classNames from 'classnames';
import { useReady, createSelectorQuery, nextTick } from '@tarojs/taro';
import { View, Text } from '@tarojs/components';
import { DataContext } from './context';
import { jsx as _jsx } from "react/jsx-runtime";
import { jsxs as _jsxs } from "react/jsx-runtime";
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 = function Swiper(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,
style = propSwiper.style,
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, 1),
touch = _useState18[0];
var _useMemo = useMemo(function () {
var childCount = 0;
var childs = Children.map(propSwiper.children, function (child) {
if (! /*#__PURE__*/isValidElement(child)) return null;
childCount++;
return child;
});
return {
childs: childs,
childCount: childCount
};
}, [propSwiper.children]),
childs = _useMemo.childs,
childCount = _useMemo.childCount;
var trackSize = childCount * Number(size); // 父组件参数传入子组件item
var parent = {
propSwiper: propSwiper,
size: size
}; // 浏览器 帧 事件
var requestFrame = useCallback(function (fn) {
window.requestAnimationFrame.call(window, fn);
}, []); // 取值 方法
var range = useCallback(function (num, min, max) {
return Math.min(Math.max(num, min), max);
}, []);
var getDirection = useCallback(function (x, y) {
if (x > y && x > DISTANCE) return 'horizontal';
if (y > x && y > DISTANCE) return 'vertical';
return '';
}, []);
var getMinOffset = useCallback(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;
}, [childCount, isVertical, rect, size]); // 确定当前active 元素
var getActive = function getActive(pace) {
if (pace) {
var _active = active + pace;
if (propSwiper.loop) {
return range(_active, -1, childCount);
}
return range(_active, 0, childCount - 1);
}
return active;
}; // 计算位移
var getOffset = useCallback(function (active) {
var offset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
var minOffset = getMinOffset();
var currentPosition = active * Number(size);
if (!propSwiper.loop) {
currentPosition = Math.min(currentPosition, -minOffset);
}
var targetOffset = offset - currentPosition;
if (!propSwiper.loop) {
targetOffset = range(targetOffset, minOffset, 0);
}
return targetOffset;
}, [getMinOffset, propSwiper.loop, range, size]);
var getStyle = useCallback(function () {
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 && !propSwiper.loop ? -val / 2 : val / 2);
}
target.style.transitionDuration = "".concat(_swiper.current.moving ? 0 : propSwiper.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)"));
}, [active, childCount, height, isCenter, isVertical, offset, propSwiper.duration, propSwiper.loop, rect, size, width]); // 切换方法
var move = useCallback(function (_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;
if (childCount <= 1) return;
var targetActive = getActive(pace);
var minOffset = getMinOffset(); // 父级容器偏移量
var targetOffset = getOffset(targetActive, offset); // 如果循环,调整开头结尾图片位置
if (propSwiper.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) {
propSwiper.onChange && propSwiper.onChange((targetActive + childCount) % childCount);
} // eslint-disable-next-line react-hooks/exhaustive-deps
active = targetActive;
setActive(targetActive);
setOffset(targetOffset);
getStyle(targetOffset);
}, [active, childCount, childOffset, children, getActive, getMinOffset, getOffset, getStyle, propSwiper, trackSize]); // 重置 全部位移信息
var touchReset = useCallback(function () {
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;
}, [touch]); // 重置首尾位置信息
var resettPosition = useCallback(function () {
_swiper.current.moving = true;
if (active <= -1) {
move({
pace: childCount
});
}
if (active >= childCount) {
move({
pace: -childCount
});
}
}, [active, childCount, move]); // 清除定时器
var stopAutoPlay = useCallback(function () {
clearTimeout(_swiper.current.autoplayTimer);
_swiper.current.autoplayTimer = null;
}, []); // 下一页
var next = useCallback(function () {
resettPosition();
touchReset();
requestFrame(function () {
requestFrame(function () {
_swiper.current.moving = false;
move({
pace: 1,
isEmit: true
});
});
});
}, [move, requestFrame, resettPosition, touchReset]); // 上一页
var prev = useCallback(function () {
resettPosition();
touchReset();
requestFrame(function () {
requestFrame(function () {
_swiper.current.moving = false;
move({
pace: -1,
isEmit: true
});
});
});
}, [move, requestFrame, resettPosition, touchReset]); // 前往指定页
var to = useCallback(function (index) {
resettPosition();
touchReset();
requestFrame(function () {
requestFrame(function () {
_swiper.current.moving = false;
var targetIndex;
if (propSwiper.loop && childCount === index) {
targetIndex = active === 0 ? 0 : index;
} else {
targetIndex = index % childCount;
}
move({
pace: targetIndex - active,
isEmit: true
});
});
});
}, [active, childCount, move, propSwiper.loop, requestFrame, resettPosition, touchReset]); // 定时轮播
var autoplay = useCallback(function () {
if (propSwiper.autoPlay <= 0 || childCount <= 1) return;
stopAutoPlay();
_swiper.current.autoplayTimer = setTimeout(function () {
next();
autoplay();
}, Number(propSwiper.autoPlay));
}, [childCount, next, propSwiper.autoPlay, stopAutoPlay]); // 触摸事件开始
var touchStart = useCallback(function (e) {
var _e$touches$, _e$touches$2;
touchReset();
touch.startX = (e === null || e === void 0 ? void 0 : (_e$touches$ = e.touches[0]) === null || _e$touches$ === void 0 ? void 0 : _e$touches$.clientX) || 0;
touch.startY = (e === null || e === void 0 ? void 0 : (_e$touches$2 = e.touches[0]) === null || _e$touches$2 === void 0 ? void 0 : _e$touches$2.clientY) || 0;
}, [touch, touchReset]); // 触摸事件移动
var touchMove = useCallback(function (e) {
var _e$touches$3, _e$touches$4;
touch.deltaX = ((e === null || e === void 0 ? void 0 : (_e$touches$3 = e.touches[0]) === null || _e$touches$3 === void 0 ? void 0 : _e$touches$3.clientX) || 0) - touch.startX;
touch.deltaY = ((e === null || e === void 0 ? void 0 : (_e$touches$4 = e.touches[0]) === null || _e$touches$4 === void 0 ? void 0 : _e$touches$4.clientY) || 0) - 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);
}
}, [getDirection, isVertical, touch]);
var contentClass = classNames((_classNames = {}, _defineProperty(_classNames, 'van-swiper__inner', true), _defineProperty(_classNames, 'van-swiper__vertical', isVertical), _classNames));
var onTouchStart = useCallback(function (e) {
if (propSwiper.isPreventDefault) e.preventDefault();
if (propSwiper.isStopPropagation) e.stopPropagation();
if (!propSwiper.touchable) return;
touchStart(e);
touch.touchTime = Date.now();
stopAutoPlay();
resettPosition();
}, [propSwiper.isPreventDefault, propSwiper.isStopPropagation, propSwiper.touchable, resettPosition, stopAutoPlay, touch, touchStart]);
var onTouchMove = useCallback(function (e) {
if (propSwiper.touchable && _swiper.current.moving) {
touchMove(e);
if (touch.stateDirection === propSwiper.direction) {
move({
offset: touch.delta
});
}
}
}, [move, propSwiper.direction, propSwiper.touchable, touch.delta, touch.stateDirection, touchMove]);
var onTouchEnd = useCallback(function () {
if (!propSwiper.touchable || !_swiper.current.moving) return;
var speed = touch.delta / (Date.now() - touch.touchTime);
var isShouldMove = Math.abs(speed) > 0.2 || Math.abs(touch.delta) > +(size / 2).toFixed(2);
var pace = 0;
_swiper.current.moving = false;
if (isShouldMove && touch.stateDirection === propSwiper.direction) {
var _offset2 = isVertical ? touch.offsetY : touch.offsetX;
if (propSwiper.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();
}, [autoplay, getStyle, isVertical, move, propSwiper.direction, propSwiper.loop, propSwiper.touchable, size, touch.delta, touch.offsetX, touch.offsetY, touch.stateDirection, touch.touchTime]);
useEffect(function () {
_swiper.current.activePagination = (active + childCount) % childCount; // eslint-disable-next-line react-hooks/exhaustive-deps
}, [active]);
var queryRect = useCallback(function (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 = useCallback( /*#__PURE__*/_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; // eslint-disable-next-line react-hooks/exhaustive-deps
size = isVertical ? _height : _width; // eslint-disable-next-line react-hooks/exhaustive-deps
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);
})), [childCount, getOffset, propSwiper.height, propSwiper.initPage, propSwiper.width, queryRect, ready]);
useEffect(function () {
if (ready) {
getStyle();
} // eslint-disable-next-line react-hooks/exhaustive-deps
}, [isVertical, width, height, offset, ready]);
useEffect(function () {
if (ready && rect) {
stopAutoPlay();
autoplay();
}
return function () {
setReady(false);
}; // eslint-disable-next-line react-hooks/exhaustive-deps
}, [ready, rect]);
useEffect(function () {
stopAutoPlay();
autoplay(); // eslint-disable-next-line react-hooks/exhaustive-deps
}, [children]);
useEffect(function () {
nextTick(function () {
init();
}); // eslint-disable-next-line react-hooks/exhaustive-deps
}, [propSwiper.initPage]);
useEffect(function () {
return function () {
stopAutoPlay();
}; // eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
useReady(function () {
nextTick(function () {
setTimeout(function () {
init();
});
});
});
var itemStyle = useCallback(function (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;
}, [childOffset, direction, propSwiper.direction, size]);
useImperativeHandle(ref, function () {
return {
to: to,
next: next,
prev: prev
};
});
return /*#__PURE__*/_jsx(DataContext.Provider, {
value: parent,
children: /*#__PURE__*/_jsxs(View, _objectSpread(_objectSpread({
className: "van-swiper ".concat(className),
ref: container
}, rest), {}, {
id: 'container-' + refRandomId,
onTouchStart: onTouchStart,
onTouchMove: onTouchMove,
onTouchEnd: onTouchEnd // @ts-ignore
,
catchMove: isVertical,
style: _objectSpread(_objectSpread({}, style), {}, {
height: height
}),
children: [/*#__PURE__*/_jsxs(View, {
className: contentClass,
ref: innerRef,
children: [Children.map(childs, function (child, index) {
return /*#__PURE__*/_jsx(View, {
className: 'van-swiper-item-wrapper',
style: itemStyle(index),
children: child
}, index);
}), process.env.TARO_ENV !== 'h5' && /*#__PURE__*/_jsx(View, {
className: 'van-swiper-item-wrapper',
style: itemStyle(0),
children: childs && childs.length ? childs[0] : ''
})]
}), propSwiper.paginationVisible && !('pageContent' in propSwiper) ? /*#__PURE__*/_jsx(View, {
className: classNames((_classNames2 = {}, _defineProperty(_classNames2, 'van-swiper__pagination', true), _defineProperty(_classNames2, 'van-swiper__pagination-vertical', isVertical), _classNames2)),
children: Children.map(childs, function (_, index) {
var _classNames3;
return /*#__PURE__*/_jsx(Text, {
style: (active + childCount) % childCount === index ? {
backgroundColor: propSwiper.paginationColor
} : undefined,
className: classNames((_classNames3 = {}, _defineProperty(_classNames3, 'van-swiper__pagination-item', true), _defineProperty(_classNames3, "active", (active + childCount) % childCount === index), _classNames3))
}, index);
})
}) : /*#__PURE__*/_jsx(View, {
children: pageContent
})]
}))
});
};
export var Swiper_ = /*#__PURE__*/forwardRef(Swiper);
export default Swiper_;