diff --git a/components/carousel/__tests__/index.test.js b/components/carousel/__tests__/index.test.js
index 6f372c2c6..2ee12bd2a 100644
--- a/components/carousel/__tests__/index.test.js
+++ b/components/carousel/__tests__/index.test.js
@@ -21,9 +21,7 @@ describe('Carousel', () => {
sync: false,
};
const wrapper = mount(Carousel, props);
- const { innerSlider, slick } = wrapper.vm;
- const innerSliderFromRefs = slick.innerSlider;
- expect(innerSlider).toBe(innerSliderFromRefs);
+ const { innerSlider } = wrapper.componentVM;
expect(typeof innerSlider.slickNext).toBe('function');
});
@@ -39,26 +37,25 @@ describe('Carousel', () => {
sync: false,
};
const wrapper = mount(Carousel, props);
- const { prev, next, goTo } = wrapper.vm;
+ const { prev, next, goTo, innerSlider } = wrapper.componentVM;
expect(typeof prev).toBe('function');
expect(typeof next).toBe('function');
expect(typeof goTo).toBe('function');
- const slick = wrapper.vm.slick;
- expect(slick.innerSlider.currentSlide).toBe(0);
+ expect(innerSlider.currentSlide).toBe(0);
wrapper.vm.goTo(2);
await asyncExpect(() => {
- expect(slick.innerSlider.currentSlide).toBe(2);
+ expect(innerSlider.currentSlide).toBe(2);
}, 1000);
prev();
await asyncExpect(() => {
- expect(slick.innerSlider.currentSlide).toBe(1);
+ expect(innerSlider.currentSlide).toBe(1);
}, 1000);
next();
await asyncExpect(() => {
- expect(slick.innerSlider.currentSlide).toBe(2);
+ expect(innerSlider.currentSlide).toBe(2);
}, 1000);
});
// TODO
@@ -77,8 +74,8 @@ describe('Carousel', () => {
// sync: false,
// };
// const wrapper = mount(Carousel, props);
-
- // const spy = jest.spyOn(wrapper.vm.slick.innerSlider, 'handleAutoPlay');
+ // await sleep(100);
+ // const spy = jest.spyOn(wrapper.componentVM.innerSlider, 'handleAutoPlay');
// window.resizeTo(1000);
// expect(spy).not.toHaveBeenCalled();
// await new Promise(resolve => setTimeout(resolve, 1000));
@@ -100,12 +97,9 @@ describe('Carousel', () => {
sync: false,
};
const wrapper = mount(Carousel, props);
- const { onWindowResized } = wrapper.vm;
- const spy = jest.spyOn(wrapper.vm.onWindowResized, 'cancel');
- const spy2 = jest.spyOn(window, 'removeEventListener');
+ const spy = jest.spyOn(window, 'removeEventListener');
wrapper.unmount();
expect(spy).toHaveBeenCalled();
- expect(spy2).toHaveBeenCalledWith('resize', onWindowResized);
});
describe('should works for dotPosition', () => {
diff --git a/components/carousel/demo/customPaging.vue b/components/carousel/demo/customPaging.vue
index 0e83c4307..434444be7 100644
--- a/components/carousel/demo/customPaging.vue
+++ b/components/carousel/demo/customPaging.vue
@@ -71,6 +71,7 @@ export default defineComponent({
width: 100%;
height: 100%;
filter: grayscale(100%);
+ display: block;
}
.ant-carousel :deep .slick-thumb li.slick-active img {
filter: grayscale(0%);
diff --git a/components/carousel/index.en-US.md b/components/carousel/index.en-US.md
index 824c68003..bcda411c3 100644
--- a/components/carousel/index.en-US.md
+++ b/components/carousel/index.en-US.md
@@ -17,14 +17,14 @@ A carousel component. Scales with its container.
| Property | Description | Type | Default | Version |
| --- | --- | --- | --- | --- |
-| afterChange | Callback function called after the current index changes | function(current) | - | |
| autoplay | Whether to scroll automatically | boolean | `false` | |
-| beforeChange | Callback function called before the current index changes | function(from, to) | - | |
| dots | Whether to show the dots at the bottom of the gallery | boolean | `true` | |
-| dotPosition | The position of the dots, which can be one of `top` `bottom` `left` `right` | string | bottom | 1.5.0 |
+| dotPosition | The position of the dots, which can be one of `top` `bottom` `left` `right` | string | `bottom` | 1.5.0 |
| dotsClass | Class name of the dots | string | `slick-dots` | |
| easing | Transition interpolation function name | string | `linear` | |
| effect | Transition effect | `scrollx` \| `fade` | `scrollx` | |
+| afterChange | Callback function called after the current index changes | function(current) | - | |
+| beforeChange | Callback function called before the current index changes | function(from, to) | - | |
## Methods
@@ -34,4 +34,4 @@ A carousel component. Scales with its container.
| next() | Change current slide to next slide | |
| prev() | Change current slide to previous slide | |
-For more info on the parameters, refer to the [vc-slick props](https://github.com/vueComponent/ant-design-vue/blob/next/components/vc-slick/src/default-props.js#L3)
+For more info on the props, refer to the [carousel props](https://github.com/vueComponent/ant-design-vue/blob/next/components/carousel/index.tsx)
diff --git a/components/carousel/index.tsx b/components/carousel/index.tsx
index fe5c6bae3..d9f454a20 100644
--- a/components/carousel/index.tsx
+++ b/components/carousel/index.tsx
@@ -1,13 +1,11 @@
import type { ExtractPropTypes, PropType } from 'vue';
-import { defineComponent, inject } from 'vue';
+import { ref, computed, watchEffect, defineComponent } from 'vue';
import PropTypes from '../_util/vue-types';
-import debounce from 'lodash-es/debounce';
-import hasProp, { getComponent } from '../_util/props-util';
-import { defaultConfigProvider } from '../config-provider';
import warning from '../_util/warning';
import classNames from '../_util/classNames';
import SlickCarousel from '../vc-slick/src';
import { withInstall } from '../_util/type';
+import useConfigInject from '../_util/hooks/useConfigInject';
export type SwipeDirection = 'left' | 'down' | 'right' | 'up' | string;
@@ -20,7 +18,7 @@ export interface CarouselRef {
goTo: (slide: number, dontAnimate?: boolean) => void;
next: () => void;
prev: () => void;
- autoPlay: (palyType?: 'update' | 'leave' | 'blur') => void;
+ autoplay: (palyType?: 'update' | 'leave' | 'blur') => void;
innerSlider: any;
}
@@ -60,13 +58,14 @@ export const carouselProps = () => ({
speed: Number,
swipe: { type: Boolean, default: undefined },
swipeToSlide: { type: Boolean, default: undefined },
+ swipeEvent: Function as PropType<(swipeDirection: SwipeDirection) => void>,
touchMove: { type: Boolean, default: undefined },
touchThreshold: Number,
variableWidth: { type: Boolean, default: undefined },
useCSS: { type: Boolean, default: undefined },
slickGoTo: Number,
responsive: Array,
- dotPosition: String as PropType
,
+ dotPosition: { type: String as PropType, default: undefined },
verticalSwiping: { type: Boolean, default: false },
});
export type CarouselProps = Partial>>;
@@ -74,110 +73,76 @@ const Carousel = defineComponent({
name: 'ACarousel',
inheritAttrs: false,
props: carouselProps(),
- setup() {
- return {
- configProvider: inject('configProvider', defaultConfigProvider),
- slick: undefined,
- innerSlider: undefined,
+ setup(props, { slots, attrs, expose }) {
+ const slickRef = ref();
+
+ const goTo = (slide: number, dontAnimate = false) => {
+ slickRef.value?.slickGoTo(slide, dontAnimate);
};
- },
- beforeMount() {
- this.onWindowResized = debounce(this.onWindowResized, 500, {
- leading: false,
- });
- },
- mounted() {
- if (hasProp(this, 'vertical')) {
+
+ expose({
+ goTo,
+ autoplay: palyType => {
+ slickRef.value?.innerSlider?.handleAutoPlay(palyType);
+ },
+ prev: () => {
+ slickRef.value?.slickPrev();
+ },
+ next: () => {
+ slickRef.value?.slickNext();
+ },
+ innerSlider: computed(() => {
+ return slickRef.value?.innerSlider;
+ }),
+ } as CarouselRef);
+ watchEffect(() => {
warning(
- !this.vertical,
+ props.vertical === undefined,
'Carousel',
'`vertical` is deprecated, please use `dotPosition` instead.',
);
- }
- const { autoplay } = this;
- if (autoplay) {
- window.addEventListener('resize', this.onWindowResized);
- }
- // https://github.com/ant-design/ant-design/issues/7191
- this.innerSlider = this.slick && this.slick.innerSlider;
- },
- beforeUnmount() {
- const { autoplay } = this;
- if (autoplay) {
- window.removeEventListener('resize', this.onWindowResized);
- (this.onWindowResized as any).cancel();
- }
- },
- methods: {
- getDotPosition() {
- if (this.dotPosition) {
- return this.dotPosition;
- }
- if (hasProp(this, 'vertical')) {
- return this.vertical ? 'right' : 'bottom';
- }
+ });
+ const { prefixCls, direction } = useConfigInject('carousel', props);
+ const dotPosition = computed(() => {
+ if (props.dotPosition) return props.dotPosition;
+ if (props.vertical !== undefined) return props.vertical ? 'right' : 'bottom';
return 'bottom';
- },
- saveSlick(node: HTMLElement) {
- this.slick = node;
- },
- onWindowResized() {
- // Fix https://github.com/ant-design/ant-design/issues/2550
- const { autoplay } = this;
- if (autoplay && this.slick && this.slick.innerSlider && this.slick.innerSlider.autoPlay) {
- this.slick.innerSlider.autoPlay();
- }
- },
-
- next() {
- this.slick.slickNext();
- },
-
- prev() {
- this.slick.slickPrev();
- },
-
- goTo(slide: number, dontAnimate = false) {
- this.slick.slickGoTo(slide, dontAnimate);
- },
- },
-
- render() {
- const props = { ...this.$props };
- const { $slots } = this;
-
- if (props.effect === 'fade') {
- props.fade = true;
- }
- const { class: cls, style, ...restAttrs } = this.$attrs as any;
- const getPrefixCls = this.configProvider.getPrefixCls;
- let className = getPrefixCls('carousel', props.prefixCls);
- const dotsClass = 'slick-dots';
- const dotPosition = this.getDotPosition();
- props.vertical = dotPosition === 'left' || dotPosition === 'right';
- props.dotsClass = classNames(`${dotsClass}`, `${dotsClass}-${dotPosition || 'bottom'}`, {
- [`${props.dotsClass}`]: !!props.dotsClass,
});
- className = classNames({
- [cls]: !!cls,
- [className]: !!className,
- [`${className}-vertical`]: props.vertical,
+ const vertical = computed(() => dotPosition.value === 'left' || dotPosition.value === 'right');
+ const dsClass = computed(() => {
+ const dotsClass = 'slick-dots';
+ return classNames({
+ [dotsClass]: true,
+ [`${dotsClass}-${dotPosition.value}`]: true,
+ [`${props.dotsClass}`]: !!props.dotsClass,
+ });
});
- const SlickCarouselProps = {
- ...props,
- ...restAttrs,
- nextArrow: getComponent(this, 'nextArrow'),
- prevArrow: getComponent(this, 'prevArrow'),
+ return () => {
+ const { dots, arrows, draggable, effect } = props;
+ const { class: cls, style, ...restAttrs } = attrs;
+ const fade = effect === 'fade' ? true : props.fade;
+ const className = classNames(prefixCls.value, {
+ [`${prefixCls.value}-rtl`]: direction.value === 'rtl',
+ [`${prefixCls.value}-vertical`]: vertical.value,
+ [`${cls}`]: !!cls,
+ });
+ return (
+
+
+
+ );
};
- return (
-
-
-
- );
},
});
diff --git a/components/carousel/index.zh-CN.md b/components/carousel/index.zh-CN.md
index ce56d3a35..130a1a669 100644
--- a/components/carousel/index.zh-CN.md
+++ b/components/carousel/index.zh-CN.md
@@ -18,14 +18,14 @@ cover: https://gw.alipayobjects.com/zos/antfincdn/%24C9tmj978R/Carousel.svg
| 参数 | 说明 | 类型 | 默认值 | 版本 |
| --- | --- | --- | --- | --- |
-| afterChange | 切换面板的回调 | function(current) | 无 | |
| autoplay | 是否自动切换 | boolean | false | |
-| beforeChange | 切换面板的回调 | function(from, to) | 无 | |
-| dotPosition | 面板指示点位置,可选 `top` `bottom` `left` `right` | string | bottom | 1.5.0 |
+| dotPosition | 面板指示点位置,可选 `top` `bottom` `left` `right` | string | `bottom` | 1.5.0 |
| dots | 是否显示面板指示点 | boolean | true | |
| dotsClass | 面板指示点类名 | string | `slick-dots` | |
-| easing | 动画效果 | string | linear | |
-| effect | 动画效果函数,可取 scrollx, fade | string | scrollx | |
+| easing | 动画效果 | string | `linear` | |
+| effect | 动画效果函数 | `scrollx` \| `fade` | `scrollx` | |
+| afterChange | 切换面板的回调 | function(current) | - | |
+| beforeChange | 切换面板的回调 | function(from, to) | - | |
## 方法
@@ -35,4 +35,4 @@ cover: https://gw.alipayobjects.com/zos/antfincdn/%24C9tmj978R/Carousel.svg
| next() | 切换到下一面板 | |
| prev() | 切换到上一面板 | |
-更多参数可参考:[vc-slick props](https://github.com/vueComponent/ant-design-vue/blob/next/components/vc-slick/src/default-props.js#L3)
+更多属性可参考源码:[carousel props](https://github.com/vueComponent/ant-design-vue/blob/next/components/carousel/index.tsx)
diff --git a/components/vc-slick/src/inner-slider.jsx b/components/vc-slick/src/inner-slider.jsx
index 1ed82b589..cf78697fe 100644
--- a/components/vc-slick/src/inner-slider.jsx
+++ b/components/vc-slick/src/inner-slider.jsx
@@ -164,7 +164,7 @@ export default {
if (this.autoplayTimer) {
clearInterval(this.autoplayTimer);
}
- this.ro.disconnect();
+ this.ro?.disconnect();
},
updated() {
this.checkImagesLoad();
diff --git a/components/vc-slick/src/slider.jsx b/components/vc-slick/src/slider.jsx
index 6318cc5ff..21afd5cd7 100644
--- a/components/vc-slick/src/slider.jsx
+++ b/components/vc-slick/src/slider.jsx
@@ -77,19 +77,19 @@ export default defineComponent({
this._responsiveMediaHandlers.push({ mql, query, listener });
},
slickPrev() {
- this.innerSlider.slickPrev();
+ this.innerSlider?.slickPrev();
},
slickNext() {
- this.innerSlider.slickNext();
+ this.innerSlider?.slickNext();
},
slickGoTo(slide, dontAnimate = false) {
- this.innerSlider.slickGoTo(slide, dontAnimate);
+ this.innerSlider?.slickGoTo(slide, dontAnimate);
},
slickPause() {
- this.innerSlider.pause('paused');
+ this.innerSlider?.pause('paused');
},
slickPlay() {
- this.innerSlider.handleAutoPlay('play');
+ this.innerSlider?.handleAutoPlay('play');
},
},