@nutui/nutui-react
Version:
京东风格的轻量级移动端 React 组件库,支持一套代码生成 H5 和小程序
260 lines (259 loc) • 10.5 kB
JavaScript
import { _ as _define_property } from "@swc/helpers/_/_define_property";
import { _ as _object_spread } from "@swc/helpers/_/_object_spread";
import { _ as _sliced_to_array } from "@swc/helpers/_/_sliced_to_array";
import React, { useEffect, useMemo, useRef, useState } from "react";
import { useDrag } from "@use-gesture/react";
import { useSpring } from "@react-spring/web";
import classNames from "classnames";
import Indicator from "../indicator";
import { getRefValue, useRefState } from "../../hooks/use-ref-state";
import { defaultEffect } from "./effects/default";
import { focusEffect, updateTransform, useList } from "./effects/focus";
var defaultProps = {
direction: 'horizontal',
indicator: false,
loop: false,
duration: 3000,
autoPlay: false,
defaultValue: 0,
touchable: true,
effect: undefined
};
export var Swiper = /*#__PURE__*/ React.forwardRef(function(props, ref) {
var boundIndex = function boundIndex(current) {
var min = 0;
var max = count - 1;
if (current === max && !loop && props.slideSize) {
var slideSize = props.slideSize;
var swiperSize = getSwiperSize();
var ratio = (swiperSize - slideSize) / slideSize;
return bound(current, min, max - ratio);
}
return current;
};
var classPrefix = 'nut-swiper';
var _$_object_spread = _object_spread({}, defaultProps, props), children = _$_object_spread.children, direction = _$_object_spread.direction, indicator = _$_object_spread.indicator, loop = _$_object_spread.loop, effect = _$_object_spread.effect, autoPlay = _$_object_spread.autoPlay, touchable = _$_object_spread.touchable, defaultValue = _$_object_spread.defaultValue, duration = _$_object_spread.duration, style = _$_object_spread.style, className = _$_object_spread.className;
var isVertical = direction === 'vertical';
var count = useMemo(function() {
var c = 0;
React.Children.map(children, function(child, index) {
c += 1;
});
return c;
}, [
children
]);
var getSlideSize = function() {
if (props.slideSize) return props.slideSize;
if (stageRef.current) {
if (isVertical) return stageRef.current.offsetHeight;
return stageRef.current.offsetWidth;
}
return 0;
};
var getSwiperSize = function() {
if (swiperRef.current) {
if (isVertical) return swiperRef.current.offsetHeight;
return swiperRef.current.offsetWidth;
}
return 0;
};
var bound = function(v, min, max) {
if (min !== undefined) {
v = Math.max(v, min);
}
if (max !== undefined) {
v = Math.min(v, max);
}
return v;
};
var timeoutRef = useRef(null);
var _useState = _sliced_to_array(useState(false), 2), dragging = _useState[0], setDragging = _useState[1];
var _useRefState = _sliced_to_array(useRefState(defaultValue), 2), current = _useRefState[0], setCurrent = _useRefState[1];
var stageRef = useRef(null);
var swiperRef = useRef(null);
var _useSpring = _sliced_to_array(useSpring(function() {
return {
x: !isVertical ? current.current * 100 * -1 : 0,
y: isVertical ? current.current * 100 * -1 : 0,
s: 0,
reset: function() {},
config: {
tension: 200,
friction: 30
}
};
}), 2), springs = _useSpring[0], api = _useSpring[1];
useEffect(function() {
var _obj;
api.start((_obj = {}, _define_property(_obj, isVertical ? 'y' : 'x', boundIndex(current.current) * -1 * 100), _define_property(_obj, "immediate", true), _obj));
}, [
swiperRef.current
]);
var swiperDirection = useRef(1);
var _useList = _sliced_to_array(useList(effect, count, current), 2), transforms = _useList[0], setTransforms = _useList[1];
// 自动播放
var runTimeSwiper = function() {
var durationNumber = typeof duration === 'string' ? parseInt(duration) : duration;
var d = typeof autoPlay === 'number' ? autoPlay : durationNumber;
timeoutRef.current = window.setTimeout(function() {
next();
runTimeSwiper();
}, d);
};
useEffect(function() {
if (!autoPlay || dragging) return;
runTimeSwiper();
return function() {
if (timeoutRef.current) window.clearTimeout(timeoutRef.current);
};
}, [
autoPlay,
duration,
dragging,
count
]);
var to = function(index) {
var immediate = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : false;
var _props_onChange;
var targetIndex = bound(index, 0, count - 1);
if (loop) {
var cycleIndex = index % count;
targetIndex = cycleIndex < 0 ? cycleIndex + count : cycleIndex;
}
setCurrent(targetIndex);
(_props_onChange = props.onChange) === null || _props_onChange === void 0 ? void 0 : _props_onChange.call(props, targetIndex);
if (effect) {
updateTransform(transforms, setTransforms, effect, targetIndex);
}
var _obj;
api.start((_obj = {}, // 这里需要统一成百分比
_define_property(_obj, isVertical ? 'y' : 'x', (loop ? -index : boundIndex(targetIndex) * -1) * 100), _define_property(_obj, "s", 0), _define_property(_obj, "immediate", immediate), _obj));
};
var getSpringsAxis = function() {
return springs[isVertical ? 'y' : 'x'];
};
var next = function() {
to(Math.round(-getSpringsAxis().get() / 100) + 1);
};
var prev = function() {
to(Math.round(-getSpringsAxis().get() / 100) - 1);
};
React.useImperativeHandle(ref, function() {
return {
to: to,
next: next,
prev: prev
};
});
var bind = useDrag(function(state) {
var axis = Number(isVertical);
var slideSize = getSlideSize();
var offset = state.offset[axis];
setDragging(!!state.dragging);
var distance = state.distance[axis];
swiperDirection.current = state.direction[axis];
if (state.last) {
// 计算位置
var swipeDirection = state.direction[axis];
var velocity = state.velocity[axis];
var minIndex = Math.floor(offset / slideSize);
var maxIndex = minIndex + 1;
var index = Math.round((offset + velocity * 2000 * swipeDirection) / slideSize);
to(bound(index, minIndex, maxIndex));
} else {
var _obj;
// 实时移动,换算百分比
api.start((_obj = {}, _define_property(_obj, isVertical ? 'y' : 'x', -(offset / slideSize * 100)), _define_property(_obj, "s", distance / slideSize), _define_property(_obj, "immediate", true), _obj));
}
}, {
enabled: touchable,
transform: function(param) {
var _param = _sliced_to_array(param, 2), x = _param[0], y = _param[1];
return [
-x,
-y
];
},
from: function() {
// 由百分比转换到像素
var slideSize = getSlideSize();
var x = springs.x.get() / 100 * slideSize;
var y = springs.y.get() / 100 * slideSize;
return [
-x,
-y
];
},
bounds: function() {
if (loop) return {};
var slideSize = getSlideSize();
if (isVertical) {
return {
top: 0,
bottom: (count - 1) * slideSize
};
}
return {
left: 0,
right: (count - 1) * slideSize
};
},
rubberband: true,
triggerAllEvents: true,
preventScroll: isVertical,
axis: isVertical ? 'y' : 'x',
pointer: {
touch: true
}
});
var renderIndicator = function() {
if (/*#__PURE__*/ React.isValidElement(indicator)) return indicator;
if (!indicator) return null;
var _obj;
return /*#__PURE__*/ React.createElement("div", {
className: classNames((_obj = {}, _define_property(_obj, "".concat(classPrefix, "-indicator"), true), _define_property(_obj, "".concat(classPrefix, "-indicator-vertical"), isVertical), _define_property(_obj, "".concat(classPrefix, "-indicator-horizontal"), !isVertical), _obj))
}, /*#__PURE__*/ React.createElement(Indicator, {
current: getRefValue(current),
total: count,
direction: direction
}));
};
var renderEffect = function() {
if (!effect) return defaultEffect({
children: children,
getSpringsAxis: getSpringsAxis,
loop: loop,
count: count,
isVertical: isVertical
});
if (effect && effect.name === 'focus') {
return focusEffect({
children: children,
springs: springs,
loop: loop,
count: count,
isVertical: isVertical,
effect: effect,
current: current,
swiperDirection: swiperDirection,
dragging: dragging,
transforms: transforms
});
}
};
var renderSlides = function() {
var _obj;
return /*#__PURE__*/ React.createElement("div", {
ref: stageRef,
className: classNames("".concat(classPrefix, "-inner"), (_obj = {}, _define_property(_obj, "".concat(classPrefix, "-inner-vertical"), isVertical), _define_property(_obj, "".concat(classPrefix, "-inner-horizontal"), !isVertical), _obj)),
style: _object_spread({}, props.slideSize ? _define_property({}, isVertical ? 'height' : 'width', "".concat(props.slideSize, "px")) : {})
}, renderEffect());
};
return /*#__PURE__*/ React.createElement("div", _object_spread({
className: classNames(classPrefix, "".concat(classPrefix, "-canmove-").concat(direction), className),
style: style,
ref: swiperRef
}, bind()), renderSlides(), renderIndicator());
});
Swiper.displayName = 'NutSwiper';