diff --git a/packages/vant/src/swipe/README.md b/packages/vant/src/swipe/README.md
index 4f4bd19eb56..02185a00e62 100644
--- a/packages/vant/src/swipe/README.md
+++ b/packages/vant/src/swipe/README.md
@@ -137,6 +137,17 @@ export default {
```
+### RTL Layout
+
+```html
+
+ 1
+ 2
+ 3
+ 4
+
+```
+
## API
### Swipe Props
diff --git a/packages/vant/src/swipe/README.zh-CN.md b/packages/vant/src/swipe/README.zh-CN.md
index d7aeb207008..ab8e1278d62 100644
--- a/packages/vant/src/swipe/README.zh-CN.md
+++ b/packages/vant/src/swipe/README.zh-CN.md
@@ -145,6 +145,19 @@ export default {
```
+### RTL 布局
+
+可以通过对上下文或自身样式的direction属性判断调整。
+
+```html
+
+ 1
+ 2
+ 3
+ 4
+
+```
+
## API
### Swipe Props
diff --git a/packages/vant/src/swipe/Swipe.tsx b/packages/vant/src/swipe/Swipe.tsx
index 370c87af2d9..08f4a9a7d28 100644
--- a/packages/vant/src/swipe/Swipe.tsx
+++ b/packages/vant/src/swipe/Swipe.tsx
@@ -25,6 +25,7 @@ import {
preventDefault,
createNamespace,
makeNumericProp,
+ isRtl,
} from '../utils';
// Composables
@@ -83,6 +84,7 @@ export default defineComponent({
// Whether the user is dragging the swipe
let dragging = false;
+ let rtl = false;
const touch = useTouch();
const { children, linkChildren } = useChildren(SWIPE_KEY);
@@ -98,7 +100,9 @@ export default defineComponent({
const minOffset = computed(() => {
if (state.rect) {
const base = props.vertical ? state.rect.height : state.rect.width;
- return base - size.value * count.value;
+ return rtl && !props.vertical
+ ? size.value * count.value - base
+ : base - size.value * count.value;
}
return 0;
});
@@ -111,9 +115,9 @@ export default defineComponent({
const trackSize = computed(() => count.value * size.value);
- const activeIndicator = computed(
- () => (state.active + count.value) % count.value,
- );
+ const activeIndicator = computed(() => {
+ return (state.active + count.value) % count.value;
+ });
const isCorrectDirection = computed(() => {
const expect = props.vertical ? 'vertical' : 'horizontal';
@@ -153,14 +157,21 @@ export default defineComponent({
const getTargetOffset = (targetActive: number, offset = 0) => {
let currentPosition = targetActive * size.value;
if (!props.loop) {
- currentPosition = Math.min(currentPosition, -minOffset.value);
+ currentPosition =
+ rtl && !props.vertical
+ ? Math.min(currentPosition, minOffset.value)
+ : Math.min(currentPosition, -minOffset.value);
}
-
- let targetOffset = offset - currentPosition;
+ let targetOffset =
+ rtl && !props.vertical
+ ? offset + currentPosition
+ : offset - currentPosition;
if (!props.loop) {
- targetOffset = clamp(targetOffset, minOffset.value, 0);
+ targetOffset =
+ rtl && !props.vertical
+ ? clamp(targetOffset, 0, minOffset.value)
+ : clamp(targetOffset, minOffset.value, 0);
}
-
return targetOffset;
};
@@ -180,22 +191,34 @@ export default defineComponent({
const { active } = state;
const targetActive = getTargetActive(pace);
const targetOffset = getTargetOffset(targetActive, offset);
-
// auto move first and last swipe in loop mode
if (props.loop) {
- if (children[0] && targetOffset !== minOffset.value) {
- const outRightBound = targetOffset < minOffset.value;
- children[0].setOffset(outRightBound ? trackSize.value : 0);
- }
+ if (rtl && !props.vertical) {
+ if (children[count.value - 1]) {
+ const outRightBound = targetOffset < size.value;
+ children[count.value - 1].setOffset(
+ outRightBound ? trackSize.value : 0,
+ );
+ }
- if (children[count.value - 1] && targetOffset !== 0) {
- const outLeftBound = targetOffset > 0;
- children[count.value - 1].setOffset(
- outLeftBound ? -trackSize.value : 0,
- );
+ if (children[0]) {
+ const outLeftBound = targetOffset >= minOffset.value;
+ children[0].setOffset(outLeftBound ? -trackSize.value : 0);
+ }
+ } else {
+ if (children[0] && targetOffset !== minOffset.value) {
+ const outRightBound = targetOffset < minOffset.value;
+ children[0].setOffset(outRightBound ? trackSize.value : 0);
+ }
+
+ if (children[count.value - 1] && targetOffset !== 0) {
+ const outLeftBound = targetOffset > 0;
+ children[count.value - 1].setOffset(
+ outLeftBound ? -trackSize.value : 0,
+ );
+ }
}
}
-
state.active = targetActive;
state.offset = targetOffset;
@@ -281,6 +304,7 @@ export default defineComponent({
}
}
+ rtl = isRtl(root);
state.active = active;
state.swiping = true;
state.offset = getTargetOffset(active);
@@ -327,9 +351,13 @@ export default defineComponent({
if (isCorrectDirection.value) {
const isEdgeTouch =
!props.loop &&
- ((state.active === 0 && delta.value > 0) ||
- (state.active === count.value - 1 && delta.value < 0));
-
+ ((!rtl &&
+ ((state.active === 0 && delta.value > 0) ||
+ (state.active === count.value - 1 && delta.value < 0))) ||
+ (rtl &&
+ ((state.active === count.value - 1 && delta.value > 0) ||
+ (state.active === 0 && delta.value < 0)) &&
+ !props.vertical));
if (!isEdgeTouch) {
preventDefault(event, props.stopPropagation);
move({ offset: delta.value });
@@ -357,16 +385,19 @@ export default defineComponent({
const offset = props.vertical
? touch.offsetY.value
: touch.offsetX.value;
-
let pace = 0;
-
if (props.loop) {
- pace = offset > 0 ? (delta.value > 0 ? -1 : 1) : 0;
+ if (offset > 0) {
+ pace = delta.value > 0 ? -1 : 1;
+ } else {
+ pace = 0;
+ }
} else {
pace = -Math[delta.value > 0 ? 'ceil' : 'floor'](
delta.value / size.value,
);
}
+ pace = rtl && !props.vertical ? -pace : pace;
move({
pace,
@@ -430,7 +461,12 @@ export default defineComponent({
}
if (props.showIndicators && count.value > 1) {
return (
-
+
{Array(count.value).fill('').map(renderDot)}
);
diff --git a/packages/vant/src/swipe/demo/index.vue b/packages/vant/src/swipe/demo/index.vue
index 5b33fbd8e8d..d049dfef054 100644
--- a/packages/vant/src/swipe/demo/index.vue
+++ b/packages/vant/src/swipe/demo/index.vue
@@ -11,6 +11,7 @@ const t = useTranslate({
title4: '纵向滚动',
title5: '自定义滑块大小',
title6: '自定义指示器',
+ title7: 'RTL 布局',
message: '当前 Swipe 索引:',
},
'en-US': {
@@ -19,6 +20,7 @@ const t = useTranslate({
title4: 'Vertical Scrolling',
title5: 'Set SwipeItem Size',
title6: 'Custom indicator',
+ title7: ' RTL Layout',
message: 'Current Swipe index:',
},
});
@@ -95,6 +97,15 @@ const onChange = (index: number) => showToast(t('message') + index);
+
+
+
+ 1
+ 2
+ 3
+ 4
+
+