feat: 优化 Swiper 使用默认插槽时插槽内容的显示效果 (#1301)

This commit is contained in:
不如摸鱼去 2025-09-15 22:27:05 +08:00 committed by GitHub
parent 046b135a14
commit 41dd4177b6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 252 additions and 31 deletions

View File

@ -300,18 +300,21 @@ const isLoop = ref(false)
``` ```
## slot插槽自定义内容 ## 插槽用法
通过默认插槽可以自定义轮播项的内容。
```html ```html
<wd-swiper <wd-swiper
:list="swiperList" :list="swiperList"
autoplay autoplay
v-model:current="current" v-model:current="current"
:indicator="{ type: 'dots' }" :indicator="{ type: 'dots-bar' }"
@click="handleClick" @click="handleClick"
@change="onChange" @change="onChange"
> >
<template v-slot="{ item, index }"> <template #default="{ item }">
<view class="custom-indicator" style="position: absolute; bottom: 24rpx; right: 24rpx">{{ index + 1 }}/{{ item }}</view> <image :src="item as string" mode="aspectFill" style="width: 100%; height: 100%" />
</template> </template>
</wd-swiper> </wd-swiper>
``` ```
@ -401,8 +404,8 @@ const isLoop = ref(false)
| name | 说明 | 参数 | 最低版本 | | name | 说明 | 参数 | 最低版本 |
| --------- | ------------ | ------------------------------------ | -------- | | --------- | ------------ | ------------------------------------ | -------- |
| indicator | 自定义指示器 | `{ current: number, total: number }` | 0.1.22 | | indicator | 自定义指示器 | `{ current: number, total: number }` | $LOWEST_VERSION$ |
| default | item展示内容 | `{ item: any, index: number }` | 0.1.22 | | default | item展示内容 | `{ item: string | SwiperList, index: number }` | $LOWEST_VERSION$ |
## 外部样式类 ## 外部样式类

View File

@ -201,31 +201,216 @@ Set the `display-multiple-items` property to control the number of slides displa
} }
``` ```
## Vertical Direction
Set `direction` to `vertical` to arrange slides vertically.
```html
<wd-swiper
:list="swiperList"
direction="vertical"
indicatorPosition="right"
autoplay
v-model:current="current"
:indicator="{ type: 'dots-bar' }"
@click="handleClick"
@change="onChange"
></wd-swiper>
```
## Custom Indicator
Use the `indicator` slot to customize the indicator style.
```html
<wd-swiper
:list="swiperList"
direction="vertical"
indicatorPosition="right"
autoplay
v-model:current="current"
@click="handleClick"
@change="onChange"
>
<template #indicator="{ current, total }">
<view class="custom-indicator" style="position: absolute; bottom: 24rpx; right: 24rpx">{{ current + 1 }}/{{ total }}</view>
</template>
</wd-swiper>
```
```scss
.custom-indicator {
padding: 0 12rpx;
height: 48rpx;
line-height: 48rpx;
border-radius: 45%;
background: rgba(0, 0, 0, 0.6);
color: #ffffff;
font-size: 24rpx;
}
```
## Specify valueKey and textKey
Use `value-key` to specify the image address field in each object of the `list`, default is `value`.
Use `text-key` to specify the title field in each object of the `list`, default is `text`.
```html
<wd-swiper
value-key="url"
text-key="title"
:list="customSwiperList"
autoplay
v-model:current="current"
@click="handleClick"
@change="onChange"
></wd-swiper>
```
```ts
const current = ref<number>(0)
const customSwiperList = ref([
{ url: 'https://wot-ui.cn/assets/redpanda.jpg', title: 'Red Panda!' },
{ url: 'https://wot-ui.cn/assets/capybara.jpg', title: 'Capybara!' },
{ url: 'https://wot-ui.cn/assets/panda.jpg', title: 'Giant Panda!' },
{ url: 'https://wot-ui.cn/assets/moon.jpg', title: 'Poetic China!' }
])
```
## Property Control Switching
```html
<wd-swiper :loop="isLoop" :autoplay="false" :list="swiperList" v-model:current="current" />
<wd-gap />
<wd-cell-group>
<wd-cell title="loop">
<wd-switch v-model="isLoop" size="24px" />
</wd-cell>
<wd-cell title="current" :value="current.toString()" />
</wd-cell-group>
<view style="display: flex; justify-content: space-between">
<wd-button @click="current--">prev</wd-button>
<wd-button type="success" @click="current++">next</wd-button>
</view>
```
```javascript
const current = ref<number>(0)
const isLoop = ref(false)
```
## Slot Usage
Use the default slot to customize the content of carousel items.
```html
<wd-swiper
:list="swiperList"
autoplay
v-model:current="current"
:indicator="{ type: 'dots-bar' }"
@click="handleClick"
@change="onChange"
>
<template #default="{ item }">
<image :src="item as string" mode="aspectFill" style="width: 100%; height: 100%" />
</template>
</wd-swiper>
```
## Attributes ## Attributes
| Attribute | Description | Type | Default | Version | | Parameter | Description | Type | Optional Values | Default Value | Minimum Version |
|-----------|-------------|------|---------|----------| | ------------------------- | ------------------------------------------------------------------ | --------------------------------- | ------------------------------------------------------------------------------------------------------ | ------------- | ---------------- |
| list | List of images or videos to display | array | [] | - | | autoplay | Whether to enable auto-play | `boolean` | - | true | 0.1.22 |
| v-model:current | Current slide index | number | 0 | - | | v-model:current | Control which carousel item is currently displayed (index) | `number` | - | 0 | 0.1.22 |
| autoplay | Whether to enable auto-play | boolean | false | - | | direction | Carousel sliding direction | `DirectionType` | `horizontal, vertical` | horizontal | 0.1.22 |
| interval | Auto-play interval (ms) | number | 3000 | - | | displayMultipleItems | Number of slides displayed simultaneously | `number` | - | 1 | 0.1.22 |
| duration | Slide animation duration (ms) | number | 500 | - | | duration | Slide animation duration | `number` | - | 300 | 0.1.22 |
| indicator | Indicator configuration object | object | { type: 'dots' } | - | | easingFunction | Switching easing animation type (WeChat Mini Program, Kuaishou Mini Program, JD Mini Program) | `EasingType` | - | default | 0.1.22 |
| indicator-position | Indicator position | string | 'bottom' | - | | height | Height of the carousel | `string / number` | - | 192 | 0.1.22 |
| previous-margin | Previous slide margin | string | '0px' | - | | interval | Carousel interval time | `number` | - | 5000 | 0.1.22 |
| next-margin | Next slide margin | string | '0px' | - | | list | Image list | `string[] / SwiperList[]` | - | - | 0.1.22 |
| display-multiple-items | Number of slides to display simultaneously | number | 1 | - | | loop | Whether to enable loop playback | `boolean` | - | true | 0.1.22 |
| autoplay-video | Whether to auto-play videos | boolean | true | - | | nextMargin | Next margin | `string / number` | - | 0 | 0.1.22 |
| stop-autoplay-when-video-play | Whether to stop carousel when playing video | boolean | false | - | | indicatorPosition | Indicator display position | `IndicatorPositionType` | `left, top-left, top, top-right, bottom-left, bottom, bottom-right, right` | bottom | 0.1.22 |
| loop | Whether to enable loop mode | boolean | true | - | | previousMargin | Previous margin | `string / number` | - | 0 | 0.1.22 |
| custom-indicator-class | Custom indicator class | string | - | - | | snapToEdge | Whether margins should apply to first and last elements | `boolean` | - | false | 0.1.22 |
| custom-image-class | Custom image class | string | - | - | | indicator | Complete indicator configuration | `SwiperIndicatorProps / boolean` | - | true | 0.1.22 |
| custom-next-image-class | Custom next image class | string | - | - | | imageMode | Image cropping and scaling mode | `string` | Refer to official documentation [mode](https://uniapp.dcloud.net.cn/component/image.html#mode-%E6%9C%89%E6%95%88%E5%80%BC) | `aspectFill` | 0.1.55 |
| custom-prev-image-class | Custom previous image class | string | - | - | | autoplayVideo | Whether videos auto-play, default is auto-play | `boolean` | - | true | 1.3.13 |
| stopPreviousVideo | Whether to stop previous video playback when switching carousel items, default stops previous video when switching | `boolean` | - | true | 1.3.13 |
| stopAutoplayWhenVideoPlay | Whether to stop auto-carousel when video is playing | `boolean` | - | false | 1.3.13 |
| customStyle | External custom style | `string` | - | '' | 0.1.22 |
| value-key | Key corresponding to value in option object | `string` | - | `value` | 1.3.7 |
| text-key | Key corresponding to title text in option object | `string` | - | `text` | 1.3.13 |
| adjust-height | Automatically use specified slide height as entire container height. When vertical is true, default is not adjusted, only supported by Alipay Mini Program. | `string` | `'first' / 'current' / 'highest' / 'none'` | `highest` | 1.3.13 |
| adjust-vertical-height | Force adjust-height to take effect when vertical is true. Only supported by Alipay Mini Program. | `boolean` | - | `false` | 1.3.13 |
| muted | Whether video plays muted | `boolean` | - | `true` | 1.6.0 |
| videoLoop | Whether video loops | `boolean` | - | `true` | 1.6.0 |
### DirectionType
Carousel sliding direction, optional values are `'horizontal'` and `'vertical'`.
### EasingType
Switching easing animation type, optional values are `'default'`, `'linear'`, `'easeInCubic'`, `'easeOutCubic'` and `'easeInOutCubic'`.
### IndicatorPositionType
Page information display position, optional values are `'left'`, `'top-left'`, `'top'`, `'top-right'`, `'bottom-left'`, `'bottom'`, `'bottom-right'` and `'right'`.
### SwiperList
Carousel item list configuration, including image or video address `value`, video cover `poster`, file resource type `type` and other attributes, supports extended attributes. After specifying `type`, the component will not internally determine the file type and will use `type` as the standard.
| name | Description | Minimum Version |
| ------ | ------------------------------ | --------------- |
| value | Image or video address | - |
| poster | Video cover | - |
| type | Used to specify file resource type, optional values `image`, `video` | 1.4.0 |
### SwiperIndicatorProps
| Parameter | Description | Type | Optional Values | Default Value | Minimum Version |
| ------------------- | ------------------------------ | --------------------- | ---------------------------------------------------------------------------------- | ------------- | --------------- |
| current | Current carousel item (index) | Number | - | 0 | 0.1.22 |
| direction | Carousel sliding direction | DirectionType | `horizontal, vertical` | horizontal | 0.1.22 |
| min-show-num | Won't show navigator below this number | Number | - | 2 | 0.1.22 |
| pagination-position | Page information display position | IndicatorPositionType | `left, top-left, top, top-right, bottom-left, bottom, bottom-right, right` | bottom | 0.1.22 |
| show-controls | Whether to show control buttons | Boolean | - | false | 0.1.22 |
| total | Total number of items | Number | - | 0 | 0.1.22 |
| type | Navigator type | SwiperIndicatorType | `dots, dots-bar, fraction` | dots | 0.1.22 |
| autoplay | Whether to enable auto-play | boolean | - | true | 0.1.22 |
## Events ## Events
| Event | Description | Parameters | | Event Name | Description | Parameters | Minimum Version |
|-------|-------------|------------| | ---------- | ------------------------ | ----------------------------------------------------------- | --------------- |
| click | Triggered when clicking a slide | event: Event | | click | Triggered when clicking carousel item | `(index: number, item: SwiperList \| string)` | 0.1.22 |
| change | Triggered when current slide changes | index: number | | change | Triggered when carousel switches | `(current: number, source: 'autoplay' \| 'touch' \| 'nav')` | 0.1.22 |
## Slot
| name | Description | Parameters | Minimum Version |
| --------- | ------------------- | ------------------------------------ | --------------- |
| indicator | Custom indicator | `{ current: number, total: number }` | $LOWEST_VERSION$ |
| default | Item display content | `{ item: string | SwiperList, index: number }` | $LOWEST_VERSION$ |
## External Style Classes
| Class Name | Description | Minimum Version |
| -------------------- | --------------------------- | --------------- |
| customClass | External custom class name | 0.1.22 |
| customIndicatorClass | Custom indicator class name | 0.1.22 |
| customImageClass | Custom image class name, will be deprecated in version 1.3, please use `customItemClass` instead | 0.1.22 |
| customPrevImageClass | Custom previous image class name, will be deprecated in version 1.3, please use `customPrevClass` instead | 0.1.22 |
| customNextImageClass | Custom next image class name, will be deprecated in version 1.3, please use `customNextClass` instead | 0.1.22 |
| customItemClass | Custom item class name | 1.3.13 |
| customPrevClass | Custom previous item class name | 1.3.13 |
| customNextClass | Custom next item class name | 1.3.13 |
| customTextClass | Custom text title class name | 1.3.13 |
| customTextStyle | Custom text title style | 1.3.13 |

View File

@ -175,6 +175,14 @@
<wd-button type="success" @click="current8++">next</wd-button> <wd-button type="success" @click="current8++">next</wd-button>
</view> </view>
</demo-block> </demo-block>
<demo-block :title="$t('cha-cao-yong-fa')">
<wd-swiper :list="swiperList" autoplay v-model:current="current1" :indicator="{ type: 'dots-bar' }" @click="handleClick" @change="onChange">
<template #default="{ item }">
<image :src="item as string" mode="aspectFill" style="width: 100%; height: 100%" />
</template>
</wd-swiper>
</demo-block>
</page-wraper> </page-wraper>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>

View File

@ -15,6 +15,26 @@
align-items: center; align-items: center;
box-sizing: border-box; box-sizing: border-box;
padding: $-swiper-item-padding; padding: $-swiper-item-padding;
@include m(slot) {
// 问题来自 https://github.com/dcloudio/uni-app/issues/4629支付宝小程序不支持属性选择器
/* #ifdef MP */
:deep() {
/* #ifdef MP-WEIXIN */
view:not([class]) {
width: 100%;
height: 100%;
}
/* #endif */
/* #ifndef MP-WEIXIN */
view {
width: 100%;
height: 100%;
}
/* #endif */
}
/* #endif */
}
} }
@include e(image, video) { @include e(image, video) {

View File

@ -22,7 +22,7 @@
@change="handleChange" @change="handleChange"
@animationfinish="handleAnimationfinish" @animationfinish="handleAnimationfinish"
> >
<swiper-item v-for="(item, index) in list" :key="index" class="wd-swiper__item"> <swiper-item v-for="(item, index) in list" :key="index" :class="swiperItemClass">
<slot :item="item" :index="index"> <slot :item="item" :index="index">
<video <video
v-if="isVideo(item)" v-if="isVideo(item)"
@ -88,10 +88,11 @@ export default {
<script lang="ts" setup> <script lang="ts" setup>
import wdSwiperNav from '../wd-swiper-nav/wd-swiper-nav.vue' import wdSwiperNav from '../wd-swiper-nav/wd-swiper-nav.vue'
import { computed, watch, ref, getCurrentInstance } from 'vue' import { computed, watch, ref, getCurrentInstance, useSlots } from 'vue'
import { addUnit, isObj, isImageUrl, isVideoUrl, uuid, isDef } from '../common/util' import { addUnit, isObj, isImageUrl, isVideoUrl, uuid, isDef } from '../common/util'
import { swiperProps, type SwiperList } from './types' import { swiperProps, type SwiperList } from './types'
import type { SwiperNavProps } from '../wd-swiper-nav/types' import type { SwiperNavProps } from '../wd-swiper-nav/types'
const slots = useSlots()
const props = defineProps(swiperProps) const props = defineProps(swiperProps)
const emit = defineEmits(['click', 'change', 'animationfinish', 'update:current']) const emit = defineEmits(['click', 'change', 'animationfinish', 'update:current'])
@ -130,6 +131,10 @@ watch(
} }
) )
const swiperItemClass = computed(() => {
return `wd-swiper__item ${slots.default ? 'wd-swiper__item--slot' : ''}`
})
const swiperIndicator = computed(() => { const swiperIndicator = computed(() => {
const { list, direction, indicatorPosition, indicator } = props const { list, direction, indicatorPosition, indicator } = props
const swiperIndicator: Partial<SwiperNavProps> = { const swiperIndicator: Partial<SwiperNavProps> = {