feat: add carousel

pull/165/head
wangxueliang 2018-07-20 16:13:21 +08:00
parent e6367f26cb
commit dcf2048231
77 changed files with 5638 additions and 6 deletions

View File

@ -14,7 +14,8 @@ module.exports = {
"jsx",
"json",
"vue",
"md"
"md",
"jpg"
],
modulePathIgnorePatterns: [
'/_site/',

View File

@ -0,0 +1,318 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders ./components/carousel/demo/autoplay.md correctly 1`] = `
<div class="ant-carousel">
<div class="slick-slider slick-initialized">
<div class="slick-list">
<div class="slick-track" style="width: 900%; left: -100%;">
<div tabindex="-1" data-index="-1" aria-hidden="true" class="slick-slide slick-cloned" style="width: 11.11111111111111%;">
<div>
<div tabindex="-1" class="" style="width: 100%; display: inline-block;">
<h3>4</h3>
</div>
</div>
</div>
<div tabindex="-1" data-index="0" class="slick-slide slick-active slick-current" style="outline: none; width: 11.11111111111111%;">
<div>
<div tabindex="-1" class="" style="width: 100%; display: inline-block;">
<h3>1</h3>
</div>
</div>
</div>
<div tabindex="-1" data-index="1" aria-hidden="true" class="slick-slide" style="outline: none; width: 11.11111111111111%;">
<div>
<div tabindex="-1" class="" style="width: 100%; display: inline-block;">
<h3>2</h3>
</div>
</div>
</div>
<div tabindex="-1" data-index="2" aria-hidden="true" class="slick-slide" style="outline: none; width: 11.11111111111111%;">
<div>
<div tabindex="-1" class="" style="width: 100%; display: inline-block;">
<h3>3</h3>
</div>
</div>
</div>
<div tabindex="-1" data-index="3" aria-hidden="true" class="slick-slide" style="outline: none; width: 11.11111111111111%;">
<div>
<div tabindex="-1" class="" style="width: 100%; display: inline-block;">
<h3>4</h3>
</div>
</div>
</div>
<div tabindex="-1" data-index="4" aria-hidden="true" class="slick-slide slick-cloned" style="width: 11.11111111111111%;">
<div>
<div tabindex="-1" class="" style="width: 100%; display: inline-block;">
<h3>1</h3>
</div>
</div>
</div>
<div tabindex="-1" data-index="5" aria-hidden="true" class="slick-slide slick-cloned" style="width: 11.11111111111111%;">
<div>
<div tabindex="-1" class="" style="width: 100%; display: inline-block;">
<h3>2</h3>
</div>
</div>
</div>
<div tabindex="-1" data-index="6" aria-hidden="true" class="slick-slide slick-cloned" style="width: 11.11111111111111%;">
<div>
<div tabindex="-1" class="" style="width: 100%; display: inline-block;">
<h3>3</h3>
</div>
</div>
</div>
<div tabindex="-1" data-index="7" aria-hidden="true" class="slick-slide slick-cloned" style="width: 11.11111111111111%;">
<div>
<div tabindex="-1" class="" style="width: 100%; display: inline-block;">
<h3>4</h3>
</div>
</div>
</div>
</div>
</div>
<ul class="slick-dots" style="display: block;">
<li class="slick-active">
<button class="">1</button>
</li>
<li class="">
<button class="">2</button>
</li>
<li class="">
<button class="">3</button>
</li>
<li class="">
<button class="">4</button>
</li>
</ul>
</div>
</div>
`;
exports[`renders ./components/carousel/demo/basic.md correctly 1`] = `
<div class="ant-carousel">
<div class="slick-slider slick-initialized">
<div class="slick-list">
<div class="slick-track" style="width: 900%; left: -100%;">
<div tabindex="-1" data-index="-1" aria-hidden="true" class="slick-slide slick-cloned" style="width: 11.11111111111111%;">
<div>
<div tabindex="-1" class="" style="width: 100%; display: inline-block;">
<h3>4</h3>
</div>
</div>
</div>
<div tabindex="-1" data-index="0" class="slick-slide slick-active slick-current" style="outline: none; width: 11.11111111111111%;">
<div>
<div tabindex="-1" class="" style="width: 100%; display: inline-block;">
<h3>1</h3>
</div>
</div>
</div>
<div tabindex="-1" data-index="1" aria-hidden="true" class="slick-slide" style="outline: none; width: 11.11111111111111%;">
<div>
<div tabindex="-1" class="" style="width: 100%; display: inline-block;">
<h3>2</h3>
</div>
</div>
</div>
<div tabindex="-1" data-index="2" aria-hidden="true" class="slick-slide" style="outline: none; width: 11.11111111111111%;">
<div>
<div tabindex="-1" class="" style="width: 100%; display: inline-block;">
<h3>3</h3>
</div>
</div>
</div>
<div tabindex="-1" data-index="3" aria-hidden="true" class="slick-slide" style="outline: none; width: 11.11111111111111%;">
<div>
<div tabindex="-1" class="" style="width: 100%; display: inline-block;">
<h3>4</h3>
</div>
</div>
</div>
<div tabindex="-1" data-index="4" aria-hidden="true" class="slick-slide slick-cloned" style="width: 11.11111111111111%;">
<div>
<div tabindex="-1" class="" style="width: 100%; display: inline-block;">
<h3>1</h3>
</div>
</div>
</div>
<div tabindex="-1" data-index="5" aria-hidden="true" class="slick-slide slick-cloned" style="width: 11.11111111111111%;">
<div>
<div tabindex="-1" class="" style="width: 100%; display: inline-block;">
<h3>2</h3>
</div>
</div>
</div>
<div tabindex="-1" data-index="6" aria-hidden="true" class="slick-slide slick-cloned" style="width: 11.11111111111111%;">
<div>
<div tabindex="-1" class="" style="width: 100%; display: inline-block;">
<h3>3</h3>
</div>
</div>
</div>
<div tabindex="-1" data-index="7" aria-hidden="true" class="slick-slide slick-cloned" style="width: 11.11111111111111%;">
<div>
<div tabindex="-1" class="" style="width: 100%; display: inline-block;">
<h3>4</h3>
</div>
</div>
</div>
</div>
</div>
<ul class="slick-dots" style="display: block;">
<li class="slick-active">
<button class="">1</button>
</li>
<li class="">
<button class="">2</button>
</li>
<li class="">
<button class="">3</button>
</li>
<li class="">
<button class="">4</button>
</li>
</ul>
</div>
</div>
`;
exports[`renders ./components/carousel/demo/fade.md correctly 1`] = `
<div class="ant-carousel">
<div class="slick-slider slick-initialized">
<div class="slick-list">
<div class="slick-track" style="width: 900%; left: -100%;">
<div tabindex="-1" data-index="0" class="slick-slide slick-active slick-current" style="outline: none; width: 11.11111111111111%; position: relative; left: 0px; opacity: 1;">
<div>
<div tabindex="-1" class="" style="width: 100%; display: inline-block;">
<h3>1</h3>
</div>
</div>
</div>
<div tabindex="-1" data-index="1" aria-hidden="true" class="slick-slide" style="outline: none; width: 11.11111111111111%; position: relative; left: -11px; opacity: 0;">
<div>
<div tabindex="-1" class="" style="width: 100%; display: inline-block;">
<h3>2</h3>
</div>
</div>
</div>
<div tabindex="-1" data-index="2" aria-hidden="true" class="slick-slide" style="outline: none; width: 11.11111111111111%; position: relative; left: -22px; opacity: 0;">
<div>
<div tabindex="-1" class="" style="width: 100%; display: inline-block;">
<h3>3</h3>
</div>
</div>
</div>
<div tabindex="-1" data-index="3" aria-hidden="true" class="slick-slide" style="outline: none; width: 11.11111111111111%; position: relative; left: -33px; opacity: 0;">
<div>
<div tabindex="-1" class="" style="width: 100%; display: inline-block;">
<h3>4</h3>
</div>
</div>
</div>
</div>
</div>
<ul class="slick-dots" style="display: block;">
<li class="slick-active">
<button class="">1</button>
</li>
<li class="">
<button class="">2</button>
</li>
<li class="">
<button class="">3</button>
</li>
<li class="">
<button class="">4</button>
</li>
</ul>
</div>
</div>
`;
exports[`renders ./components/carousel/demo/vertical.md correctly 1`] = `
<div class="ant-carousel ant-carousel-vertical">
<div class="slick-slider slick-vertical slick-initialized">
<div class="slick-list">
<div class="slick-track" style="width: 900%; left: -100%;">
<div tabindex="-1" data-index="-1" aria-hidden="true" class="slick-slide slick-cloned" style="width: 11.11111111111111%;">
<div>
<div tabindex="-1" class="" style="width: 100%; display: inline-block;">
<h3>4</h3>
</div>
</div>
</div>
<div tabindex="-1" data-index="0" class="slick-slide slick-active slick-current" style="outline: none; width: 11.11111111111111%;">
<div>
<div tabindex="-1" class="" style="width: 100%; display: inline-block;">
<h3>1</h3>
</div>
</div>
</div>
<div tabindex="-1" data-index="1" aria-hidden="true" class="slick-slide" style="outline: none; width: 11.11111111111111%;">
<div>
<div tabindex="-1" class="" style="width: 100%; display: inline-block;">
<h3>2</h3>
</div>
</div>
</div>
<div tabindex="-1" data-index="2" aria-hidden="true" class="slick-slide" style="outline: none; width: 11.11111111111111%;">
<div>
<div tabindex="-1" class="" style="width: 100%; display: inline-block;">
<h3>3</h3>
</div>
</div>
</div>
<div tabindex="-1" data-index="3" aria-hidden="true" class="slick-slide" style="outline: none; width: 11.11111111111111%;">
<div>
<div tabindex="-1" class="" style="width: 100%; display: inline-block;">
<h3>4</h3>
</div>
</div>
</div>
<div tabindex="-1" data-index="4" aria-hidden="true" class="slick-slide slick-cloned" style="width: 11.11111111111111%;">
<div>
<div tabindex="-1" class="" style="width: 100%; display: inline-block;">
<h3>1</h3>
</div>
</div>
</div>
<div tabindex="-1" data-index="5" aria-hidden="true" class="slick-slide slick-cloned" style="width: 11.11111111111111%;">
<div>
<div tabindex="-1" class="" style="width: 100%; display: inline-block;">
<h3>2</h3>
</div>
</div>
</div>
<div tabindex="-1" data-index="6" aria-hidden="true" class="slick-slide slick-cloned" style="width: 11.11111111111111%;">
<div>
<div tabindex="-1" class="" style="width: 100%; display: inline-block;">
<h3>3</h3>
</div>
</div>
</div>
<div tabindex="-1" data-index="7" aria-hidden="true" class="slick-slide slick-cloned" style="width: 11.11111111111111%;">
<div>
<div tabindex="-1" class="" style="width: 100%; display: inline-block;">
<h3>4</h3>
</div>
</div>
</div>
</div>
</div>
<ul class="slick-dots" style="display: block;">
<li class="slick-active">
<button class="">1</button>
</li>
<li class="">
<button class="">2</button>
</li>
<li class="">
<button class="">3</button>
</li>
<li class="">
<button class="">4</button>
</li>
</ul>
</div>
</div>
`;

View File

@ -0,0 +1,3 @@
import demoTest from '../../../tests/shared/demoTest'
demoTest('carousel', { skip: ['customPaging.md'] })

View File

@ -0,0 +1,87 @@
import { mount } from '@vue/test-utils'
import { asyncExpect } from '@/tests/utils'
import Carousel from '..'
describe('Carousel', () => {
it('should has innerSlider', () => {
const props = {
slots: {
default: '<div />',
},
sync: true,
}
const wrapper = mount(Carousel, props)
const { innerSlider, $refs } = wrapper.vm
const innerSliderFromRefs = $refs.slick.innerSlider
expect(innerSlider).toBe(innerSliderFromRefs)
expect(typeof innerSlider.slickNext).toBe('function')
})
it('should has prev, next and go function', async () => {
const props = {
slots: {
default: '<div>1</div><div>2</div><div>3</div>',
},
sync: true,
}
const wrapper = mount(Carousel, props)
const { prev, next, goTo } = wrapper.vm
expect(typeof prev).toBe('function')
expect(typeof next).toBe('function')
expect(typeof goTo).toBe('function')
const slick = wrapper.vm.$refs.slick
expect(slick.innerSlider.currentSlide).toBe(0)
wrapper.vm.goTo(2)
await asyncExpect(() => {
expect(slick.innerSlider.currentSlide).toBe(2)
}, 1000)
prev()
await asyncExpect(() => {
expect(slick.innerSlider.currentSlide).toBe(1)
}, 1000)
next()
await asyncExpect(() => {
expect(slick.innerSlider.currentSlide).toBe(2)
}, 1000)
})
it('should trigger autoPlay after window resize', async () => {
const props = {
propsData: {
autoplay: true,
},
slots: {
default: '<div>1</div><div>2</div><div>3</div>',
},
sync: true,
}
const wrapper = mount(Carousel, props)
const spy = jest.spyOn(wrapper.vm.$refs.slick.innerSlider, 'handleAutoPlay')
window.resizeTo(1000)
expect(spy).not.toBeCalled()
await new Promise(resolve => setTimeout(resolve, 1000))
expect(spy).toBeCalled()
})
it('cancel resize listener when unmount', async () => {
const props = {
propsData: {
autoplay: true,
},
slots: {
default: '<div>1</div><div>2</div><div>3</div>',
},
sync: true,
}
const wrapper = mount(Carousel, props)
const onWindowResized = wrapper.vm.onWindowResized
const spy = jest.spyOn(wrapper.vm.onWindowResized, 'cancel')
const spy2 = jest.spyOn(window, 'removeEventListener')
wrapper.destroy()
expect(spy).toBeCalled()
expect(spy2).toBeCalledWith('resize', onWindowResized)
})
})

View File

@ -0,0 +1,38 @@
<cn>
#### 自动切换
定时切换下一张。
</cn>
<us>
#### Scroll automatically
Timing of scrolling to the next card/picture.
</us>
```html
<template>
<a-carousel autoplay>
<div><h3>1</h3></div>
<div><h3>2</h3></div>
<div><h3>3</h3></div>
<div><h3>4</h3></div>
</a-carousel>
</template>
<script>
export default {
}
</script>
<style scoped>
/* For demo */
.ant-carousel >>> .slick-slide {
text-align: center;
height: 160px;
line-height: 160px;
background: #364d79;
overflow: hidden;
}
.ant-carousel >>> .slick-slide h3 {
color: #fff;
}
</style>
```

View File

@ -0,0 +1,43 @@
<cn>
#### 基本
最简单的用法。
</cn>
<us>
#### Basic
Basic usage.
</us>
```html
<template>
<a-carousel :afterChange="onChange">
<div><h3>1</h3></div>
<div><h3>2</h3></div>
<div><h3>3</h3></div>
<div><h3>4</h3></div>
</a-carousel>
</template>
<script>
export default {
methods: {
onChange (a, b, c) {
console.log(a, b, c)
},
},
}
</script>
<style scoped>
/* For demo */
.ant-carousel >>> .slick-slide {
text-align: center;
height: 160px;
line-height: 160px;
background: #364d79;
overflow: hidden;
}
.ant-carousel >>> .slick-slide h3 {
color: #fff;
}
</style>
```

View File

@ -0,0 +1,73 @@
<cn>
#### 自定义分页
自定义分页展示。
</cn>
<us>
#### Custom Paging
Custom paging display
</us>
```html
<template>
<a-carousel arrows dotsClass="slick-dots slick-thumb">
<a slot="customPaging" slot-scope="props">
<img :src="getImgUrl(props.i)" />
</a>
<div>
<img :src="imgList['abstract01']" />
</div>
<div>
<img :src="imgList['abstract02']" />
</div>
<div>
<img :src="imgList['abstract03']" />
</div>
<div>
<img :src="imgList['abstract04']" />
</div>
</a-carousel>
</template>
<script>
import imgList from '../../vc-slick/demo/imglist'
export default {
data() {
return {
imgList,
}
},
methods: {
getImgUrl(i) {
return this.imgList[`abstract0${i + 1}`]
}
}
}
</script>
<style scoped>
/* For demo */
.ant-carousel >>> .slick-dots {
height: auto
}
.ant-carousel >>> .slick-slide img{
border: 5px solid #FFF;
display: block;
margin: auto;
max-width: 80%;
}
.ant-carousel >>> .slick-thumb {
bottom: -45px;
}
.ant-carousel >>> .slick-thumb li {
width: 60px;
height: 45px;
}
.ant-carousel >>> .slick-thumb li img {
width: 100%;
height: 100%;
filter: grayscale(100%);
}
.ant-carousel >>> .slick-thumb li.slick-active img{
filter: grayscale(0%);
}
</style>
```

View File

@ -0,0 +1,38 @@
<cn>
#### 渐显
切换效果为渐显。
</cn>
<us>
#### Fade in
Slides use fade for transition.
</us>
```html
<template>
<a-carousel effect="fade">
<div><h3>1</h3></div>
<div><h3>2</h3></div>
<div><h3>3</h3></div>
<div><h3>4</h3></div>
</a-carousel>
</template>
<script>
export default {
}
</script>
<style scoped>
/* For demo */
.ant-carousel >>> .slick-slide {
text-align: center;
height: 160px;
line-height: 160px;
background: #364d79;
overflow: hidden;
}
.ant-carousel >>> .slick-slide h3 {
color: #fff;
}
</style>
```

View File

@ -0,0 +1,53 @@
<script>
import Basic from './basic'
import Fade from './fade'
import Autoplay from './autoplay'
import Vertical from './vertical'
import CustomPaging from './customPaging'
import CN from '../index.zh-CN.md'
import US from '../index.en-US.md'
import '../style'
const md = {
cn: `# 旋转木马,一组轮播的区域。
## 何时使用
- 当有一组平级的内容
- 当内容空间不足时可以用走马灯的形式进行收纳进行轮播展现
- 常用于一组图片或卡片轮播
## 代码演示
`,
us: `# A carousel component. Scales with its container.
## When To Use
- When there is a group of content on the same level.
- When there is insufficient content space, it can be used to save space in the form of a revolving door.
- Commonly used for a group of pictures/cards.
## Examples
`,
}
export default {
category: 'Components',
type: 'Data Display',
title: 'Carousel',
subtitle: '走马灯',
render () {
return (
<div>
<md cn={md.cn} us={md.us} />
<Basic />
<Vertical />
<Fade />
<Autoplay />
<CustomPaging />
<api>
<CN slot='cn' />
<US />
</api>
</div>
)
},
}
</script>

View File

@ -0,0 +1,38 @@
<cn>
#### 垂直
垂直显示。
</cn>
<us>
#### Vertical
Vertical pagination.
</us>
```html
<template>
<a-carousel vertical>
<div><h3>1</h3></div>
<div><h3>2</h3></div>
<div><h3>3</h3></div>
<div><h3>4</h3></div>
</a-carousel>
</template>
<script>
export default {
}
</script>
<style scoped>
/* For demo */
.ant-carousel >>> .slick-slide {
text-align: center;
height: 160px;
line-height: 160px;
background: #364d79;
overflow: hidden;
}
.ant-carousel >>> .slick-slide h3 {
color: #fff;
}
</style>
```

View File

@ -0,0 +1,21 @@
## API
| Property | Description | Type | Default |
| -------- | ----------- | ---- | ------- |
| 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` |
| easing | Transition interpolation function name | string | `linear` |
| effect | Transition effect | `scrollx` \| `fade` | `scrollx` |
| vertical | Whether to use a vertical display | boolean | `false` |
## Methods
| Name | Description |
| ---- | ----------- |
| goTo(slideNumber) | Change current slide to given slide number |
| next() | Change current slide to next slide |
| prev() | Change current slide to previous slide |
For more info on the parameters, refer to the <https://github.com/akiran/react-slick>

View File

@ -0,0 +1,159 @@
import PropTypes from '../_util/vue-types'
import debounce from 'lodash/debounce'
import { initDefaultProps, getComponentFromProp, filterEmpty } from '../_util/props-util'
// matchMedia polyfill for
// https://github.com/WickyNilliams/enquire.js/issues/82
if (typeof window !== 'undefined') {
const matchMediaPolyfill = (mediaQuery) => {
return {
media: mediaQuery,
matches: false,
addListener () {
},
removeListener () {
},
}
}
window.matchMedia = window.matchMedia || matchMediaPolyfill
}
// Use require over import (will be lifted up)
// make sure matchMedia polyfill run before require('vc-slick')
// Fix https://github.com/ant-design/ant-design/issues/6560
// Fix https://github.com/ant-design/ant-design/issues/3308
const SlickCarousel = require('../vc-slick/src').default
export const CarouselEffect = PropTypes.oneOf(['scrollx', 'fade'])
// Carousel
export const CarouselProps = {
effect: CarouselEffect,
dots: PropTypes.bool,
vertical: PropTypes.bool,
autoplay: PropTypes.bool,
easing: PropTypes.string,
beforeChange: PropTypes.func,
afterChange: PropTypes.func,
// style: PropTypes.React.CSSProperties,
prefixCls: PropTypes.string,
accessibility: PropTypes.bool,
nextArrow: PropTypes.any,
prevArrow: PropTypes.any,
pauseOnHover: PropTypes.bool,
// className: PropTypes.string,
adaptiveHeight: PropTypes.bool,
arrows: PropTypes.bool,
autoplaySpeed: PropTypes.number,
centerMode: PropTypes.bool,
centerPadding: PropTypes.string,
cssEase: PropTypes.string,
dotsClass: PropTypes.string,
draggable: PropTypes.bool,
fade: PropTypes.bool,
focusOnSelect: PropTypes.bool,
infinite: PropTypes.bool,
initialSlide: PropTypes.number,
lazyLoad: PropTypes.bool,
rtl: PropTypes.bool,
slide: PropTypes.string,
slidesToShow: PropTypes.number,
slidesToScroll: PropTypes.number,
speed: PropTypes.number,
swipe: PropTypes.bool,
swipeToSlide: PropTypes.bool,
touchMove: PropTypes.bool,
touchThreshold: PropTypes.number,
variableWidth: PropTypes.bool,
useCSS: PropTypes.bool,
slickGoTo: PropTypes.number,
}
export default {
name: 'ACarousel',
props: initDefaultProps(CarouselProps, {
dots: true,
arrows: false,
prefixCls: 'ant-carousel',
draggable: false,
}),
// innerSlider: any;
// private slick: any;
beforeMount () {
this.onWindowResized = debounce(this.onWindowResized, 500, {
leading: false,
})
},
mounted () {
const { autoplay } = this
if (autoplay) {
window.addEventListener('resize', this.onWindowResized)
}
// https://github.com/ant-design/ant-design/issues/7191
this.innerSlider = this.$refs.slick && this.$refs.slick.innerSlider
},
beforeDestroy () {
const { autoplay } = this
if (autoplay) {
window.removeEventListener('resize', this.onWindowResized)
this.onWindowResized.cancel()
}
},
methods: {
onWindowResized () {
// Fix https://github.com/ant-design/ant-design/issues/2550
const { autoplay } = this
if (autoplay && this.$refs.slick && this.$refs.slick.innerSlider && this.$refs.slick.innerSlider.autoPlay) {
this.$refs.slick.innerSlider.autoPlay()
}
},
next () {
this.$refs.slick.slickNext()
},
prev () {
this.$refs.slick.slickPrev()
},
goTo (slide) {
this.$refs.slick.slickGoTo(slide)
},
},
render () {
const props = {
...this.$props,
}
const { $slots, $listeners } = this
if (props.effect === 'fade') {
props.fade = true
}
let className = props.prefixCls
if (props.vertical) {
className = `${className} ${className}-vertical`
}
const SlickCarouselProps = {
props: {
...props,
nextArrow: getComponentFromProp(this, 'nextArrow'),
prevArrow: getComponentFromProp(this, 'prevArrow'),
},
on: $listeners,
scopedSlots: this.$scopedSlots,
}
return (
<div class={className}>
<SlickCarousel ref='slick' {...SlickCarouselProps}>
{filterEmpty($slots.default)}
</SlickCarousel>
</div>
)
},
}

View File

@ -0,0 +1,21 @@
## API
| 参数 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| afterChange | 切换面板的回调 | function(current) | 无 |
| autoplay | 是否自动切换 | boolean | false |
| beforeChange | 切换面板的回调 | function(from, to) | 无 |
| dots | 是否显示面板指示点 | boolean | true |
| easing | 动画效果 | string | linear |
| effect | 动画效果函数,可取 scrollx, fade | string | scrollx |
| vertical | 垂直显示 | boolean | false |
## 方法
| 名称 | 描述 |
| --- | --- |
| goTo(slideNumber) | 切换到指定面板 |
| next() | 切换到下一面板 |
| prev() | 切换到上一面板 |
更多参数可参考:<https://github.com/akiran/react-slick>

View File

@ -0,0 +1,2 @@
import '../../style/index.less'
import './index.less'

View File

@ -0,0 +1,210 @@
@import "../../style/themes/default";
@import "../../style/mixins/index";
.@{ant-prefix}-carousel {
.reset-component;
.slick-slider {
position: relative;
display: block;
box-sizing: border-box;
-webkit-touch-callout: none;
-ms-touch-action: pan-y;
touch-action: pan-y;
-webkit-tap-highlight-color: transparent;
}
.slick-list {
position: relative;
overflow: hidden;
display: block;
margin: 0;
padding: 0;
&:focus {
outline: none;
}
&.dragging {
cursor: pointer;
}
}
.slick-slider .slick-track,
.slick-slider .slick-list {
transform: translate3d(0, 0, 0);
}
.slick-track {
position: relative;
left: 0;
top: 0;
display: block;
&:before,
&:after {
content: "";
display: table;
}
&:after {
clear: both;
}
.slick-loading & {
visibility: hidden;
}
}
.slick-slide {
float: left;
height: 100%;
min-height: 1px;
[dir="rtl"] & {
float: right;
}
img {
display: block;
}
&.slick-loading img {
display: none;
}
display: none;
&.dragging img {
pointer-events: none;
}
}
.slick-initialized .slick-slide {
display: block;
}
.slick-loading .slick-slide {
visibility: hidden;
}
.slick-vertical .slick-slide {
display: block;
height: auto;
border: @border-width-base @border-style-base transparent;
}
.slick-arrow.slick-hidden {
display: none;
}
// Arrows
.slick-prev,
.slick-next {
position: absolute;
display: block;
height: 20px;
width: 20px;
line-height: 0;
font-size: 0;
cursor: pointer;
background: transparent;
color: transparent;
top: 50%;
margin-top: -10px;
padding: 0;
border: 0;
outline: none;
&:hover,
&:focus {
outline: none;
background: transparent;
color: transparent;
&:before {
opacity: 1;
}
}
&.slick-disabled:before {
opacity: 0.25;
}
}
.slick-prev {
left: -25px;
&:before {
content: "←";
}
}
.slick-next {
right: -25px;
&:before {
content: "→";
}
}
// Dots
.slick-dots {
position: absolute;
bottom: 12px;
list-style: none;
display: block;
text-align: center;
margin: 0;
padding: 0;
width: 100%;
height: @carousel-dot-height;
li {
position: relative;
display: inline-block;
vertical-align: top;
text-align: center;
margin: 0 2px;
padding: 0;
button {
border: 0;
cursor: pointer;
background: #fff;
opacity: 0.3;
display: block;
width: @carousel-dot-width;
height: @carousel-dot-height;
border-radius: 1px;
outline: none;
font-size: 0;
color: transparent;
transition: all .5s;
padding: 0;
&:hover,
&:focus {
opacity: 0.75;
}
}
&.slick-active button {
background: #fff;
opacity: 1;
width: @carousel-dot-active-width;
&:hover,
&:focus {
opacity: 1;
}
}
}
}
}
.@{ant-prefix}-carousel-vertical {
.slick-dots {
width: @carousel-dot-height;
bottom: auto;
right: 12px;
top: 50%;
transform: translateY(-50%);
height: auto;
li {
margin: 0 2px;
vertical-align: baseline;
button {
width: @carousel-dot-height;
height: @carousel-dot-width;
}
&.slick-active button {
width: @carousel-dot-height;
height: @carousel-dot-active-width;
}
}
}
}

View File

@ -36,7 +36,7 @@ import { default as Card } from './card'
import { default as Collapse } from './collapse'
// import { default as Carousel } from './carousel'
import { default as Carousel } from './carousel'
import { default as Cascader } from './cascader'
@ -139,6 +139,7 @@ const components = [
Card.Grid,
Collapse,
Collapse.Panel,
Carousel,
Cascader,
Checkbox,
Checkbox.Group,
@ -241,6 +242,7 @@ export {
Calendar,
Card,
Collapse,
Carousel,
Cascader,
Checkbox,
Col,

View File

@ -18,6 +18,7 @@ import './dropdown/style'
import './divider/style'
import './card/style'
import './collapse/style'
import './carousel/style'
import './notification/style'
import './message/style'
import './spin/style'
@ -46,4 +47,5 @@ import './layout/style'
import './form/style'
import './anchor/style'
import './list/style'
import './carousel/style'
import './tree-select/style'

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

@ -0,0 +1,116 @@
h3 {
background: #00558B;
color: #fff;
font-size: 36px;
line-height: 100px;
margin: 10px;
padding: 2%;
position: relative;
text-align: center;
}
.variable-width .slick-slide p {
background: #00558B;
height: 100px;
color: #fff;
margin: 5px;
line-height: 100px;
text-align: center;
}
.center .slick-center h3 {
color: #e67e22;
opacity: 1;
transform: scale(1.08);
}
.center h3{
opacity: 0.8;
transition: all 300ms ease;
}
.content {
padding: 20px;
margin: auto;
}
@media (min-width: 701px) {
.content {
width: 80%;
}
}
@media (max-width: 700px) {
.content {
width: 70%;
}
}
.slick-slide .image {
padding: 10px;
}
.slick-slide img {
border: 5px solid #FFF;
display: block;
margin: auto;
max-width: 80%;
}
.slick-slide img.slick-loading {
border: 0
}
.slick-slider {
margin: 30px auto 50px;
}
.slick-dots {
margin-left: 0;
}
.slick-thumb {
bottom: -45px;
}
.slick-thumb li {
width: 60px;
height: 45px;
}
.slick-thumb li img {
width: 100%;
height: 100%;
filter: grayscale(100%);
}
.slick-thumb li.slick-active img{
filter: grayscale(0%);
}
@media (max-width: 768px) {
h3 {
font-size:24px;
}
.center {
margin-left: -40px;
margin-right: -40px;
}
.center .slick-center h3 {
color: #e67e22;
opacity: 1;
transform: scale(1);
}
.center h3 {
opacity: 0.8;
transform: scale(0.95);
transition: all 300ms ease;
}
}
.slick-vertical .slick-slide {
height: 180px;
}
.slick-arrow {
background-color: grey;
}
.slick-arrow:hover {
background-color: grey;
}
.slick-arrow:focus {
background-color: grey;
}
.button {
background-color: #00558B;
padding: 10px 20px;
margin: 0px 20px;
border: none;
color: white;
font-size: 20px;
border-radius: 5px;
min-height: 45px
}

Binary file not shown.

View File

@ -0,0 +1,14 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg">
<metadata>Generated by Fontastic.me</metadata>
<defs>
<font id="slick" horiz-adv-x="512">
<font-face font-family="slick" units-per-em="512" ascent="480" descent="-32"/>
<missing-glyph horiz-adv-x="512" />
<glyph unicode="&#8594;" d="M241 113l130 130c4 4 6 8 6 13 0 5-2 9-6 13l-130 130c-3 3-7 5-12 5-5 0-10-2-13-5l-29-30c-4-3-6-7-6-12 0-5 2-10 6-13l87-88-87-88c-4-3-6-8-6-13 0-5 2-9 6-12l29-30c3-3 8-5 13-5 5 0 9 2 12 5z m234 143c0-40-9-77-29-110-20-34-46-60-80-80-33-20-70-29-110-29-40 0-77 9-110 29-34 20-60 46-80 80-20 33-29 70-29 110 0 40 9 77 29 110 20 34 46 60 80 80 33 20 70 29 110 29 40 0 77-9 110-29 34-20 60-46 80-80 20-33 29-70 29-110z"/>
<glyph unicode="&#8592;" d="M296 113l29 30c4 3 6 7 6 12 0 5-2 10-6 13l-87 88 87 88c4 3 6 8 6 13 0 5-2 9-6 12l-29 30c-3 3-8 5-13 5-5 0-9-2-12-5l-130-130c-4-4-6-8-6-13 0-5 2-9 6-13l130-130c3-3 7-5 12-5 5 0 10 2 13 5z m179 143c0-40-9-77-29-110-20-34-46-60-80-80-33-20-70-29-110-29-40 0-77 9-110 29-34 20-60 46-80 80-20 33-29 70-29 110 0 40 9 77 29 110 20 34 46 60 80 80 33 20 70 29 110 29 40 0 77-9 110-29 34-20 60-46 80-80 20-33 29-70 29-110z"/>
<glyph unicode="&#8226;" d="M475 256c0-40-9-77-29-110-20-34-46-60-80-80-33-20-70-29-110-29-40 0-77 9-110 29-34 20-60 46-80 80-20 33-29 70-29 110 0 40 9 77 29 110 20 34 46 60 80 80 33 20 70 29 110 29 40 0 77-9 110-29 34-20 60-46 80-80 20-33 29-70 29-110z"/>
<glyph unicode="&#97;" d="M475 439l0-128c0-5-1-9-5-13-4-4-8-5-13-5l-128 0c-8 0-13 3-17 11-3 7-2 14 4 20l40 39c-28 26-62 39-100 39-20 0-39-4-57-11-18-8-33-18-46-32-14-13-24-28-32-46-7-18-11-37-11-57 0-20 4-39 11-57 8-18 18-33 32-46 13-14 28-24 46-32 18-7 37-11 57-11 23 0 44 5 64 15 20 9 38 23 51 42 2 1 4 3 7 3 3 0 5-1 7-3l39-39c2-2 3-3 3-6 0-2-1-4-2-6-21-25-46-45-76-59-29-14-60-20-93-20-30 0-58 5-85 17-27 12-51 27-70 47-20 19-35 43-47 70-12 27-17 55-17 85 0 30 5 58 17 85 12 27 27 51 47 70 19 20 43 35 70 47 27 12 55 17 85 17 28 0 55-5 81-15 26-11 50-26 70-45l37 37c6 6 12 7 20 4 8-4 11-9 11-17z"/>
</font></defs></svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

View File

@ -0,0 +1,3 @@
@import "./slick";
@import "./slick-theme";
@import "./docs";

View File

@ -0,0 +1,204 @@
@charset 'UTF-8';
/* Slider */
.slick-loading .slick-list
{
background: #fff url('./ajax-loader.gif') center center no-repeat;
}
/* Icons */
// @font-face
// {
// font-family: 'slick';
// font-weight: normal;
// font-style: normal;
// src: url('./fonts/slick.eot');
// src: url('./fonts/slick.eot?#iefix') format('embedded-opentype'), url('./fonts/slick.woff') format('woff'), url('./fonts/slick.ttf') format('truetype'), url('./fonts/slick.svg#slick') format('svg');
// }
/* Arrows */
.slick-prev,
.slick-next
{
font-size: 0;
line-height: 0;
position: absolute;
top: 50%;
display: block;
width: 20px;
height: 20px;
padding: 0;
-webkit-transform: translate(0, -50%);
-ms-transform: translate(0, -50%);
transform: translate(0, -50%);
cursor: pointer;
color: transparent;
border: none;
outline: none;
background: transparent;
}
.slick-prev:hover,
.slick-prev:focus,
.slick-next:hover,
.slick-next:focus
{
color: transparent;
outline: none;
background: transparent;
}
.slick-prev:hover:before,
.slick-prev:focus:before,
.slick-next:hover:before,
.slick-next:focus:before
{
opacity: 1;
}
.slick-prev.slick-disabled:before,
.slick-next.slick-disabled:before
{
opacity: .25;
}
.slick-prev:before,
.slick-next:before
{
// font-family: 'slick';
font-size: 20px;
line-height: 1;
opacity: .75;
color: white;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.slick-prev
{
left: -25px;
}
[dir='rtl'] .slick-prev
{
right: -25px;
left: auto;
}
.slick-prev:before
{
content: '←';
}
[dir='rtl'] .slick-prev:before
{
content: '→';
}
.slick-next
{
right: -25px;
}
[dir='rtl'] .slick-next
{
right: auto;
left: -25px;
}
.slick-next:before
{
content: '→';
}
[dir='rtl'] .slick-next:before
{
content: '←';
}
/* Dots */
.slick-dotted.slick-slider
{
margin-bottom: 30px;
}
.slick-dots
{
position: absolute;
bottom: -25px;
display: block;
width: 100%;
padding: 0;
margin: 0;
list-style: none;
text-align: center;
}
.slick-dots li
{
position: relative;
display: inline-block;
width: 20px;
height: 20px;
margin: 0 5px;
padding: 0;
cursor: pointer;
}
.slick-dots li button
{
font-size: 0;
line-height: 0;
display: block;
width: 20px;
height: 20px;
padding: 5px;
cursor: pointer;
color: transparent;
border: 0;
outline: none;
background: transparent;
}
.slick-dots li button:hover,
.slick-dots li button:focus
{
outline: none;
}
.slick-dots li button:hover:before,
.slick-dots li button:focus:before
{
opacity: 1;
}
.slick-dots li button:before
{
// font-family: 'slick';
font-size: 40px;
line-height: 20px;
position: absolute;
top: 0;
left: 0;
width: 20px;
height: 20px;
content: '•';
text-align: center;
opacity: .25;
color: black;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.slick-dots li.slick-active button:before
{
opacity: .75;
color: black;
}

View File

@ -0,0 +1,119 @@
/* Slider */
.slick-slider
{
position: relative;
display: block;
box-sizing: border-box;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
-webkit-touch-callout: none;
-khtml-user-select: none;
-ms-touch-action: pan-y;
touch-action: pan-y;
-webkit-tap-highlight-color: transparent;
}
.slick-list
{
position: relative;
display: block;
overflow: hidden;
margin: 0;
padding: 0;
}
.slick-list:focus
{
outline: none;
}
.slick-list.dragging
{
cursor: pointer;
cursor: hand;
}
.slick-slider .slick-track,
.slick-slider .slick-list
{
-webkit-transform: translate3d(0, 0, 0);
-moz-transform: translate3d(0, 0, 0);
-ms-transform: translate3d(0, 0, 0);
-o-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
.slick-track
{
position: relative;
top: 0;
left: 0;
display: block;
margin-left: auto;
margin-right: auto;
}
.slick-track:before,
.slick-track:after
{
display: table;
content: '';
}
.slick-track:after
{
clear: both;
}
.slick-loading .slick-track
{
visibility: hidden;
}
.slick-slide
{
display: none;
float: left;
height: 100%;
min-height: 1px;
}
[dir='rtl'] .slick-slide
{
float: right;
}
.slick-slide img
{
display: block;
}
.slick-slide.slick-loading img
{
display: none;
}
.slick-slide.dragging img
{
pointer-events: none;
}
.slick-initialized .slick-slide
{
display: block;
}
.slick-loading .slick-slide
{
visibility: hidden;
}
.slick-vertical .slick-slide
{
display: block;
height: auto;
border: 1px solid transparent;
}
.slick-arrow.slick-hidden {
display: none;
}

View File

@ -0,0 +1,45 @@
import '../assets/index.less'
import Slider from '../src/slider'
export default {
render () {
const settings = {
class: '',
props: {
dots: true,
infinite: true,
slidesToShow: 1,
slidesToScroll: 1,
adaptiveHeight: true,
},
}
return (
<div>
<h2>Adaptive height</h2>
<Slider {...settings}>
<div>
<h3>1</h3>
</div>
<div>
<h3>2</h3>
<p>Hello</p>
</div>
<div>
<h3>3</h3>
<p>See ....</p>
<p>Height is adaptive</p>
</div>
<div>
<h3>4</h3>
</div>
<div>
<h3>5</h3>
</div>
<div>
<h3>6</h3>
</div>
</Slider>
</div>
)
},
}

View File

@ -0,0 +1,69 @@
import '../assets/index.less'
import Slider from '../src/slider'
export default {
render (h) {
const settings = {
props: {
dots: true,
infinite: true,
speed: 500,
slidesToShow: 1,
slidesToScroll: 1,
},
scopedSlots: {
customPaging: ({ i }) => {
return (
<div
style={{
width: '30px',
color: 'blue',
border: '1px blue solid',
}}
>
{i + 1}
</div>
)
},
appendDots: ({ dots }) => {
return (
<div
style={{
backgroundColor: '#ddd',
borderRadius: '10px',
padding: '10px',
}}
>
<ul style={{ margin: '0px' }}> {dots} </ul>
</div>
)
},
},
}
return (
<div>
<h2>Append Dots</h2>
<Slider {...settings}>
<div>
<h3>1</h3>
</div>
<div>
<h3>2</h3>
</div>
<div>
<h3>3</h3>
</div>
<div>
<h3>4</h3>
</div>
<div>
<h3>5</h3>
</div>
<div>
<h3>6</h3>
</div>
</Slider>
</div>
)
},
}

View File

@ -0,0 +1,75 @@
import '../assets/index.less'
import Slider from '../src/slider'
export default {
data () {
return {
nav1: null,
nav2: null,
}
},
mounted () {
this.nav1 = this.$refs.slider1
this.nav2 = this.$refs.slider2
},
render () {
return (
<div>
<h2>Slider Syncing (AsNavFor)</h2>
<h4>First Slider</h4>
<Slider
asNavFor={this.nav2}
ref='slider1'
>
<div>
<h3>1</h3>
</div>
<div>
<h3>2</h3>
</div>
<div>
<h3>3</h3>
</div>
<div>
<h3>4</h3>
</div>
<div>
<h3>5</h3>
</div>
<div>
<h3>6</h3>
</div>
</Slider>
<h4>Second Slider</h4>
<Slider
asNavFor={this.nav1}
ref='slider2'
slidesToShow={3}
swipeToSlide={true}
focusOnSelect={true}
>
<div>
<h3>1</h3>
</div>
<div>
<h3>2</h3>
</div>
<div>
<h3>3</h3>
</div>
<div>
<h3>4</h3>
</div>
<div>
<h3>5</h3>
</div>
<div>
<h3>6</h3>
</div>
</Slider>
</div>
)
},
}

View File

@ -0,0 +1,44 @@
import '../assets/index.less'
import Slider from '../src/slider'
export default {
render () {
const settings = {
props: {
dots: true,
infinite: true,
slidesToShow: 3,
slidesToScroll: 1,
autoplay: true,
speed: 2000,
autoplaySpeed: 2000,
cssEase: 'linear',
},
}
return (
<div>
<h2>Auto Play</h2>
<Slider {...settings}>
<div>
<h3>1</h3>
</div>
<div>
<h3>2</h3>
</div>
<div>
<h3>3</h3>
</div>
<div>
<h3>4</h3>
</div>
<div>
<h3>5</h3>
</div>
<div>
<h3>6</h3>
</div>
</Slider>
</div>
)
},
}

View File

@ -0,0 +1,59 @@
import '../assets/index.less'
import Slider from '../src/slider'
export default {
methods: {
play () {
this.$refs.slider.slickPlay()
},
pause () {
this.$refs.slider.slickPause()
},
},
render () {
const settings = {
props: {
dots: true,
infinite: true,
slidesToShow: 3,
slidesToScroll: 1,
autoplay: true,
autoplaySpeed: 2000,
},
ref: 'slider',
}
return (
<div>
<h2>Auto Play & Pause with buttons</h2>
<Slider {...settings}>
<div>
<h3>1</h3>
</div>
<div>
<h3>2</h3>
</div>
<div>
<h3>3</h3>
</div>
<div>
<h3>4</h3>
</div>
<div>
<h3>5</h3>
</div>
<div>
<h3>6</h3>
</div>
</Slider>
<div style={{ textAlign: 'center' }}>
<button class='button' onClick={this.play}>
Play
</button>
<button class='button' onClick={this.pause}>
Pause
</button>
</div>
</div>
)
},
}

View File

@ -0,0 +1,42 @@
import '../assets/index.less'
import Slider from '../src/slider'
export default {
render () {
const settings = {
props: {
centerMode: true,
infinite: true,
centerPadding: '60px',
slidesToShow: 3,
speed: 500,
},
class: 'center',
}
return (
<div>
<h2>Center Mode</h2>
<Slider {...settings}>
<div>
<h3>1</h3>
</div>
<div>
<h3>2</h3>
</div>
<div>
<h3>3</h3>
</div>
<div>
<h3>4</h3>
</div>
<div>
<h3>5</h3>
</div>
<div>
<h3>6</h3>
</div>
</Slider>
</div>
)
},
}

View File

@ -0,0 +1,62 @@
import '../assets/index.less'
import Slider from '../src/slider'
export default {
render (h) {
const settings = {
props: {
dots: true,
infinite: true,
slidesToShow: 3,
slidesToScroll: 1,
},
scopedSlots: {
nextArrow: (props) => {
const { class: className, style, on: { click }} = props
return (
<div
class={className}
style={{ ...style, display: 'block', background: 'red' }}
onClick={click}
/>
)
},
prevArrow: (props) => {
const { class: className, style, on: { click }} = props
return (
<div
class={className}
style={{ ...style, display: 'block', background: 'green' }}
onClick={click}
/>
)
},
},
}
return (
<div>
<h2>Custom Arrows</h2>
<Slider {...settings}>
<div>
<h3>1</h3>
</div>
<div>
<h3>2</h3>
</div>
<div>
<h3>3</h3>
</div>
<div>
<h3>4</h3>
</div>
<div>
<h3>5</h3>
</div>
<div>
<h3>6</h3>
</div>
</Slider>
</div>
)
},
}

View File

@ -0,0 +1,50 @@
import '../assets/index.less'
import Slider from '../src/slider'
import imgList from './imglist'
const {
abstract01, abstract02, abstract03, abstract04,
} = imgList
export default {
render () {
const settings = {
props: {
dots: true,
dotsClass: 'slick-dots slick-thumb',
infinite: true,
speed: 500,
slidesToShow: 1,
slidesToScroll: 1,
},
scopedSlots: {
customPaging: ({ i }) => {
return (
<a>
<img src={imgList[`abstract0${i + 1}`]} />
</a>
)
},
},
}
return (
<div>
<h2>Custom Paging</h2>
<Slider {...settings}>
<div>
<img src={abstract01} />
</div>
<div>
<img src={abstract02} />
</div>
<div>
<img src={abstract03} />
</div>
<div>
<img src={abstract04} />
</div>
</Slider>
</div>
)
},
}

View File

@ -0,0 +1,40 @@
import '../assets/index.less'
import Slider from '../src/slider'
const CustomSlide = {
props: ['index'],
render () {
return (
<div>
<h3>{this.index}</h3>
</div>
)
},
}
export default {
render () {
const settings = {
props: {
dots: true,
infinite: true,
speed: 500,
slidesToShow: 1,
slidesToScroll: 1,
},
}
return (
<div>
<h2>Custom Slides</h2>
<Slider {...settings}>
<CustomSlide index={1} />
<CustomSlide index={2} />
<CustomSlide index={3} />
<CustomSlide index={4} />
<CustomSlide index={5} />
<CustomSlide index={6} />
</Slider>
</div>
)
},
}

View File

@ -0,0 +1,43 @@
import '../assets/index.less'
import Slider from '../src/slider'
export default {
data () {
return {
slides: [1, 2, 3, 4, 5, 6],
}
},
methods: {
click () {
this.slides = this.slides.length === 6 ? [1, 2, 3, 4, 5, 6, 7, 8, 9] : [1, 2, 3, 4, 5, 6]
},
},
render () {
const settings = {
props: {
dots: true,
infinite: true,
speed: 500,
slidesToShow: 3,
slidesToScroll: 3,
},
}
return (
<div>
<h2>Dynamic slides</h2>
<button class='button' onClick={this.click}>
Click to change slide count
</button>
<Slider {...settings}>
{this.slides.map(function (slide) {
return (
<div key={slide}>
<h3>{slide}</h3>
</div>
)
})}
</Slider>
</div>
)
},
}

View File

@ -0,0 +1,41 @@
import '../assets/index.less'
import Slider from '../src/slider'
import imgList from './imglist'
const {
abstract01, abstract02, abstract03, abstract04,
} = imgList
export default {
render () {
const settings = {
props: {
dots: true,
fade: true,
infinite: true,
speed: 500,
slidesToShow: 1,
slidesToScroll: 1,
},
}
return (
<div>
<h2>Fade</h2>
<Slider {...settings}>
<div>
<img src={abstract01} />
</div>
<div>
<img src={abstract02} />
</div>
<div>
<img src={abstract03} />
</div>
<div>
<img src={abstract04} />
</div>
</Slider>
</div>
)
},
}

View File

@ -0,0 +1,42 @@
import '../assets/index.less'
import Slider from '../src/slider'
export default {
render () {
const settings = {
props: {
focusOnSelect: true,
infinite: true,
slidesToShow: 3,
slidesToScroll: 1,
speed: 500,
},
}
return (
<div>
<h2>FocusOnSelect</h2>
<div>Click on any slide to select and make it current slide</div>
<Slider {...settings}>
<div>
<h3>1</h3>
</div>
<div>
<h3>2</h3>
</div>
<div>
<h3>3</h3>
</div>
<div>
<h3>4</h3>
</div>
<div>
<h3>5</h3>
</div>
<div>
<h3>6</h3>
</div>
</Slider>
</div>
)
},
}

View File

@ -0,0 +1,42 @@
import '../assets/index.less'
import Slider from '../src/slider'
import imgList from './imglist'
const {
abstract01, abstract02, abstract03, abstract04,
} = imgList
export default {
render () {
const settings = {
props: {
dots: true,
lazyLoad: true,
infinite: true,
speed: 500,
slidesToShow: 1,
slidesToScroll: 1,
initialSlide: 1,
},
}
return (
<div>
<h2> Lazy Load</h2>
<Slider {...settings}>
<div>
<img src={abstract01} />
</div>
<div>
<img src={abstract02} />
</div>
<div>
<img src={abstract03} />
</div>
<div>
<img src={abstract04} />
</div>
</Slider>
</div>
)
},
}

View File

@ -0,0 +1,50 @@
import '../assets/index.less'
import Slider from '../src/slider'
export default {
render () {
const settings = {
props: {
dots: true,
infinite: true,
speed: 500,
slidesToShow: 3,
slidesToScroll: 3,
},
}
return (
<div>
<h2> Multiple items </h2>
<Slider {...settings}>
<div>
<h3>1</h3>
</div>
<div>
<h3>2</h3>
</div>
<div>
<h3>3</h3>
</div>
<div>
<h3>4</h3>
</div>
<div>
<h3>5</h3>
</div>
<div>
<h3>6</h3>
</div>
<div>
<h3>7</h3>
</div>
<div>
<h3>8</h3>
</div>
<div>
<h3>9</h3>
</div>
</Slider>
</div>
)
},
}

View File

@ -0,0 +1,74 @@
import '../assets/index.less'
import Slider from '../src/slider'
export default {
render () {
const settings = {
props: {
centerMode: true,
infinite: true,
centerPadding: '60px',
slidesToShow: 3,
speed: 500,
rows: 2,
slidesPerRow: 2,
},
class: 'center',
}
return (
<div>
<h2>Multiple Rows</h2>
<Slider {...settings}>
<div style={{ width: '400px' }}>
<h3>1</h3>
</div>
<div>
<h3>2</h3>
</div>
<div>
<h3>3</h3>
</div>
<div>
<h3>4</h3>
</div>
<div>
<h3>5</h3>
</div>
<div>
<h3>6</h3>
</div>
<div>
<h3>7</h3>
</div>
<div>
<h3>8</h3>
</div>
<div>
<h3>9</h3>
</div>
<div>
<h3>10</h3>
</div>
<div>
<h3>11</h3>
</div>
<div>
<h3>12</h3>
</div>
<div>
<h3>13</h3>
</div>
<div>
<h3>14</h3>
</div>
<div>
<h3>15</h3>
</div>
<div>
<h3>16</h3>
</div>
</Slider>
</div>
)
},
}

View File

@ -0,0 +1,43 @@
import '../assets/index.less'
import Slider from '../src/slider'
export default {
render () {
const settings = {
props: {
dots: true,
infinite: true,
slidesToShow: 3,
slidesToScroll: 1,
autoplay: true,
autoplaySpeed: 2000,
pauseOnHover: true,
},
}
return (
<div>
<h2>Pause On Hover</h2>
<Slider {...settings}>
<div>
<h3>1</h3>
</div>
<div>
<h3>2</h3>
</div>
<div>
<h3>3</h3>
</div>
<div>
<h3>4</h3>
</div>
<div>
<h3>5</h3>
</div>
<div>
<h3>6</h3>
</div>
</Slider>
</div>
)
},
}

View File

@ -0,0 +1,58 @@
import '../assets/index.less'
import Slider from '../src/slider'
export default {
methods: {
next () {
this.$refs.slider.slickNext()
},
previous () {
this.$refs.slider.slickPrev()
},
},
render () {
const settings = {
props: {
dots: true,
infinite: true,
speed: 500,
slidesToShow: 1,
slidesToScroll: 1,
},
ref: 'slider',
}
return (
<div>
<h2>Previous and Next methods</h2>
<Slider {...settings}>
<div key={1}>
<h3>1</h3>
</div>
<div key={2}>
<h3>2</h3>
</div>
<div key={3}>
<h3>3</h3>
</div>
<div key={4}>
<h3>4</h3>
</div>
<div key={5}>
<h3>5</h3>
</div>
<div key={6}>
<h3>6</h3>
</div>
</Slider>
<div style={{ textAlign: 'center' }}>
<button class='button' onClick={this.previous}>
Previous
</button>
<button class='button' onClick={this.next}>
Next
</button>
</div>
</div>
)
},
}

View File

@ -0,0 +1,87 @@
import '../assets/index.less'
import Slider from '../src/slider'
export default {
data () {
return {
display: true,
width: 600,
}
},
render () {
const settings = {
props: {
dots: true,
infinite: true,
speed: 500,
slidesToShow: 3,
slidesToScroll: 1,
},
}
return (
<div>
<h2> Resizable Collapsible </h2>
<button
class='button'
onClick={
() => {
this.width = this.width + 100
}
}
>
{' '}
increase{' '}
</button>
<button
class='button'
onClick={
() => {
this.width = this.width - 100
}
}
>
{' '}
decrease{' '}
</button>
<button
class='button'
onClick={
() => {
this.display = !this.display
}
}
>
{' '}
toggle{' '}
</button>
<div
style={{
width: this.width + 'px',
display: this.display ? 'block' : 'none',
}}
>
<Slider {...settings}>
<div>
<h3>1</h3>
</div>
<div>
<h3>2</h3>
</div>
<div>
<h3>3</h3>
</div>
<div>
<h3>4</h3>
</div>
<div>
<h3>5</h3>
</div>
<div>
<h3>6</h3>
</div>
</Slider>
</div>
</div>
)
},
}

View File

@ -0,0 +1,74 @@
import '../assets/index.less'
import Slider from '../src/slider'
export default {
render () {
const settings = {
props: {
dots: true,
infinite: false,
speed: 500,
slidesToShow: 4,
slidesToScroll: 4,
initialSlide: 0,
responsive: [
{
breakpoint: 1024,
settings: {
slidesToShow: 3,
slidesToScroll: 3,
infinite: true,
dots: true,
},
},
{
breakpoint: 600,
settings: {
slidesToShow: 2,
slidesToScroll: 2,
initialSlide: 2,
},
},
{
breakpoint: 480,
settings: {
slidesToShow: 1,
slidesToScroll: 1,
},
},
],
},
}
return (
<div>
<h2> Responsive </h2>
<Slider {...settings}>
<div>
<h3>1</h3>
</div>
<div>
<h3>2</h3>
</div>
<div>
<h3>3</h3>
</div>
<div>
<h3>4</h3>
</div>
<div>
<h3>5</h3>
</div>
<div>
<h3>6</h3>
</div>
<div>
<h3>7</h3>
</div>
<div>
<h3>8</h3>
</div>
</Slider>
</div>
)
},
}

View File

@ -0,0 +1,43 @@
import '../assets/index.less'
import Slider from '../src/slider'
export default {
render () {
const settings = {
props: {
dots: true,
infinite: true,
slidesToShow: 3,
slidesToScroll: 1,
autoplay: true,
autoplaySpeed: 2000,
rtl: true,
},
}
return (
<div>
<h2>Right to Left</h2>
<Slider {...settings}>
<div>
<h3>1</h3>
</div>
<div>
<h3>2</h3>
</div>
<div>
<h3>3</h3>
</div>
<div>
<h3>4</h3>
</div>
<div>
<h3>5</h3>
</div>
<div>
<h3>6</h3>
</div>
</Slider>
</div>
)
},
}

View File

@ -0,0 +1,41 @@
import '../assets/index.less'
import Slider from '../src/slider'
export default {
render () {
const settings = {
props: {
dots: true,
infinite: true,
speed: 500,
slidesToShow: 1,
slidesToScroll: 1,
},
}
return (
<div style={{ width: '80%', margin: '0 auto' }}>
<h2> Single Item</h2>
<Slider {...settings}>
<div onClick={(e) => alert(e)}>
<h3>1</h3>
</div>
<div>
<h3>2</h3>
</div>
<div>
<h3>3</h3>
</div>
<div>
<h3>4</h3>
</div>
<div>
<h3>5</h3>
</div>
<div>
<h3>6</h3>
</div>
</Slider>
</div>
)
},
}

View File

@ -0,0 +1,58 @@
import '../assets/index.less'
import Slider from '../src/slider'
import imgList from './imglist'
const {
abstract01, abstract02, abstract03, abstract04,
} = imgList
export default {
data () {
return {
slideIndex: 0,
updateCount: 0,
}
},
render () {
const settings = {
props: {
dots: false,
infinite: true,
speed: 500,
slidesToShow: 1,
slidesToScroll: 1,
afterChange: () => { this.updateCount = this.updateCount + 1 },
beforeChange: (current, next) => { this.slideIndex = next },
},
ref: 'slider',
}
return (
<div>
<h2>Slick Go To</h2>
<p>Total updates: {this.updateCount} </p>
<input
onInput={e => this.$refs.slider.slickGoTo(e.target.value)}
value={this.slideIndex}
type='range'
min={0}
max={3}
/>
<Slider {...settings}>
<div>
<img src={abstract01} />
</div>
<div>
<img src={abstract02} />
</div>
<div>
<img src={abstract03} />
</div>
<div>
<img src={abstract04} />
</div>
</Slider>
</div>
)
},
}

View File

@ -0,0 +1,55 @@
import '../assets/index.less'
import Slider from '../src/slider'
export default {
data () {
return {
activeSlide: 0,
activeSlide2: 0,
}
},
render () {
const settings = {
props: {
dots: true,
infinite: true,
speed: 1000,
slidesToShow: 1,
slidesToScroll: 1,
beforeChange: (current, next) => { this.activeSlide = next },
afterChange: current => { this.activeSlide2 = current },
},
}
return (
<div>
<h2>beforeChange and afterChange hooks</h2>
<p>
BeforeChange => activeSlide: <strong>{this.activeSlide}</strong>
</p>
<p>
AfterChange => activeSlide: <strong>{this.activeSlide2}</strong>
</p>
<Slider {...settings}>
<div>
<h3>1</h3>
</div>
<div>
<h3>2</h3>
</div>
<div>
<h3>3</h3>
</div>
<div>
<h3>4</h3>
</div>
<div>
<h3>5</h3>
</div>
<div>
<h3>6</h3>
</div>
</Slider>
</div>
)
},
}

View File

@ -0,0 +1,55 @@
import '../assets/index.less'
import Slider from '../src/slider'
export default {
render () {
const settings = {
props: {
infinite: true,
centerPadding: '60px',
slidesToShow: 5,
swipeToSlide: true,
afterChange: function (index) {
console.log(
`Slider Changed to: ${index + 1}, background: #222; color: #bada55`
)
},
},
class: 'center',
}
return (
<div>
<h2>Swipe To Slide</h2>
<Slider {...settings}>
<div>
<h3>1</h3>
</div>
<div>
<h3>2</h3>
</div>
<div>
<h3>3</h3>
</div>
<div>
<h3>4</h3>
</div>
<div>
<h3>5</h3>
</div>
<div>
<h3>6</h3>
</div>
<div>
<h3>7</h3>
</div>
<div>
<h3>8</h3>
</div>
<div>
<h3>9</h3>
</div>
</Slider>
</div>
)
},
}

View File

@ -0,0 +1,41 @@
import '../assets/index.less'
import Slider from '../src/slider'
export default {
render () {
const settings = {
props: {
dots: true,
infinite: false,
speed: 500,
slidesToScroll: 4,
slidesToShow: 4,
},
}
return (
<div>
<h2>Uneven sets (finite)</h2>
<Slider {...settings}>
<div>
<h3>1</h3>
</div>
<div>
<h3>2</h3>
</div>
<div>
<h3>3</h3>
</div>
<div>
<h3>4</h3>
</div>
<div>
<h3>5</h3>
</div>
<div>
<h3>6</h3>
</div>
</Slider>
</div>
)
},
}

View File

@ -0,0 +1,41 @@
import '../assets/index.less'
import Slider from '../src/slider'
export default {
render () {
const settings = {
props: {
dots: true,
infinite: true,
speed: 500,
slidesToScroll: 4,
slidesToShow: 4,
},
}
return (
<div>
<h2>Uneven sets (infinite)</h2>
<Slider {...settings}>
<div>
<h3>1</h3>
</div>
<div>
<h3>2</h3>
</div>
<div>
<h3>3</h3>
</div>
<div>
<h3>4</h3>
</div>
<div>
<h3>5</h3>
</div>
<div>
<h3>6</h3>
</div>
</Slider>
</div>
)
},
}

View File

@ -0,0 +1,43 @@
import '../assets/index.less'
import Slider from '../src/slider'
export default {
render () {
const settings = {
class: 'slider variable-width',
props: {
dots: true,
infinite: true,
centerMode: true,
slidesToShow: 1,
slidesToScroll: 1,
variableWidth: true,
},
}
return (
<div>
<h2>Variable width</h2>
<Slider {...settings}>
<div style={{ width: '100px' }}>
<p>100</p>
</div>
<div style={{ width: '200px' }}>
<p>200</p>
</div>
<div style={{ width: '75px' }}>
<p>75</p>
</div>
<div style={{ width: '300px' }}>
<p>300</p>
</div>
<div style={{ width: '225px' }}>
<p>225</p>
</div>
<div style={{ width: '175px' }}>
<p>175</p>
</div>
</Slider>
</div>
)
},
}

View File

@ -0,0 +1,48 @@
import '../assets/index.less'
import Slider from '../src/slider'
export default {
render () {
const settings = {
props: {
dots: true,
infinite: true,
slidesToShow: 3,
slidesToScroll: 1,
vertical: true,
verticalSwiping: true,
beforeChange: function (currentSlide, nextSlide) {
console.log('before change', currentSlide, nextSlide)
},
afterChange: function (currentSlide) {
console.log('after change', currentSlide)
},
},
}
return (
<div>
<h2>Vertical Mode</h2>
<Slider {...settings}>
<div>
<h3>1</h3>
</div>
<div>
<h3>2</h3>
</div>
<div>
<h3>3</h3>
</div>
<div>
<h3>4</h3>
</div>
<div>
<h3>5</h3>
</div>
<div>
<h3>6</h3>
</div>
</Slider>
</div>
)
},
}

View File

@ -0,0 +1,49 @@
import '../assets/index.less'
import Slider from '../src/slider'
export default {
render () {
const settings = {
props: {
dots: true,
infinite: true,
slidesToShow: 3,
slidesToScroll: 1,
vertical: true,
verticalSwiping: true,
swipeToSlide: true,
beforeChange: function (currentSlide, nextSlide) {
console.log('before change', currentSlide, nextSlide)
},
afterChange: function (currentSlide) {
console.log('after change', currentSlide)
},
},
}
return (
<div>
<h2>Vertical Mode with Swipe To Slide</h2>
<Slider {...settings}>
<div>
<h3>1</h3>
</div>
<div>
<h3>2</h3>
</div>
<div>
<h3>3</h3>
</div>
<div>
<h3>4</h3>
</div>
<div>
<h3>5</h3>
</div>
<div>
<h3>6</h3>
</div>
</Slider>
</div>
)
},
}

View File

@ -0,0 +1,4 @@
export const baseUrl =
process.env.NODE_ENV === 'production'
? 'https://s3.amazonaws.com/static.neostack.com/img/react-slick'
: '/img/react-slick'

View File

@ -0,0 +1,11 @@
import abstract01 from '../assets/img/react-slick/abstract01.jpg'
import abstract02 from '../assets/img/react-slick/abstract02.jpg'
import abstract03 from '../assets/img/react-slick/abstract03.jpg'
import abstract04 from '../assets/img/react-slick/abstract04.jpg'
export default {
abstract01,
abstract02,
abstract03,
abstract04,
}

View File

@ -0,0 +1,67 @@
import SimpleSlider from './SimpleSlider'
import SlideChangeHooks from './SlideChangeHooks'
import MultipleItems from './MultipleItems'
import MultipleRows from './MultipleRows'
import Responsive from './Responsive'
import Resizable from './Resizable'
import UnevenSetsInfinite from './UnevenSetsInfinite'
import UnevenSetsFinite from './UnevenSetsFinite'
import CenterMode from './CenterMode'
import FocusOnSelect from './FocusOnSelect'
import AutoPlay from './AutoPlay'
import AutoPlayMethods from './AutoPlayMethods'
import PauseOnHover from './PauseOnHover'
import Rtl from './Rtl'
import VariableWidth from './VariableWidth'
import AdaptiveHeight from './AdaptiveHeight'
import LazyLoad from './LazyLoad'
import Fade from './Fade'
import SlickGoTo from './SlickGoTo'
import CustomArrows from './CustomArrows'
import PreviousNextMethods from './PreviousNextMethods'
import DynamicSlides from './DynamicSlides'
import VerticalMode from './VerticalMode'
import SwipeToSlide from './SwipeToSlide'
import VerticalSwipeToSlide from './VerticalSwipeToSlide'
import CustomPaging from './CustomPaging'
import CustomSlides from './CustomSlides'
import AsNavFor from './AsNavFor'
import AppendDots from './AppendDots'
export default {
render () {
return (
<div class='content'>
<SimpleSlider />
<MultipleItems />
<MultipleRows />
<Responsive />
<Resizable />
<UnevenSetsInfinite />
<UnevenSetsFinite />
<CenterMode />
<FocusOnSelect />
<AutoPlay />
<AutoPlayMethods />
<PauseOnHover />
<Rtl />
<VariableWidth />
<AdaptiveHeight />
<LazyLoad />
<Fade />
<SlideChangeHooks />
<SlickGoTo />
<CustomPaging />
<CustomArrows />
<CustomSlides />
<PreviousNextMethods />
<DynamicSlides />
<VerticalMode />
<SwipeToSlide />
<VerticalSwipeToSlide />
<AsNavFor />
<AppendDots />
</div>
)
},
}

View File

@ -0,0 +1,129 @@
import classnames from 'classnames'
import { cloneElement } from '../../_util/vnode'
import { canGoNext } from './utils/innerSliderUtils'
function noop () {}
export const PrevArrow = {
functional: true,
clickHandler (options, handle, e) {
if (e) {
e.preventDefault()
}
handle(options, e)
},
render (createElement, context) {
const { props } = context
const { clickHandler, infinite, currentSlide, slideCount, slidesToShow } = props
const prevClasses = { 'slick-arrow': true, 'slick-prev': true }
let prevHandler = function (e) {
if (e) {
e.preventDefault()
}
clickHandler({ message: 'previous' })
}
if (
!infinite && (currentSlide === 0 || slideCount <= slidesToShow)
) {
prevClasses['slick-disabled'] = true
prevHandler = noop
}
const prevArrowProps = {
key: '0',
domProps: {
'data-role': 'none',
},
class: classnames(prevClasses),
style: { display: 'block' },
on: {
click: prevHandler,
},
}
const customProps = {
currentSlide: currentSlide,
slideCount: slideCount,
}
let prevArrow
if (props.prevArrow) {
prevArrow = cloneElement(props.prevArrow({
...prevArrowProps,
...{
props: customProps,
},
}), {})
} else {
prevArrow = (
<button key='0' type='button' {...prevArrowProps}>
{' '}
Previous
</button>
)
}
return prevArrow
},
}
export const NextArrow = {
functional: true,
clickHandler (options, handle, e) {
if (e) {
e.preventDefault()
}
handle(options, e)
},
render (createElement, context) {
const { props } = context
const { clickHandler, currentSlide, slideCount } = props
const nextClasses = { 'slick-arrow': true, 'slick-next': true }
let nextHandler = function (e) {
if (e) {
e.preventDefault()
}
clickHandler({ message: 'next' })
}
if (!canGoNext(props)) {
nextClasses['slick-disabled'] = true
nextHandler = noop
}
const nextArrowProps = {
key: '1',
domProps: {
'data-role': 'none',
},
class: classnames(nextClasses),
style: { display: 'block' },
on: {
click: nextHandler,
},
}
const customProps = {
currentSlide: currentSlide,
slideCount: slideCount,
}
let nextArrow
if (props.nextArrow) {
nextArrow = cloneElement(props.nextArrow({
...nextArrowProps,
...{
props: customProps,
},
}), {})
} else {
nextArrow = (
<button key='1' type='button' {...nextArrowProps}>
{' '}
Next
</button>
)
}
return nextArrow
},
}

View File

@ -0,0 +1,69 @@
import PropTypes from '../../_util/vue-types'
const defaultProps = {
accessibility: PropTypes.bool.def(true),
// 自定义高度
adaptiveHeight: PropTypes.bool.def(false),
afterChange: PropTypes.any.def(null),
// appendDots: PropTypes.func.def((h, { dots }) => {
// return <ul style={{ display: 'block' }}>{dots}</ul>
// }),
arrows: PropTypes.bool.def(true),
autoplay: PropTypes.bool.def(false),
autoplaySpeed: PropTypes.number.def(3000),
beforeChange: PropTypes.any.def(null),
centerMode: PropTypes.bool.def(false),
centerPadding: PropTypes.string.def('50px'),
// className: '',
cssEase: PropTypes.string.def('ease'),
// customPaging: PropTypes.func.def((h, { i }) => {
// return <button>{i + 1}</button>
// }),
dots: PropTypes.bool.def(false),
dotsClass: PropTypes.string.def('slick-dots'),
draggable: PropTypes.bool.def(true),
unslick: PropTypes.bool.def(false),
easing: PropTypes.string.def('linear'),
edgeFriction: PropTypes.number.def(0.35),
fade: PropTypes.bool.def(false),
focusOnSelect: PropTypes.bool.def(false),
infinite: PropTypes.bool.def(true),
initialSlide: PropTypes.number.def(0),
lazyLoad: PropTypes.any.def(null),
// nextArrow: PropTypes.any.def(null),
verticalSwiping: PropTypes.bool.def(false),
asNavFor: PropTypes.any.def(null),
// onEdge: null,
// onInit: null,
// onLazyLoadError: null,
// onReInit: null,
// 圆点hover是否暂停
pauseOnDotsHover: PropTypes.bool.def(false),
// focus是否暂停
pauseOnFocus: PropTypes.bool.def(false),
// hover是否暂停
pauseOnHover: PropTypes.bool.def(true),
// prevArrow: PropTypes.any.def(null),
responsive: PropTypes.any.def(null),
rows: PropTypes.number.def(1),
rtl: PropTypes.bool.def(false),
slide: PropTypes.string.def('div'),
slidesPerRow: PropTypes.number.def(1),
slidesToScroll: PropTypes.number.def(1),
slidesToShow: PropTypes.number.def(1),
speed: PropTypes.number.def(500),
swipe: PropTypes.bool.def(true),
swipeEvent: PropTypes.any.def(null),
swipeToSlide: PropTypes.bool.def(false),
touchMove: PropTypes.bool.def(true),
touchThreshold: PropTypes.number.def(5),
useCSS: PropTypes.bool.def(true),
useTransform: PropTypes.bool.def(true),
variableWidth: PropTypes.bool.def(false),
vertical: PropTypes.bool.def(false),
waitForAnimate: PropTypes.bool.def(true),
children: PropTypes.array,
__propsSymbol__: PropTypes.any,
}
export default defaultProps

View File

@ -0,0 +1,84 @@
import classnames from 'classnames'
import { cloneElement } from '../../_util/vnode'
const getDotCount = function (spec) {
let dots
if (spec.infinite) {
dots = Math.ceil(spec.slideCount / spec.slidesToScroll)
} else {
dots =
Math.ceil((spec.slideCount - spec.slidesToShow) / spec.slidesToScroll) +
1
}
return dots
}
export default {
functional: true,
render (createElement, context) {
const { props, listeners } = context
const {
slideCount, slidesToScroll, slidesToShow,
infinite, currentSlide, appendDots,
customPaging, clickHandler, dotsClass,
} = props
const dotCount = getDotCount({
slideCount: slideCount,
slidesToScroll: slidesToScroll,
slidesToShow: slidesToShow,
infinite: infinite,
})
// Apply join & split to Array to pre-fill it for IE8
//
// Credit: http://stackoverflow.com/a/13735425/1849458
const { mouseenter, mouseover, mouseleave } = listeners
const mouseEvents = { mouseenter, mouseover, mouseleave }
const dots = Array.apply(
null,
Array(dotCount + 1)
.join('0')
.split('')
).map((x, i) => {
const leftBound = i * slidesToScroll
const rightBound =
i * slidesToScroll + (slidesToScroll - 1)
const className = classnames({
'slick-active':
currentSlide >= leftBound &&
currentSlide <= rightBound,
})
const dotOptions = {
message: 'dots',
index: i,
slidesToScroll: slidesToScroll,
currentSlide: currentSlide,
}
function onClick (e) {
// In Autoplay the focus stays on clicked button even after transition
// to next slide. That only goes away by click somewhere outside
if (e) {
e.preventDefault()
}
clickHandler(dotOptions)
}
return (
<li key={i} class={className}>
{cloneElement(customPaging({ i }), { on: {
click: onClick,
}})}
</li>
)
})
return cloneElement(appendDots({ dots }), {
class: dotsClass,
on: {
...mouseEvents,
},
})
},
}

View File

@ -0,0 +1,3 @@
import Slider from './slider'
export default Slider

View File

@ -0,0 +1,26 @@
const initialState = {
animating: false,
autoplaying: null,
currentDirection: 0,
currentLeft: null,
currentSlide: 0,
direction: 1,
dragging: false,
edgeDragged: false,
initialized: false,
lazyLoadedList: [],
listHeight: null,
listWidth: null,
scrolling: false,
slideCount: null,
slideHeight: null,
slideWidth: null,
swipeLeft: null,
swiped: false, // used by swipeEvent. differentites between touch and swipe.
swiping: false,
touchObject: { startX: 0, startY: 0, curX: 0, curY: 0 },
trackStyle: {},
trackWidth: 0,
}
export default initialState

View File

@ -0,0 +1,851 @@
import debounce from 'lodash/debounce'
import classnames from 'classnames'
import Vue from 'vue'
import antRefDirective from '../../_util/antRefDirective'
import { getStyle } from '../../_util/props-util'
import BaseMixin from '../../_util/BaseMixin'
import defaultProps from './default-props'
import initialState from './initial-state'
import {
getOnDemandLazySlides,
extractObject,
initializedState,
getHeight,
canGoNext,
slideHandler,
changeSlide,
keyHandler,
swipeStart,
swipeMove,
swipeEnd,
getPreClones,
getPostClones,
getTrackLeft,
getTrackCSS,
} from './utils/innerSliderUtils'
import Track from './track'
import Dots from './dots'
import { PrevArrow, NextArrow } from './arrows'
import ResizeObserver from 'resize-observer-polyfill'
Vue.use(antRefDirective)
function noop () {}
export default {
props: {
...defaultProps,
},
mixins: [BaseMixin],
data () {
this.preProps = { ...this.$props }
this.list = null
this.track = null
this.callbackTimers = []
this.clickable = true
this.debouncedResize = null
return {
...initialState,
currentSlide: this.initialSlide,
slideCount: this.children.length,
}
},
methods: {
listRefHandler (ref) {
this.list = ref && ref.elm
},
trackRefHandler (ref) {
this.track = ref && ref.elm
},
adaptHeight () {
if (this.adaptiveHeight && this.list) {
const elem = this.list.querySelector(
`[data-index="${this.currentSlide}"]`
)
this.list.style.height = getHeight(elem) + 'px'
}
},
onWindowResized (setTrackStyle) {
if (this.debouncedResize) this.debouncedResize.cancel()
this.debouncedResize = debounce(() => this.resizeWindow(setTrackStyle), 50)
this.debouncedResize()
},
resizeWindow (setTrackStyle = true) {
if (!this.track) return
const spec = {
listRef: this.list,
trackRef: this.track,
children: this.children,
...this.$props,
...this.$data,
}
this.updateState(spec, setTrackStyle, () => {
if (this.autoplay) {
this.handleAutoPlay('update')
} else {
this.pause('paused')
}
})
// animating state should be cleared while resizing, otherwise autoplay stops working
this.setState({
animating: false,
})
clearTimeout(this.animationEndCallback)
delete this.animationEndCallback
},
updateState (spec, setTrackStyle, callback) {
const updatedState = initializedState(spec)
spec = { ...spec, ...updatedState, slideIndex: updatedState.currentSlide }
const targetLeft = getTrackLeft(spec)
spec = { ...spec, left: targetLeft }
const trackStyle = getTrackCSS(spec)
if (
setTrackStyle ||
this.children.length !==
spec.children.length
) {
updatedState['trackStyle'] = trackStyle
}
this.setState(updatedState, callback)
},
ssrInit () {
const children = this.children
if (this.variableWidth) {
let trackWidth = 0
let trackLeft = 0
const childrenWidths = []
const preClones = getPreClones({
...this.$props,
...this.$data,
slideCount: children.length,
})
const postClones = getPostClones({
...this.$props,
...this.$data,
slideCount: children.length,
})
children.forEach(child => {
const childWidth = getStyle(child).width.split('px')[0]
childrenWidths.push(childWidth)
trackWidth += childWidth
})
for (let i = 0; i < preClones; i++) {
trackLeft += childrenWidths[childrenWidths.length - 1 - i]
trackWidth += childrenWidths[childrenWidths.length - 1 - i]
}
for (let i = 0; i < postClones; i++) {
trackWidth += childrenWidths[i]
}
for (let i = 0; i < this.currentSlide; i++) {
trackLeft += childrenWidths[i]
}
const trackStyle = {
width: trackWidth + 'px',
left: -trackLeft + 'px',
}
if (this.centerMode) {
const currentWidth = `${childrenWidths[this.currentSlide]}px`
trackStyle.left = `calc(${
trackStyle.left
} + (100% - ${currentWidth}) / 2 ) `
}
this.setState({
trackStyle,
})
return
}
const childrenCount = children.length
const spec = { ...this.$props, ...this.$data, slideCount: childrenCount }
const slideCount = getPreClones(spec) + getPostClones(spec) + childrenCount
const trackWidth = 100 / this.slidesToShow * slideCount
const slideWidth = 100 / slideCount
let trackLeft =
-slideWidth *
(getPreClones(spec) + this.currentSlide) *
trackWidth /
100
if (this.centerMode) {
trackLeft += (100 - slideWidth * trackWidth / 100) / 2
}
const trackStyle = {
width: trackWidth + '%',
left: trackLeft + '%',
}
this.setState({
slideWidth: slideWidth + '%',
trackStyle: trackStyle,
})
},
checkImagesLoad () {
const images = document.querySelectorAll('.slick-slide img')
const imagesCount = images.length
let loadedCount = 0
Array.prototype.forEach.call(images, image => {
const handler = () =>
++loadedCount && loadedCount >= imagesCount && this.onWindowResized()
if (!image.onclick) {
image.onclick = () => image.parentNode.focus()
} else {
const prevClickHandler = image.onclick
image.onclick = () => {
prevClickHandler()
image.parentNode.focus()
}
}
if (!image.onload) {
if (this.$props.lazyLoad) {
image.onload = () => {
this.adaptHeight()
this.callbackTimers.push(
setTimeout(this.onWindowResized, this.speed)
)
}
} else {
image.onload = handler
image.onerror = () => {
handler()
this.$emit('lazyLoadError')
}
}
}
})
},
progressiveLazyLoad () {
const slidesToLoad = []
const spec = { ...this.$props, ...this.$data }
for (
let index = this.currentSlide;
index < this.slideCount + getPostClones(spec);
index++
) {
if (this.lazyLoadedList.indexOf(index) < 0) {
slidesToLoad.push(index)
break
}
}
for (
let index = this.currentSlide - 1;
index >= -getPreClones(spec);
index--
) {
if (this.lazyLoadedList.indexOf(index) < 0) {
slidesToLoad.push(index)
break
}
}
if (slidesToLoad.length > 0) {
this.setState(state => ({
lazyLoadedList: state.lazyLoadedList.concat(slidesToLoad),
}))
this.$emit('lazyLoad', slidesToLoad)
} else {
if (this.lazyLoadTimer) {
clearInterval(this.lazyLoadTimer)
delete this.lazyLoadTimer
}
}
},
slideHandler (index, dontAnimate = false) {
const {
asNavFor,
currentSlide,
beforeChange,
speed,
afterChange,
} = this.$props
const { state, nextState } = slideHandler({
index,
...this.$props,
...this.$data,
trackRef: this.track,
useCSS: this.useCSS && !dontAnimate,
})
if (!state) return
beforeChange && beforeChange(currentSlide, state.currentSlide)
const slidesToLoad = state.lazyLoadedList.filter(
value => this.lazyLoadedList.indexOf(value) < 0
)
if (this.$listeners.lazyLoad && slidesToLoad.length > 0) {
this.$emit('lazyLoad', slidesToLoad)
}
this.setState(state, () => {
asNavFor &&
asNavFor.innerSlider.currentSlide !== currentSlide &&
asNavFor.innerSlider.slideHandler(index)
if (!nextState) return
this.animationEndCallback = setTimeout(() => {
const { animating, ...firstBatch } = nextState
this.setState(firstBatch, () => {
this.callbackTimers.push(
setTimeout(() => this.setState({ animating }), 10)
)
afterChange && afterChange(state.currentSlide)
delete this.animationEndCallback
})
}, speed)
})
},
changeSlide (options, dontAnimate = false) {
const spec = { ...this.$props, ...this.$data }
const targetSlide = changeSlide(spec, options)
if (targetSlide !== 0 && !targetSlide) return
if (dontAnimate === true) {
this.slideHandler(targetSlide, dontAnimate)
} else {
this.slideHandler(targetSlide)
}
},
clickHandler (e) {
if (this.clickable === false) {
e.stopPropagation()
e.preventDefault()
}
this.clickable = true
},
keyHandler (e) {
const dir = keyHandler(e, this.accessibility, this.rtl)
dir !== '' && this.changeSlide({ message: dir })
},
selectHandler (options) {
this.changeSlide(options)
},
disableBodyScroll () {
const preventDefault = e => {
e = e || window.event
if (e.preventDefault) e.preventDefault()
e.returnValue = false
}
window.ontouchmove = preventDefault
},
enableBodyScroll () {
window.ontouchmove = null
},
swipeStart (e) {
if (this.verticalSwiping) {
this.disableBodyScroll()
}
const state = swipeStart(e, this.swipe, this.draggable)
state !== '' && this.setState(state)
},
swipeMove (e) {
const state = swipeMove(e, {
...this.$props,
...this.$data,
trackRef: this.track,
listRef: this.list,
slideIndex: this.currentSlide,
})
if (!state) return
if (state['swiping']) {
this.clickable = false
}
this.setState(state)
},
swipeEnd (e) {
const state = swipeEnd(e, {
...this.$props,
...this.$data,
trackRef: this.track,
listRef: this.list,
slideIndex: this.currentSlide,
})
if (!state) return
const triggerSlideHandler = state['triggerSlideHandler']
delete state['triggerSlideHandler']
this.setState(state)
if (triggerSlideHandler === undefined) return
this.slideHandler(triggerSlideHandler)
if (this.$props.verticalSwiping) {
this.enableBodyScroll()
}
},
slickPrev () {
// this and fellow methods are wrapped in setTimeout
// to make sure initialize setState has happened before
// any of such methods are called
this.callbackTimers.push(
setTimeout(() => this.changeSlide({ message: 'previous' }), 0)
)
},
slickNext () {
this.callbackTimers.push(
setTimeout(() => this.changeSlide({ message: 'next' }), 0)
)
},
slickGoTo (slide, dontAnimate = false) {
slide = Number(slide)
if (isNaN(slide)) return ''
this.callbackTimers.push(
setTimeout(
() =>
this.changeSlide(
{
message: 'index',
index: slide,
currentSlide: this.currentSlide,
},
dontAnimate
),
0
)
)
},
play () {
let nextIndex
if (this.rtl) {
nextIndex = this.currentSlide - this.slidesToScroll
} else {
if (canGoNext({ ...this.$props, ...this.$data })) {
nextIndex = this.currentSlide + this.slidesToScroll
} else {
return false
}
}
this.slideHandler(nextIndex)
},
handleAutoPlay (playType) {
if (this.autoplayTimer) {
clearInterval(this.autoplayTimer)
}
const autoplaying = this.autoplaying
if (playType === 'update') {
if (
autoplaying === 'hovered' ||
autoplaying === 'focused' ||
autoplaying === 'paused'
) {
return
}
} else if (playType === 'leave') {
if (autoplaying === 'paused' || autoplaying === 'focused') {
return
}
} else if (playType === 'blur') {
if (autoplaying === 'paused' || autoplaying === 'hovered') {
return
}
}
this.autoplayTimer = setInterval(this.play, this.autoplaySpeed + 50)
this.setState({ autoplaying: 'playing' })
},
pause (pauseType) {
if (this.autoplayTimer) {
clearInterval(this.autoplayTimer)
this.autoplayTimer = null
}
const autoplaying = this.autoplaying
if (pauseType === 'paused') {
this.setState({ autoplaying: 'paused' })
} else if (pauseType === 'focused') {
if (autoplaying === 'hovered' || autoplaying === 'playing') {
this.setState({ autoplaying: 'focused' })
}
} else {
// pauseType is 'hovered'
if (autoplaying === 'playing') {
this.setState({ autoplaying: 'hovered' })
}
}
},
onDotsOver () {
this.autoplay && this.pause('hovered')
},
onDotsLeave () {
this.autoplay &&
this.autoplaying === 'hovered' &&
this.handleAutoPlay('leave')
},
onTrackOver () {
this.autoplay && this.pause('hovered')
},
onTrackLeave () {
this.autoplay &&
this.autoplaying === 'hovered' &&
this.handleAutoPlay('leave')
},
onSlideFocus () {
this.autoplay && this.pause('focused')
},
onSlideBlur () {
this.autoplay &&
this.autoplaying === 'focused' &&
this.handleAutoPlay('blur')
},
customPaging ({ i }) {
return <button>{i + 1}</button>
},
appendDots ({ dots }) {
return <ul style={{ display: 'block' }}>{dots}</ul>
},
},
beforeMount () {
this.ssrInit()
this.$emit('init')
if (this.lazyLoad) {
const slidesToLoad = getOnDemandLazySlides({
...this.$props,
...this.$data,
})
if (slidesToLoad.length > 0) {
this.setState(prevState => ({
lazyLoadedList: prevState.lazyLoadedList.concat(slidesToLoad),
}))
this.$emit('lazyLoad', slidesToLoad)
}
}
},
mounted () {
this.$nextTick(() => {
const spec = {
listRef: this.list,
trackRef: this.track,
children: this.children,
...this.$props,
}
this.updateState(spec, true, () => {
this.adaptHeight()
this.autoplay && this.handleAutoPlay('update')
})
if (this.lazyLoad === 'progressive') {
this.lazyLoadTimer = setInterval(this.progressiveLazyLoad, 1000)
}
this.ro = new ResizeObserver(() => {
if (this.animating) {
this.onWindowResized(false) // don't set trackStyle hence don't break animation
this.callbackTimers.push(
setTimeout(() => this.onWindowResized(), this.speed)
)
} else {
this.onWindowResized()
}
})
this.ro.observe(this.list)
Array.prototype.forEach.call(
document.querySelectorAll('.slick-slide'),
slide => {
slide.onfocus = this.$props.pauseOnFocus ? this.onSlideFocus : null
slide.onblur = this.$props.pauseOnFocus ? this.onSlideBlur : null
}
)
// To support server-side rendering
if (!window) {
return
}
if (window.addEventListener) {
window.addEventListener('resize', this.onWindowResized)
} else {
window.attachEvent('onresize', this.onWindowResized)
}
})
},
beforeDestroy () {
if (this.animationEndCallback) {
clearTimeout(this.animationEndCallback)
}
if (this.lazyLoadTimer) {
clearInterval(this.lazyLoadTimer)
}
if (this.callbackTimers.length) {
this.callbackTimers.forEach(timer => clearTimeout(timer))
this.callbackTimers = []
}
if (window.addEventListener) {
window.removeEventListener('resize', this.onWindowResized)
} else {
window.detachEvent('onresize', this.onWindowResized)
}
if (this.autoplayTimer) {
clearInterval(this.autoplayTimer)
}
},
updated () {
this.checkImagesLoad()
this.$emit('reInit')
if (this.lazyLoad) {
const slidesToLoad = getOnDemandLazySlides({
...this.$props,
...this.$data,
})
if (slidesToLoad.length > 0) {
this.setState(prevState => ({
lazyLoadedList: prevState.lazyLoadedList.concat(slidesToLoad),
}))
this.$emit('lazyLoad')
}
}
// if (this.props.onLazyLoad) {
// this.props.onLazyLoad([leftMostSlide])
// }
this.adaptHeight()
},
watch: {
__propsSymbol__ () {
const nextProps = this.$props
const spec = {
listRef: this.list,
trackRef: this.track,
...nextProps,
...this.$data,
}
let setTrackStyle = false
for (const key of Object.keys(this.preProps)) {
if (!nextProps.hasOwnProperty(key)) {
setTrackStyle = true
break
}
if (
typeof nextProps[key] === 'object' ||
typeof nextProps[key] === 'function' ||
typeof nextProps[key] === 'symbol'
) {
continue
}
if (nextProps[key] !== this.preProps[key]) {
setTrackStyle = true
break
}
}
this.updateState(spec, setTrackStyle, () => {
if (this.currentSlide >= nextProps.children.length) {
this.changeSlide({
message: 'index',
index: nextProps.children.length - nextProps.slidesToShow,
currentSlide: this.currentSlide,
})
}
if (nextProps.autoplay) {
this.handleAutoPlay('update')
} else {
this.pause('paused')
}
})
this.preProps = { ...nextProps }
},
// '$props': function (props) {
// const spec = {
// listRef: this.list,
// trackRef: this.track,
// children: this.$slots.default,
// ...props,
// ...this.$data,
// }
// let setTrackStyle = false
// for (const key of Object.keys(this.$props)) {
// if (!props.hasOwnProperty(key)) {
// setTrackStyle = true
// break
// }
// if (
// typeof props[key] === 'object' ||
// typeof props[key] === 'function'
// ) {
// continue
// }
// if (props[key] !== this.$props[key]) {
// setTrackStyle = true
// break
// }
// }
// this.updateState(spec, setTrackStyle, () => {
// const children = this.$slots.default
// if (this.currentSlide >= children.length) {
// this.changeSlide({
// message: 'index',
// index:
// children.length - props.slidesToShow,
// currentSlide: this.currentSlide,
// })
// }
// if (props.autoplay) {
// this.handleAutoPlay('update')
// } else {
// this.pause('paused')
// }
// })
// },
},
render () {
const className = classnames('slick-slider', {
'slick-vertical': this.vertical,
'slick-initialized': true,
})
const spec = { ...this.$props, ...this.$data }
let trackProps = extractObject(spec, [
'fade',
'cssEase',
'speed',
'infinite',
'centerMode',
'focusOnSelect',
'currentSlide',
'lazyLoad',
'lazyLoadedList',
'rtl',
'slideWidth',
'slideHeight',
'listHeight',
'vertical',
'slidesToShow',
'slidesToScroll',
'slideCount',
'trackStyle',
'variableWidth',
'unslick',
'centerPadding',
])
const { pauseOnHover } = this.$props
trackProps = {
props: {
...trackProps,
focusOnSelect: this.focusOnSelect ? this.selectHandler : null,
},
directives: [{
name: 'ant-ref',
value: this.trackRefHandler,
}],
on: {
mouseenter: pauseOnHover ? this.onTrackOver : noop,
mouseleave: pauseOnHover ? this.onTrackLeave : noop,
mouseover: pauseOnHover ? this.onTrackOver : noop,
},
}
let dots
if (
this.dots === true &&
this.slideCount >= this.slidesToShow
) {
let dotProps = extractObject(spec, [
'dotsClass',
'slideCount',
'slidesToShow',
'currentSlide',
'slidesToScroll',
'clickHandler',
'children',
'infinite',
'appendDots',
])
dotProps.customPaging = this.customPaging
dotProps.appendDots = this.appendDots
const { customPaging, appendDots } = this.$scopedSlots
if (customPaging) {
dotProps.customPaging = customPaging
}
if (appendDots) {
dotProps.appendDots = appendDots
}
const { pauseOnDotsHover } = this.$props
dotProps = {
props: {
...dotProps,
clickHandler: this.changeSlide,
},
on: {
mouseenter: pauseOnDotsHover ? this.onDotsLeave : noop,
mouseover: pauseOnDotsHover ? this.onDotsOver : noop,
mouseleave: pauseOnDotsHover ? this.onDotsLeave : noop,
},
}
dots = <Dots {...dotProps} />
}
let prevArrow, nextArrow
const arrowProps = extractObject(spec, [
'infinite',
'centerMode',
'currentSlide',
'slideCount',
'slidesToShow',
])
arrowProps.clickHandler = this.changeSlide
const { prevArrow: prevArrowCustom, nextArrow: nextArrowCustom } = this.$scopedSlots
if (prevArrowCustom) {
arrowProps.prevArrow = prevArrowCustom
}
if (nextArrowCustom) {
arrowProps.nextArrow = nextArrowCustom
}
if (this.arrows) {
prevArrow = <PrevArrow {...{ props: arrowProps }} />
nextArrow = <NextArrow {...{ props: arrowProps }} />
}
let verticalHeightStyle = null
if (this.vertical) {
verticalHeightStyle = {
height: typeof this.listHeight === 'number' ? `${this.listHeight}px` : this.listHeight,
}
}
let centerPaddingStyle = null
if (this.vertical === false) {
if (this.centerMode === true) {
centerPaddingStyle = {
padding: '0px ' + this.centerPadding,
}
}
} else {
if (this.centerMode === true) {
centerPaddingStyle = {
padding: this.centerPadding + ' 0px',
}
}
}
const listStyle = { ...verticalHeightStyle, ...centerPaddingStyle }
const touchMove = this.touchMove
let listProps = {
directives: [{
name: 'ant-ref',
value: this.listRefHandler,
}],
class: 'slick-list',
style: listStyle,
on: {
click: this.clickHandler,
mousedown: touchMove ? this.swipeStart : noop,
mousemove: this.dragging && touchMove ? this.swipeMove : noop,
mouseup: touchMove ? this.swipeEnd : noop,
mouseleave: this.dragging && touchMove ? this.swipeEnd : noop,
touchstart: touchMove ? this.swipeStart : noop,
touchmove: this.dragging && touchMove ? this.swipeMove : noop,
touchend: touchMove ? this.swipeEnd : noop,
touchcancel: this.dragging && touchMove ? this.swipeEnd : noop,
keydown: this.accessibility ? this.keyHandler : noop,
},
}
let innerSliderProps = {
class: className,
props: {
dir: 'ltr',
},
}
if (this.unslick) {
listProps = {
class: 'slick-list',
directives: [{
name: 'ant-ref',
value: this.listRefHandler,
}],
}
innerSliderProps = { class: className }
}
return (
<div {...innerSliderProps}>
{!this.unslick ? prevArrow : ''}
<div {...listProps}>
<Track {...trackProps}>
{this.children}
</Track>
</div>
{!this.unslick ? nextArrow : ''}
{!this.unslick ? dots : ''}
</div>
)
},
}

View File

@ -0,0 +1,241 @@
import json2mq from 'json2mq'
import Vue from 'vue'
import antRefDirective from '../../_util/antRefDirective'
import BaseMixin from '../../_util/BaseMixin'
import { cloneElement } from '../../_util/vnode'
import { getStyle } from '../../_util/props-util'
import InnerSlider from './inner-slider'
import defaultProps from './default-props'
import { canUseDOM } from './utils/innerSliderUtils'
const enquire = canUseDOM() && require('enquire.js')
Vue.use(antRefDirective)
export default {
props: {
...defaultProps,
},
mixins: [BaseMixin],
data () {
this._responsiveMediaHandlers = []
return {
breakpoint: null,
}
},
methods: {
innerSliderRefHandler (ref) {
this.innerSlider = ref && ref.componentInstance
},
media (query, handler) {
// javascript handler for css media query
enquire.register(query, handler)
this._responsiveMediaHandlers.push({ query, handler })
},
slickPrev () {
this.innerSlider.slickPrev()
},
slickNext () {
this.innerSlider.slickNext()
},
slickGoTo (slide, dontAnimate = false) {
this.innerSlider.slickGoTo(slide, dontAnimate)
},
slickPause () {
this.innerSlider.pause('paused')
},
slickPlay () {
this.innerSlider.handleAutoPlay('play')
},
},
// handles responsive breakpoints
beforeMount () {
// performance monitoring
// if (process.env.NODE_ENV !== 'production') {
// const { whyDidYouUpdate } = require('why-did-you-update')
// whyDidYouUpdate(React)
// }
if (this.responsive) {
const breakpoints = this.responsive.map(
breakpt => breakpt.breakpoint
)
// sort them in increasing order of their numerical value
breakpoints.sort((x, y) => x - y)
breakpoints.forEach((breakpoint, index) => {
// media query for each breakpoint
let bQuery
if (index === 0) {
bQuery = json2mq({ minWidth: 0, maxWidth: breakpoint })
} else {
bQuery = json2mq({
minWidth: breakpoints[index - 1] + 1,
maxWidth: breakpoint,
})
}
// when not using server side rendering
canUseDOM() &&
this.media(bQuery, () => {
this.setState({ breakpoint: breakpoint })
})
})
// Register media query for full screen. Need to support resize from small to large
// convert javascript object to media query string
const query = json2mq({ minWidth: breakpoints.slice(-1)[0] })
canUseDOM() &&
this.media(query, () => {
this.setState({ breakpoint: null })
})
}
},
beforeDestroy () {
this._responsiveMediaHandlers.forEach(function (obj) {
enquire.unregister(obj.query, obj.handler)
})
},
render () {
let settings
let newProps
if (this.breakpoint) {
newProps = this.responsive.filter(
resp => resp.breakpoint === this.breakpoint
)
settings =
newProps[0].settings === 'unslick'
? 'unslick'
: { ...this.$props, ...newProps[0].settings }
} else {
settings = { ...this.$props }
}
// force scrolling by one if centerMode is on
if (settings.centerMode) {
if (
settings.slidesToScroll > 1 &&
process.env.NODE_ENV !== 'production'
) {
console.warn(
`slidesToScroll should be equal to 1 in centerMode, you are using ${
settings.slidesToScroll
}`
)
}
settings.slidesToScroll = 1
}
// force showing one slide and scrolling by one if the fade mode is on
if (settings.fade) {
if (settings.slidesToShow > 1 && process.env.NODE_ENV !== 'production') {
console.warn(
`slidesToShow should be equal to 1 when fade is true, you're using ${
settings.slidesToShow
}`
)
}
if (
settings.slidesToScroll > 1 &&
process.env.NODE_ENV !== 'production'
) {
console.warn(
`slidesToScroll should be equal to 1 when fade is true, you're using ${
settings.slidesToScroll
}`
)
}
settings.slidesToShow = 1
settings.slidesToScroll = 1
}
// makes sure that children is an array, even when there is only 1 child
let children = this.$slots.default || []
// Children may contain false or null, so we should filter them
// children may also contain string filled with spaces (in certain cases where we use jsx strings)
children = children.filter(child => {
if (typeof child === 'string') {
return !!child.trim()
}
return !!child
})
// rows and slidesPerRow logic is handled here
if (
settings.variableWidth &&
(settings.rows > 1 || settings.slidesPerRow > 1)
) {
console.warn(
`variableWidth is not supported in case of rows > 1 or slidesPerRow > 1`
)
settings.variableWidth = false
}
const newChildren = []
let currentWidth = null
for (
let i = 0;
i < children.length;
i += settings.rows * settings.slidesPerRow
) {
const newSlide = []
for (
let j = i;
j < i + settings.rows * settings.slidesPerRow;
j += settings.slidesPerRow
) {
const row = []
for (let k = j; k < j + settings.slidesPerRow; k += 1) {
if (settings.variableWidth && getStyle(children[k])) {
currentWidth = getStyle(children[k]).width
}
if (k >= children.length) break
row.push(
cloneElement(children[k], {
key: 100 * i + 10 * j + k,
attrs: {
tabIndex: -1,
},
style: {
width: `${100 / settings.slidesPerRow}%`,
display: 'inline-block',
},
})
)
}
newSlide.push(<div key={10 * i + j}>{row}</div>)
}
if (settings.variableWidth) {
newChildren.push(
<div key={i} style={{ width: currentWidth }}>
{newSlide}
</div>
)
} else {
newChildren.push(<div key={i}>{newSlide}</div>)
}
}
if (settings === 'unslick') {
const className = 'regular slider ' + (this.className || '')
return <div class={className}>{newChildren}</div>
} else if (newChildren.length <= settings.slidesToShow) {
settings.unslick = true
}
const sliderProps = {
props: {
...settings,
children: newChildren,
__propsSymbol__: Symbol(),
},
on: {
...this.$listeners,
},
directives: [{
name: 'ant-ref',
value: this.innerSliderRefHandler,
}],
scopedSlots: this.$scopedSlots,
}
return (
<InnerSlider {...sliderProps} />
)
},
}

View File

@ -0,0 +1,232 @@
import classnames from 'classnames'
import { cloneElement } from '../../_util/vnode'
import { getStyle, getClass } from '../../_util/props-util'
import {
lazyStartIndex,
lazyEndIndex,
getPreClones,
} from './utils/innerSliderUtils'
// given specifications/props for a slide, fetch all the classes that need to be applied to the slide
const getSlideClasses = spec => {
let slickActive, slickCenter
let centerOffset, index
if (spec.rtl) {
index = spec.slideCount - 1 - spec.index
} else {
index = spec.index
}
const slickCloned = index < 0 || index >= spec.slideCount
if (spec.centerMode) {
centerOffset = Math.floor(spec.slidesToShow / 2)
slickCenter = (index - spec.currentSlide) % spec.slideCount === 0
if (
index > spec.currentSlide - centerOffset - 1 &&
index <= spec.currentSlide + centerOffset
) {
slickActive = true
}
} else {
slickActive =
spec.currentSlide <= index &&
index < spec.currentSlide + spec.slidesToShow
}
const slickCurrent = index === spec.currentSlide
return {
'slick-slide': true,
'slick-active': slickActive,
'slick-center': slickCenter,
'slick-cloned': slickCloned,
'slick-current': slickCurrent, // dubious in case of RTL
}
}
const getSlideStyle = function (spec) {
const style = {}
if (spec.variableWidth === undefined || spec.variableWidth === false) {
style.width = spec.slideWidth + (typeof spec.slideWidth === 'number' ? 'px' : '')
}
if (spec.fade) {
style.position = 'relative'
if (spec.vertical) {
style.top = -spec.index * parseInt(spec.slideHeight) + 'px'
} else {
style.left = -spec.index * parseInt(spec.slideWidth) + 'px'
}
style.opacity = spec.currentSlide === spec.index ? 1 : 0
style.transition =
'opacity ' +
spec.speed +
'ms ' +
spec.cssEase +
', ' +
'visibility ' +
spec.speed +
'ms ' +
spec.cssEase
style.WebkitTransition =
'opacity ' +
spec.speed +
'ms ' +
spec.cssEase +
', ' +
'visibility ' +
spec.speed +
'ms ' +
spec.cssEase
}
return style
}
const getKey = (child, fallbackKey) => child.key || (child.key === 0 && '0') || fallbackKey
const renderSlides = function (spec, children, createElement) {
let key
const slides = []
const preCloneSlides = []
const postCloneSlides = []
const childrenCount = children.length
const startIndex = lazyStartIndex(spec)
const endIndex = lazyEndIndex(spec)
children.forEach((elem, index) => {
let child
const childOnClickOptions = {
message: 'children',
index: index,
slidesToScroll: spec.slidesToScroll,
currentSlide: spec.currentSlide,
}
// in case of lazyLoad, whether or not we want to fetch the slide
if (
!spec.lazyLoad ||
(spec.lazyLoad && spec.lazyLoadedList.indexOf(index) >= 0)
) {
child = elem
} else {
child = createElement('div')
}
const childStyle = getSlideStyle({ ...spec, index })
const slideClass = getClass(child.context) || ''
let slideClasses = getSlideClasses({ ...spec, index })
// push a cloned element of the desired slide
slides.push(
cloneElement(child, {
key: 'original' + getKey(child, index),
attrs: {
tabIndex: '-1',
'data-index': index,
'aria-hidden': !slideClasses['slick-active'],
},
class: classnames(slideClasses, slideClass),
style: { outline: 'none', ...(getStyle(child.context) || {}), ...childStyle },
on: {
click: e => {
// child.props && child.props.onClick && child.props.onClick(e)
if (spec.focusOnSelect) {
spec.focusOnSelect(childOnClickOptions)
}
},
},
}, true)
)
// if slide needs to be precloned or postcloned
if (spec.infinite && spec.fade === false) {
const preCloneNo = childrenCount - index
if (
preCloneNo <= getPreClones(spec) &&
childrenCount !== spec.slidesToShow
) {
key = -preCloneNo
if (key >= startIndex) {
child = elem
}
slideClasses = getSlideClasses({ ...spec, index: key })
preCloneSlides.push(
cloneElement(child, {
key: 'precloned' + getKey(child, key),
class: classnames(slideClasses, slideClass),
attrs: {
tabIndex: '-1',
'data-index': key,
'aria-hidden': !slideClasses['slick-active'],
},
style: { ...(getStyle(child.context) || {}), ...childStyle },
on: {
click: e => {
// child.props && child.props.onClick && child.props.onClick(e)
if (spec.focusOnSelect) {
spec.focusOnSelect(childOnClickOptions)
}
},
},
})
)
}
if (childrenCount !== spec.slidesToShow) {
key = childrenCount + index
if (key < endIndex) {
child = elem
}
slideClasses = getSlideClasses({ ...spec, index: key })
postCloneSlides.push(
cloneElement(child, {
key: 'postcloned' + getKey(child, key),
attrs: {
tabIndex: '-1',
'data-index': key,
'aria-hidden': !slideClasses['slick-active'],
},
class: classnames(slideClasses, slideClass),
style: { ...(getStyle(child.context) || {}), ...childStyle },
on: {
click: e => {
// child.props && child.props.onClick && child.props.onClick(e)
if (spec.focusOnSelect) {
spec.focusOnSelect(childOnClickOptions)
}
},
},
})
)
}
}
})
if (spec.rtl) {
return preCloneSlides.concat(slides, postCloneSlides).reverse()
} else {
return preCloneSlides.concat(slides, postCloneSlides)
}
}
export default {
functional: true,
render (createElement, context) {
const { props, listeners, children, data } = context
const slides = renderSlides(props, children, createElement)
const { mouseenter, mouseover, mouseleave } = listeners
const mouseEvents = { mouseenter, mouseover, mouseleave }
const trackProps = {
class: 'slick-track',
style: props.trackStyle,
on: {
...mouseEvents,
},
directives: data.directives,
}
return (
<div
{...trackProps}
>
{slides}
</div>
)
},
}

View File

@ -0,0 +1,819 @@
export const getOnDemandLazySlides = spec => {
const onDemandSlides = []
const startIndex = lazyStartIndex(spec)
const endIndex = lazyEndIndex(spec)
for (let slideIndex = startIndex; slideIndex < endIndex; slideIndex++) {
if (spec.lazyLoadedList.indexOf(slideIndex) < 0) {
onDemandSlides.push(slideIndex)
}
}
return onDemandSlides
}
// return list of slides that need to be present
export const getRequiredLazySlides = spec => {
const requiredSlides = []
const startIndex = lazyStartIndex(spec)
const endIndex = lazyEndIndex(spec)
for (let slideIndex = startIndex; slideIndex < endIndex; slideIndex++) {
requiredSlides.push(slideIndex)
}
return requiredSlides
}
// startIndex that needs to be present
export const lazyStartIndex = spec =>
spec.currentSlide - lazySlidesOnLeft(spec)
export const lazyEndIndex = spec => spec.currentSlide + lazySlidesOnRight(spec)
export const lazySlidesOnLeft = spec =>
spec.centerMode
? Math.floor(spec.slidesToShow / 2) +
(parseInt(spec.centerPadding) > 0 ? 1 : 0)
: 0
export const lazySlidesOnRight = spec =>
spec.centerMode
? Math.floor((spec.slidesToShow - 1) / 2) +
1 +
(parseInt(spec.centerPadding) > 0 ? 1 : 0)
: spec.slidesToShow
// get width of an element
export const getWidth = elem => (elem && elem.offsetWidth) || 0
export const getHeight = elem => (elem && elem.offsetHeight) || 0
export const getSwipeDirection = (touchObject, verticalSwiping = false) => {
let swipeAngle
const xDist = touchObject.startX - touchObject.curX
const yDist = touchObject.startY - touchObject.curY
const r = Math.atan2(yDist, xDist)
swipeAngle = Math.round(r * 180 / Math.PI)
if (swipeAngle < 0) {
swipeAngle = 360 - Math.abs(swipeAngle)
}
if (
(swipeAngle <= 45 && swipeAngle >= 0) ||
(swipeAngle <= 360 && swipeAngle >= 315)
) {
return 'left'
}
if (swipeAngle >= 135 && swipeAngle <= 225) {
return 'right'
}
if (verticalSwiping === true) {
if (swipeAngle >= 35 && swipeAngle <= 135) {
return 'up'
} else {
return 'down'
}
}
return 'vertical'
}
// whether or not we can go next
export const canGoNext = spec => {
let canGo = true
if (!spec.infinite) {
if (spec.centerMode && spec.currentSlide >= spec.slideCount - 1) {
canGo = false
} else if (
spec.slideCount <= spec.slidesToShow ||
spec.currentSlide >= spec.slideCount - spec.slidesToShow
) {
canGo = false
}
}
return canGo
}
// given an object and a list of keys, return new object with given keys
export const extractObject = (spec, keys) => {
const newObject = {}
keys.forEach(key => (newObject[key] = spec[key]))
return newObject
}
// get initialized state
export const initializedState = spec => {
// spec also contains listRef, trackRef
const slideCount = spec.children.length
const listWidth = Math.ceil(getWidth(spec.listRef))
const trackWidth = Math.ceil(getWidth(spec.trackRef))
let slideWidth
if (!spec.vertical) {
let centerPaddingAdj = spec.centerMode && parseInt(spec.centerPadding) * 2
if (
typeof spec.centerPadding === 'string' &&
spec.centerPadding.slice(-1) === '%'
) {
centerPaddingAdj *= listWidth / 100
}
slideWidth = Math.ceil((listWidth - centerPaddingAdj) / spec.slidesToShow)
} else {
slideWidth = listWidth
}
const slideHeight =
spec.listRef &&
getHeight(
spec.listRef.querySelector('[data-index="0"]')
)
const listHeight = slideHeight * spec.slidesToShow
let currentSlide =
spec.currentSlide === undefined ? spec.initialSlide : spec.currentSlide
if (spec.rtl && spec.currentSlide === undefined) {
currentSlide = slideCount - 1 - spec.initialSlide
}
const lazyLoadedList = spec.lazyLoadedList || []
const slidesToLoad = getOnDemandLazySlides(
{ currentSlide, lazyLoadedList },
spec
)
lazyLoadedList.concat(slidesToLoad)
const state = {
slideCount,
slideWidth,
listWidth,
trackWidth,
currentSlide,
slideHeight,
listHeight,
lazyLoadedList,
}
if (spec.autoplaying === null && spec.autoplay) {
state['autoplaying'] = 'playing'
}
return state
}
export const slideHandler = spec => {
const {
waitForAnimate,
animating,
fade,
infinite,
index,
slideCount,
lazyLoadedList,
lazyLoad,
currentSlide,
centerMode,
slidesToScroll,
slidesToShow,
useCSS,
} = spec
if (waitForAnimate && animating) return {}
let animationSlide = index
let finalSlide
let animationLeft
let finalLeft
let state = {}
let nextState = {}
if (fade) {
if (!infinite && (index < 0 || index >= slideCount)) return {}
if (index < 0) {
animationSlide = index + slideCount
} else if (index >= slideCount) {
animationSlide = index - slideCount
}
if (lazyLoad && lazyLoadedList.indexOf(animationSlide) < 0) {
lazyLoadedList.push(animationSlide)
}
state = {
animating: true,
currentSlide: animationSlide,
lazyLoadedList,
}
nextState = { animating: false }
} else {
finalSlide = animationSlide
if (animationSlide < 0) {
finalSlide = animationSlide + slideCount
if (!infinite) finalSlide = 0
else if (slideCount % slidesToScroll !== 0) { finalSlide = slideCount - slideCount % slidesToScroll }
} else if (!canGoNext(spec) && animationSlide > currentSlide) {
animationSlide = finalSlide = currentSlide
} else if (centerMode && animationSlide >= slideCount) {
animationSlide = infinite ? slideCount : slideCount - 1
finalSlide = infinite ? 0 : slideCount - 1
} else if (animationSlide >= slideCount) {
finalSlide = animationSlide - slideCount
if (!infinite) finalSlide = slideCount - slidesToShow
else if (slideCount % slidesToScroll !== 0) finalSlide = 0
}
animationLeft = getTrackLeft({ ...spec, slideIndex: animationSlide })
finalLeft = getTrackLeft({ ...spec, slideIndex: finalSlide })
if (!infinite) {
if (animationLeft === finalLeft) animationSlide = finalSlide
animationLeft = finalLeft
}
lazyLoad &&
lazyLoadedList.concat(
getOnDemandLazySlides({ ...spec, currentSlide: animationSlide })
)
if (!useCSS) {
state = {
currentSlide: finalSlide,
trackStyle: getTrackCSS({ ...spec, left: finalLeft }),
lazyLoadedList,
}
} else {
state = {
animating: true,
currentSlide: finalSlide,
trackStyle: getTrackAnimateCSS({ ...spec, left: animationLeft }),
lazyLoadedList,
}
nextState = {
animating: false,
currentSlide: finalSlide,
trackStyle: getTrackCSS({ ...spec, left: finalLeft }),
swipeLeft: null,
}
}
}
return { state, nextState }
}
export const changeSlide = (spec, options) => {
let previousInt, slideOffset, targetSlide
const {
slidesToScroll,
slidesToShow,
slideCount,
currentSlide,
lazyLoad,
infinite,
} = spec
const unevenOffset = slideCount % slidesToScroll !== 0
const indexOffset = unevenOffset ? 0 : (slideCount - currentSlide) % slidesToScroll
if (options.message === 'previous') {
slideOffset = indexOffset === 0 ? slidesToScroll : slidesToShow - indexOffset
targetSlide = currentSlide - slideOffset
if (lazyLoad && !infinite) {
previousInt = currentSlide - slideOffset
targetSlide = previousInt === -1 ? slideCount - 1 : previousInt
}
} else if (options.message === 'next') {
slideOffset = indexOffset === 0 ? slidesToScroll : indexOffset
targetSlide = currentSlide + slideOffset
if (lazyLoad && !infinite) {
targetSlide = (currentSlide + slidesToScroll) % slideCount + indexOffset
}
} else if (options.message === 'dots') {
// Click on dots
targetSlide = options.index * options.slidesToScroll
if (targetSlide === options.currentSlide) {
return null
}
} else if (options.message === 'children') {
// Click on the slides
targetSlide = options.index
if (targetSlide === options.currentSlide) {
return null
}
if (infinite) {
const direction = siblingDirection({ ...spec, targetSlide })
if (targetSlide > options.currentSlide && direction === 'left') {
targetSlide = targetSlide - slideCount
} else if (targetSlide < options.currentSlide && direction === 'right') {
targetSlide = targetSlide + slideCount
}
}
} else if (options.message === 'index') {
targetSlide = Number(options.index)
if (targetSlide === options.currentSlide) {
return null
}
}
return targetSlide
}
export const keyHandler = (e, accessibility, rtl) => {
if (e.target.tagName.match('TEXTAREA|INPUT|SELECT') || !accessibility) { return '' }
if (e.keyCode === 37) return rtl ? 'next' : 'previous'
if (e.keyCode === 39) return rtl ? 'previous' : 'next'
return ''
}
export const swipeStart = (e, swipe, draggable) => {
e.target.tagName === 'IMG' && e.preventDefault()
if (!swipe || (!draggable && e.type.indexOf('mouse') !== -1)) return ''
return {
dragging: true,
touchObject: {
startX: e.touches ? e.touches[0].pageX : e.clientX,
startY: e.touches ? e.touches[0].pageY : e.clientY,
curX: e.touches ? e.touches[0].pageX : e.clientX,
curY: e.touches ? e.touches[0].pageY : e.clientY,
},
}
}
export const swipeMove = (e, spec) => {
// spec also contains, trackRef and slideIndex
const {
scrolling,
animating,
vertical,
swipeToSlide,
verticalSwiping,
rtl,
currentSlide,
edgeFriction,
edgeDragged,
onEdge,
swiped,
swiping,
slideCount,
slidesToScroll,
infinite,
touchObject,
swipeEvent,
listHeight,
listWidth,
} = spec
if (scrolling) return
if (animating) return e.preventDefault()
if (vertical && swipeToSlide && verticalSwiping) e.preventDefault()
let swipeLeft
let state = {}
const curLeft = getTrackLeft(spec)
touchObject.curX = e.touches ? e.touches[0].pageX : e.clientX
touchObject.curY = e.touches ? e.touches[0].pageY : e.clientY
touchObject.swipeLength = Math.round(
Math.sqrt(Math.pow(touchObject.curX - touchObject.startX, 2))
)
const verticalSwipeLength = Math.round(
Math.sqrt(Math.pow(touchObject.curY - touchObject.startY, 2))
)
if (!verticalSwiping && !swiping && verticalSwipeLength > 10) {
return { scrolling: true }
}
if (verticalSwiping) touchObject.swipeLength = verticalSwipeLength
let positionOffset =
(!rtl ? 1 : -1) * (touchObject.curX > touchObject.startX ? 1 : -1)
if (verticalSwiping) { positionOffset = touchObject.curY > touchObject.startY ? 1 : -1 }
const dotCount = Math.ceil(slideCount / slidesToScroll)
const swipeDirection = getSwipeDirection(spec.touchObject, verticalSwiping)
let touchSwipeLength = touchObject.swipeLength
if (!infinite) {
if (
(currentSlide === 0 && swipeDirection === 'right') ||
(currentSlide + 1 >= dotCount && swipeDirection === 'left') ||
(!canGoNext(spec) && swipeDirection === 'left')
) {
touchSwipeLength = touchObject.swipeLength * edgeFriction
if (edgeDragged === false && onEdge) {
onEdge(swipeDirection)
state['edgeDragged'] = true
}
}
}
if (!swiped && swipeEvent) {
swipeEvent(swipeDirection)
state['swiped'] = true
}
if (!vertical) {
if (!rtl) {
swipeLeft = curLeft + touchSwipeLength * positionOffset
} else {
swipeLeft = curLeft - touchSwipeLength * positionOffset
}
} else {
swipeLeft =
curLeft + touchSwipeLength * (listHeight / listWidth) * positionOffset
}
if (verticalSwiping) {
swipeLeft = curLeft + touchSwipeLength * positionOffset
}
state = {
...state,
touchObject,
swipeLeft,
trackStyle: getTrackCSS({ ...spec, left: swipeLeft }),
}
if (
Math.abs(touchObject.curX - touchObject.startX) <
Math.abs(touchObject.curY - touchObject.startY) * 0.8
) {
return state
}
if (touchObject.swipeLength > 10) {
state['swiping'] = true
e.preventDefault()
}
return state
}
export const swipeEnd = (e, spec) => {
const {
dragging,
swipe,
touchObject,
listWidth,
touchThreshold,
verticalSwiping,
listHeight,
currentSlide,
swipeToSlide,
scrolling,
onSwipe,
} = spec
if (!dragging) {
if (swipe) e.preventDefault()
return {}
}
const minSwipe = verticalSwiping
? listHeight / touchThreshold
: listWidth / touchThreshold
const swipeDirection = getSwipeDirection(touchObject, verticalSwiping)
// reset the state of touch related state variables.
const state = {
dragging: false,
edgeDragged: false,
scrolling: false,
swiping: false,
swiped: false,
swipeLeft: null,
touchObject: {},
}
if (scrolling) {
return state
}
if (!touchObject.swipeLength) {
return state
}
if (touchObject.swipeLength > minSwipe) {
e.preventDefault()
if (onSwipe) {
onSwipe(swipeDirection)
}
let slideCount, newSlide
switch (swipeDirection) {
case 'left':
case 'up':
newSlide = currentSlide + getSlideCount(spec)
slideCount = swipeToSlide ? checkNavigable(spec, newSlide) : newSlide
state['currentDirection'] = 0
break
case 'right':
case 'down':
newSlide = currentSlide - getSlideCount(spec)
slideCount = swipeToSlide ? checkNavigable(spec, newSlide) : newSlide
state['currentDirection'] = 1
break
default:
slideCount = currentSlide
}
state['triggerSlideHandler'] = slideCount
} else {
// Adjust the track back to it's original position.
const currentLeft = getTrackLeft(spec)
state['trackStyle'] = getTrackAnimateCSS({ ...spec, left: currentLeft })
}
return state
}
export const getNavigableIndexes = spec => {
const max = spec.infinite ? spec.slideCount * 2 : spec.slideCount
let breakpoint = spec.infinite ? spec.slidesToShow * -1 : 0
let counter = spec.infinite ? spec.slidesToShow * -1 : 0
const indexes = []
while (breakpoint < max) {
indexes.push(breakpoint)
breakpoint = counter + spec.slidesToScroll
counter += Math.min(spec.slidesToScroll, spec.slidesToShow)
}
return indexes
}
export const checkNavigable = (spec, index) => {
const navigables = getNavigableIndexes(spec)
let prevNavigable = 0
if (index > navigables[navigables.length - 1]) {
index = navigables[navigables.length - 1]
} else {
for (const n in navigables) {
if (index < navigables[n]) {
index = prevNavigable
break
}
prevNavigable = navigables[n]
}
}
return index
}
export const getSlideCount = spec => {
const centerOffset = spec.centerMode
? spec.slideWidth * Math.floor(spec.slidesToShow / 2)
: 0
if (spec.swipeToSlide) {
let swipedSlide
const slickList = spec.listRef
const slides = slickList.querySelectorAll('.slick-slide')
Array.from(slides).every(slide => {
if (!spec.vertical) {
if (
slide.offsetLeft - centerOffset + getWidth(slide) / 2 >
spec.swipeLeft * -1
) {
swipedSlide = slide
return false
}
} else {
if (slide.offsetTop + getHeight(slide) / 2 > spec.swipeLeft * -1) {
swipedSlide = slide
return false
}
}
return true
})
if (!swipedSlide) {
return 0
}
const currentIndex =
spec.rtl === true
? spec.slideCount - spec.currentSlide
: spec.currentSlide
const slidesTraversed =
Math.abs(swipedSlide.dataset.index - currentIndex) || 1
return slidesTraversed
} else {
return spec.slidesToScroll
}
}
export const checkSpecKeys = (spec, keysArray) =>
keysArray.reduce((value, key) => value && spec.hasOwnProperty(key), true)
? null
: console.error('Keys Missing:', spec)
export const getTrackCSS = spec => {
checkSpecKeys(spec, [
'left',
'variableWidth',
'slideCount',
'slidesToShow',
'slideWidth',
])
let trackWidth, trackHeight
const trackChildren = spec.slideCount + 2 * spec.slidesToShow
if (!spec.vertical) {
trackWidth = getTotalSlides(spec) * spec.slideWidth
} else {
trackHeight = trackChildren * spec.slideHeight
}
let style = {
opacity: 1,
transition: '',
WebkitTransition: '',
}
if (spec.useTransform) {
const WebkitTransform = !spec.vertical
? 'translate3d(' + spec.left + 'px, 0px, 0px)'
: 'translate3d(0px, ' + spec.left + 'px, 0px)'
const transform = !spec.vertical
? 'translate3d(' + spec.left + 'px, 0px, 0px)'
: 'translate3d(0px, ' + spec.left + 'px, 0px)'
const msTransform = !spec.vertical
? 'translateX(' + spec.left + 'px)'
: 'translateY(' + spec.left + 'px)'
style = {
...style,
WebkitTransform,
transform,
msTransform,
}
} else {
if (spec.vertical) {
style['top'] = spec.left
} else {
style['left'] = spec.left
}
}
if (spec.fade) style = { opacity: 1 }
if (trackWidth) style.width = trackWidth + 'px'
if (trackHeight) style.height = trackHeight + 'px'
// Fallback for IE8
if (window && !window.addEventListener && window.attachEvent) {
if (!spec.vertical) {
style.marginLeft = spec.left + 'px'
} else {
style.marginTop = spec.left + 'px'
}
}
return style
}
export const getTrackAnimateCSS = spec => {
checkSpecKeys(spec, [
'left',
'variableWidth',
'slideCount',
'slidesToShow',
'slideWidth',
'speed',
'cssEase',
])
const style = getTrackCSS(spec)
// useCSS is true by default so it can be undefined
if (spec.useTransform) {
style.WebkitTransition =
'-webkit-transform ' + spec.speed + 'ms ' + spec.cssEase
style.transition = 'transform ' + spec.speed + 'ms ' + spec.cssEase
} else {
if (spec.vertical) {
style.transition = 'top ' + spec.speed + 'ms ' + spec.cssEase
} else {
style.transition = 'left ' + spec.speed + 'ms ' + spec.cssEase
}
}
return style
}
export const getTrackLeft = spec => {
if (spec.unslick) {
return 0
}
checkSpecKeys(spec, [
'slideIndex',
'trackRef',
'infinite',
'centerMode',
'slideCount',
'slidesToShow',
'slidesToScroll',
'slideWidth',
'listWidth',
'variableWidth',
'slideHeight',
])
const {
slideIndex,
trackRef,
infinite,
centerMode,
slideCount,
slidesToShow,
slidesToScroll,
slideWidth,
listWidth,
variableWidth,
slideHeight,
fade,
vertical,
} = spec
let slideOffset = 0
let targetLeft
let targetSlide
let verticalOffset = 0
if (fade || spec.slideCount === 1) {
return 0
}
let slidesToOffset = 0
if (infinite) {
slidesToOffset = -getPreClones(spec) // bring active slide to the beginning of visual area
// if next scroll doesn't have enough children, just reach till the end of original slides instead of shifting slidesToScroll children
if (
slideCount % slidesToScroll !== 0 &&
slideIndex + slidesToScroll > slideCount
) {
slidesToOffset = -(slideIndex > slideCount
? slidesToShow - (slideIndex - slideCount)
: slideCount % slidesToScroll)
}
// shift current slide to center of the frame
if (centerMode) {
slidesToOffset += parseInt(slidesToShow / 2)
}
} else {
if (
slideCount % slidesToScroll !== 0 &&
slideIndex + slidesToScroll > slideCount
) {
slidesToOffset = slidesToShow - slideCount % slidesToScroll
}
if (centerMode) {
slidesToOffset = parseInt(slidesToShow / 2)
}
}
slideOffset = slidesToOffset * slideWidth
verticalOffset = slidesToOffset * slideHeight
if (!vertical) {
targetLeft = slideIndex * slideWidth * -1 + slideOffset
} else {
targetLeft = slideIndex * slideHeight * -1 + verticalOffset
}
if (variableWidth === true) {
let targetSlideIndex
const trackElem = trackRef
targetSlideIndex = slideIndex + getPreClones(spec)
targetSlide = trackElem && trackElem.childNodes[targetSlideIndex]
targetLeft = targetSlide ? targetSlide.offsetLeft * -1 : 0
if (centerMode === true) {
targetSlideIndex = infinite
? slideIndex + getPreClones(spec)
: slideIndex
targetSlide = trackElem && trackElem.children[targetSlideIndex]
targetLeft = 0
for (let slide = 0; slide < targetSlideIndex; slide++) {
targetLeft -=
trackElem &&
trackElem.children[slide] &&
trackElem.children[slide].offsetWidth
}
targetLeft -= parseInt(spec.centerPadding)
targetLeft += targetSlide && (listWidth - targetSlide.offsetWidth) / 2
}
}
return targetLeft
}
export const getPreClones = spec => {
if (spec.unslick || !spec.infinite) {
return 0
}
if (spec.variableWidth) {
return spec.slideCount
}
return spec.slidesToShow + (spec.centerMode ? 1 : 0)
}
export const getPostClones = spec => {
if (spec.unslick || !spec.infinite) {
return 0
}
return spec.slideCount
}
export const getTotalSlides = spec =>
spec.slideCount === 1
? 1
: getPreClones(spec) + spec.slideCount + getPostClones(spec)
export const siblingDirection = spec => {
if (spec.targetSlide > spec.currentSlide) {
if (spec.targetSlide > spec.currentSlide + slidesOnRight(spec)) {
return 'left'
}
return 'right'
} else {
if (spec.targetSlide < spec.currentSlide - slidesOnLeft(spec)) {
return 'right'
}
return 'left'
}
}
export const slidesOnRight = ({
slidesToShow,
centerMode,
rtl,
centerPadding,
}) => {
// returns no of slides on the right of active slide
if (centerMode) {
let right = (slidesToShow - 1) / 2 + 1
if (parseInt(centerPadding) > 0) right += 1
if (rtl && slidesToShow % 2 === 0) right += 1
return right
}
if (rtl) {
return 0
}
return slidesToShow - 1
}
export const slidesOnLeft = ({
slidesToShow,
centerMode,
rtl,
centerPadding,
}) => {
// returns no of slides on the left of active slide
if (centerMode) {
let left = (slidesToShow - 1) / 2 + 1
if (parseInt(centerPadding) > 0) left += 1
if (!rtl && slidesToShow % 2 === 0) left += 1
return left
}
if (rtl) {
return slidesToShow - 1
}
return 0
}
export const canUseDOM = () =>
!!(
typeof window !== 'undefined' &&
window.document &&
window.document.createElement
)

View File

@ -162,12 +162,14 @@
"dom-closest": "^0.2.0",
"dom-scroll-into-view": "^1.2.1",
"enquire.js": "^2.1.6",
"json2mq": "^0.2.0",
"is-negative-zero": "^2.0.0",
"lodash": "^4.17.5",
"moment": "^2.21.0",
"omit.js": "^1.0.0",
"resize-observer-polyfill": "^1.5.0",
"shallow-equal": "^1.0.0",
"shallowequal": "^1.0.2",
"warning": "^3.0.0"
}
}
}

View File

@ -12,7 +12,7 @@ import {
Calendar,
Card,
Collapse,
// Carousel,
Carousel,
Cascader,
Checkbox,
Col,
@ -75,7 +75,7 @@ Vue.component(Card.Meta.name, Card.Meta)
Vue.component(Card.Grid.name, Card.Grid)
Vue.component(Collapse.name, Collapse)
Vue.component(Collapse.Panel.name, Collapse.Panel)
// Vue.component(Carousel.name, Carousel)
Vue.component(Carousel.name, Carousel)
Vue.component(Cascader.name, Cascader)
Vue.component(Checkbox.name, Checkbox)
Vue.component(Checkbox.Group.name, Checkbox.Group)

View File

@ -276,6 +276,12 @@ export default {
type: 'Data Entry',
title: 'Upload',
},
carousel: {
category: 'Components',
type: 'Data Display',
title: 'Carousel',
subtitle: '走马灯',
},
tree: {
category: 'Components',
subtitle: '树形控件',

View File

@ -399,4 +399,12 @@ export default [
path: 'list-cn',
component: () => import('../components/list/demo/index.vue'),
},
{
path: 'carousel',
component: () => import('../components/carousel/demo/index.vue'),
},
{
path: 'carousel-cn',
component: () => import('../components/carousel/demo/index.vue'),
},
]

View File

@ -10,7 +10,7 @@ import Api from './components/api'
import './components'
import demoBox from './components/demoBox'
import demoContainer from './components/demoContainer'
import Test from '../components/upload/demo/index'
import Test from '../components/carousel/demo/index'
Vue.use(VueClipboard)
Vue.use(VueRouter)

View File

@ -18,6 +18,7 @@ Array [
"Calendar",
"Card",
"Collapse",
"Carousel",
"Cascader",
"Checkbox",
"Col",