Skip to content

Commit

Permalink
feat: init project
Browse files Browse the repository at this point in the history
  • Loading branch information
kagol committed Jan 27, 2022
1 parent 2456573 commit 01b416a
Show file tree
Hide file tree
Showing 57 changed files with 6,333 additions and 2 deletions.
138 changes: 136 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,136 @@
# vue-carousel
一个简单、灵活的 Vue3 走马灯组件,非常轻量,只有 5kB。
# Vue DevUI Carousel

一个简单、灵活的`Vue3`走马灯组件,非常轻量,只有`5kB`

预览地址:
[https://kagol.gitee.io/vue-carousel/](https://kagol.gitee.io/vue-carousel/)

## 快速开始

创建一个vite工程:

```
yarn create vite vite-demo --template vue-ts
```

安装`Carousel`
```
yarn add vue-devui-carousel
```

`main.ts`中引入`Carousel`
```
import Carousel from 'vue-devui-carousel'
import 'vue-devui-carousel/dist/style.css'
createApp(App)
.use(Carousel)
.mount('#app')
```

`App.vue`中使用:

```
<DCarousel>
<div class="carousel-item">page 1</div>
<div class="carousel-item">page 2</div>
<div class="carousel-item">page 3</div>
</DCarousel>
```

## 效果动图

默认效果:

![1-default.gif](https://pic.imgdb.cn/item/61f2b4932ab3f51d9107f30c.gif)

掘金活动:

![2-juejin.gif](https://pic.imgdb.cn/item/61f2b4932ab3f51d9107f315.gif)

指示器位置:

![3-indicator-position.gif](https://pic.imgdb.cn/item/61f2b4932ab3f51d9107f31c.gif)

自定义指示器:

![4-custom-indicator.gif](https://pic.imgdb.cn/item/61f2b4932ab3f51d9107f325.gif)

分页器位置:

![5-pagination-position.gif](https://pic.imgdb.cn/item/61f2b4932ab3f51d9107f32f.gif)

自定义分页器:

![6-custom-pagination.gif](https://pic.imgdb.cn/item/61f2b5282ab3f51d9108b5ef.gif)

华为官网:

![7-huawei.gif](https://pic.imgdb.cn/item/61f2b7bb2ab3f51d910d4651.gif)

QQ音乐:

![8-qqmusic.gif](https://pic.imgdb.cn/item/61f2bb5d2ab3f51d91146170.gif)

B站:

![9-bilibili.gif](https://pic.imgdb.cn/item/61f2b85e2ab3f51d910e65ab.gif)

手风琴式折叠卡片:

![10-collapse-card.gif](https://pic.imgdb.cn/item/61f2b6f42ab3f51d910bc018.gif)

## API

### DCarousel 组件

props

| 属性 | 类型 | 默认 | 说明 |
| ------- | ------ | ---- | -------------- |
| v-model | Number | 1 | 可选,当前页码 |
| autoplay | Boolean | true | 可选,是否自动播放 |
| interval | Number | 3000 | 可选,自动播放的时间间隔,单位是毫秒 |

插槽

| 属性 | 类型 | 默认 | 说明 |
| ------- | ------ | ---- | -------------- |
| default | -- | -- | 必选,默认插槽 |
| indicator | -- | -- | 可选,指示器插槽 |
| pagination | -- | -- | 可选,分页器插槽 |

### DCarouselIndicator 组件

props

| 属性 | 类型 | 默认 | 说明 |
| ------- | ------ | ---- | -------------- |
| v-model | Number | 1 | 可选,当前页码 |
| count | Number | -- | 可选,指示器元素数量 |

插槽

| 属性 | 类型 | 默认 | 说明 |
| ------- | ------ | ---- | -------------- |
| default | ({ pageIndex, setPageIndex }) => {} | -- | 可选,默认插槽 |

### DCarouselPrev 组件

插槽

| 属性 | 类型 | 默认 | 说明 |
| ------- | ------ | ---- | -------------- |
| default | -- | -- | 可选,默认插槽 |

### DCarouselNext 组件

插槽

| 属性 | 类型 | 默认 | 说明 |
| ------- | ------ | ---- | -------------- |
| default | -- | -- | 可选,默认插槽 |

参考:

[用积木理论设计的Carousel组件都有哪些有趣的玩法?](https://juejin.cn/post/7056193763810476063/)
Empty file.
18 changes: 18 additions & 0 deletions carousel/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { App } from 'vue'
import DCarousel from './src/carousel'
import DCarouselIndicator from './src/components/carousel-indicator'
import DCarouselPrev from './src/components/carousel-prev'
import DCarouselNext from './src/components/carousel-next'
import usePage from './src/composables/use-page'

export { DCarousel, DCarouselIndicator, DCarouselPrev, DCarouselNext, usePage }

export default {
install(app: App) {
app.component(DCarousel.name, DCarousel)
app.component(DCarouselIndicator.name, DCarouselIndicator)
app.component(DCarouselPrev.name, DCarouselPrev)
app.component(DCarouselNext.name, DCarouselNext)
app.config.globalProperties.usePage = usePage
}
}
38 changes: 38 additions & 0 deletions carousel/src/carousel.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
.devui-carousel {
position: relative;
overflow: hidden;

.devui-carousel-indicator {
position: absolute;
}
}

.devui-carousel-item-container {
display: flex;
position: relative;
transition: left 500ms ease 0s; // 内容切换时的动效

& > * {
flex: 1;
}
}

.devui-arrow {
position: absolute;
top: 50%;
margin-top: -18px;
cursor: pointer;
width: 36px;
height: 36px;
border-radius: 18px;
background: var(--devui-highlight-overlay, rgba(255, 255, 255, .8));
box-shadow: var(--devui-shadow-length-hover, 0 4px 16px 0) var(--devui-light-shadow, rgba(0, 0, 0, .1));
display: inline-flex;
align-items: center;
justify-content: center;
transition: background-color var(--devui-animation-duration-slow, .3s) var(--devui-animation-ease-in-out-smooth, cubic-bezier(.645, .045, .355, 1));

&:hover {
background: var(--devui-area, #f8f8f8);
}
}
110 changes: 110 additions & 0 deletions carousel/src/carousel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import { defineComponent, renderSlot, useSlots, watch, toRefs, ref } from 'vue'

// Components
import DCarouselIndicator from './components/carousel-indicator'
import DCarouselPrev from './components/carousel-prev'
import DCarouselNext from './components/carousel-next'

// Composables
import usePage from './composables/use-page'
import useAutoplay from './composables/use-autoplay'

// Util
import { formatPageIndex } from './carousel.util'

// Props/Types
import { carouselProps, CarouselProps } from './carousel.type'

// SCSS
import './carousel.scss'

export default defineComponent({
name: 'DCarousel',
components: {
DCarouselIndicator,
DCarouselPrev,
DCarouselNext,
},
props: carouselProps,
emits: ['update:modelValue'],
setup(props: CarouselProps, { slots, emit }) {
const { modelValue, autoplay, interval } = toRefs(props)

const { pageIndex, prevPage, nextPage, setPageIndex } = usePage(modelValue.value)
const { startPlay, stopPlay } = useAutoplay(nextPage, interval.value)

const count = useSlots().default().filter(item => typeof item.type !== 'symbol').length
const defaultFormattedPageIndex = formatPageIndex(pageIndex.value, count)
const formattedPageIndex = ref(defaultFormattedPageIndex)

const launchTimer = (autoplay) => {
if (autoplay) {
startPlay()
} else {
stopPlay()
}
}

launchTimer(autoplay.value)

watch(autoplay, (newVal) => {
launchTimer(newVal)
})

watch(modelValue, (newVal: number) => {
pageIndex.value = newVal
})

watch(pageIndex, (newVal: number) => {
emit('update:modelValue', newVal)
formattedPageIndex.value = formatPageIndex(pageIndex.value, count)
})

watch(formattedPageIndex, (newVal: number) => {
pageIndex.value = newVal
})

return () => {
return (
<div class="devui-carousel">
<div
class="devui-carousel-item-container"
style={{
width: count * 100 + '%',
left: -(formattedPageIndex.value - 1) * 100 + '%',
}}
>
{renderSlot(useSlots(), 'default')}
</div>
{
slots.pagination
? renderSlot(useSlots(), 'pagination', {
prevPage, nextPage
}) : <>
<DCarouselPrev onClick={() => {
emit('update:modelValue', props.modelValue-1)
prevPage()
}} />
<DCarouselNext onClick={() => {
emit('update:modelValue', props.modelValue+1)
nextPage()
}} />
</>
}
{slots.indicator ? (
slots.indicator({
count,
pageIndex: formattedPageIndex.value,
setPageIndex
})
) : (
<DCarouselIndicator
count={count}
v-model={formattedPageIndex.value}
></DCarouselIndicator>
)}
</div>
)
}
},
})
17 changes: 17 additions & 0 deletions carousel/src/carousel.type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { extractPropTypes } from 'vue'

export const carouselProps = {
modelValue: {
type: Number,
},
autoplay: {
type: Boolean,
default: true,
},
interval: {
type: Number,
default: 3000,
}
}

export type CarouselProps = extractPropTypes<typeof carouselProps>
7 changes: 7 additions & 0 deletions carousel/src/carousel.util.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export const formatPageIndex = (current, count) => {
if (current <= 0) {
return current + count * (Math.floor(-current / count) + 1)
} else {
return current % count === 0 ? count : current % count
}
}
24 changes: 24 additions & 0 deletions carousel/src/components/arrow-left.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
export default () => (
<svg
_ngcontent-jai-c250=""
width="18px"
height="18px"
viewBox="0 0 16 16"
version="1.1"
>
<g
_ngcontent-jai-c250=""
stroke="none"
stroke-width="1"
fill="none"
fill-rule="evenodd"
>
<polygon
_ngcontent-jai-c250=""
fill="#293040"
fill-rule="nonzero"
points="10.7071068 12.2928932 9.29289322 13.7071068 3.58578644 8 9.29289322 2.29289322 10.7071068 3.70710678 6.41421356 8"
></polygon>
</g>
</svg>
)
25 changes: 25 additions & 0 deletions carousel/src/components/arrow-right.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
export default () => (
<svg
_ngcontent-jai-c250=""
width="18px"
height="18px"
viewBox="0 0 16 16"
version="1.1"
>
<g
_ngcontent-jai-c250=""
stroke="none"
stroke-width="1"
fill="none"
fill-rule="evenodd"
>
<polygon
_ngcontent-jai-c250=""
fill="#293040"
fill-rule="nonzero"
transform="translate(8.146447, 8.000000) scale(-1, 1) translate(-8.146447, -8.000000) "
points="11.7071068 12.2928932 10.2928932 13.7071068 4.58578644 8 10.2928932 2.29289322 11.7071068 3.70710678 7.41421356 8"
></polygon>
</g>
</svg>
)
Loading

0 comments on commit 01b416a

Please sign in to comment.