),
+ showArrow: Boolean,
autoplay: Boolean,
dotPlacement: {
type: String as PropType<'top' | 'bottom' | 'left' | 'right'>,
@@ -271,6 +273,7 @@ export default defineComponent({
},
render () {
const {
+ showArrow,
dotPlacement,
mergedClsPrefix,
current,
@@ -350,6 +353,34 @@ export default defineComponent({
)
})}
+ {showArrow && [
+ {
+ this.next()
+ }}
+ >
+
+
,
+ {
+ this.prev()
+ }}
+ >
+
+
+ ]}
)
}
diff --git a/src/carousel/src/styles/index.cssr.ts b/src/carousel/src/styles/index.cssr.ts
index 3853346b111..731a854e4c1 100644
--- a/src/carousel/src/styles/index.cssr.ts
+++ b/src/carousel/src/styles/index.cssr.ts
@@ -47,6 +47,55 @@ export default cB('carousel', `
margin-right: 0;
`)
]),
+ cE('arrow', `
+ position: absolute;
+ transition: transform .1s var(--bezier);
+ transform: scale(1);
+ cursor: pointer;
+ height: 50px;
+ width: 50px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ color: var(--dot-color-active);
+ `, [
+ cM('right', `
+ transform: translateY(-50%);
+ top: 50%;
+ right: 0;
+ `, [
+ c('&:hover', {
+ transform: 'translateY(-50%) scale(1.1)'
+ })
+ ]),
+ cM('left', `
+ transform: translateY(-50%);
+ top: 50%;
+ left: 0;
+ `, [
+ c('&:hover', {
+ transform: 'translateY(-50%) scale(1.1)'
+ })
+ ]),
+ cM('top', `
+ transform: translateX(-50%) rotate(90deg);
+ top: 0;
+ left: 50%;
+ `, [
+ c('&:hover', {
+ transform: 'translateX(-50%) scale(1.1) rotate(90deg)'
+ })
+ ]),
+ cM('bottom', `
+ transform: translateX(-50%) rotate(90deg);
+ bottom: 0;
+ left: 50%;
+ `, [
+ c('&:hover', {
+ transform: 'translateX(-50%) scale(1.1) rotate(90deg)'
+ })
+ ])
+ ]),
cM('left', [
cE('slides', `
flex-direction: column;
diff --git a/src/carousel/tests/Carousel.spec.ts b/src/carousel/tests/Carousel.spec.ts
index abd7ce9f513..8ec4d7f6141 100644
--- a/src/carousel/tests/Carousel.spec.ts
+++ b/src/carousel/tests/Carousel.spec.ts
@@ -1,5 +1,7 @@
+import { h, nextTick } from 'vue'
import { mount } from '@vue/test-utils'
import { NCarousel } from '../index'
+import { sleep } from 'seemly'
describe('n-carousel', () => {
it('should work with import on demand', () => {
@@ -15,4 +17,75 @@ describe('n-carousel', () => {
)
}
})
+
+ it('should work with `showArrow` prop', async () => {
+ const wrapper = mount(NCarousel)
+
+ const dotToArrow = [
+ {
+ dot: ['top', 'bottom'],
+ arrow: ['left', 'right']
+ },
+ {
+ dot: ['left', 'right'],
+ arrow: ['top', 'bottom']
+ }
+ ]
+
+ for (const item of dotToArrow) {
+ for (const dotItem of item.dot) {
+ await wrapper.setProps({ showArrow: true, dotPlacement: dotItem })
+
+ expect(
+ wrapper.find(`.n-carousel__arrow--${item.arrow[0]}`).exists()
+ ).toBe(true)
+ expect(
+ wrapper.find(`.n-carousel__arrow--${item.arrow[1]}`).exists()
+ ).toBe(true)
+ }
+ }
+ })
+
+ it('arrow button should work', async () => {
+ const wrapper = mount(NCarousel, {
+ slots: {
+ default: () => {
+ return [
+ h('img', {
+ style: 'width: 100%; height: 240px; object-fit: cover;',
+ src: 'https://s.anw.red/news/1623152423.jpg!/both/800x450/quality/78/progressive/true/ignore-error/true'
+ }),
+ h('img', {
+ style: 'width: 100%; height: 240px; object-fit: cover;',
+ src: 'https://s.anw.red/news/1623152423.jpg!/both/800x450/quality/78/progressive/true/ignore-error/true'
+ })
+ ]
+ }
+ }
+ })
+
+ await wrapper.setProps({
+ showArrow: true
+ })
+
+ const slidesDOMArray = wrapper.find('.n-carousel__slides').findAll('div')
+
+ expect(slidesDOMArray[1].attributes('aria-hidden')).toBe('false')
+
+ wrapper
+ .find('.n-carousel__arrow--right')
+ .trigger('click')
+ .then(async () => {
+ expect(slidesDOMArray[2].attributes('aria-hidden')).toBe('false')
+ await sleep(1000)
+ nextTick(() => {
+ wrapper
+ .find('.n-carousel__arrow--left')
+ .trigger('click')
+ .then(() => {
+ expect(slidesDOMArray[1].attributes('aria-hidden')).toBe('false')
+ })
+ })
+ })
+ })
})