| <template> | 
|     <view | 
|         class="u-swiper" | 
|         :style="{ | 
|             backgroundColor: bgColor, | 
|             height: $u.addUnit(height), | 
|             borderRadius: $u.addUnit(radius) | 
|         }" | 
|     > | 
|         <view | 
|             class="u-swiper__loading" | 
|             v-if="loading" | 
|         > | 
|             <u-loading-icon mode="circle"></u-loading-icon> | 
|         </view> | 
|         <swiper | 
|             v-else | 
|             class="u-swiper__wrapper" | 
|             :style="{ | 
|                 height: $u.addUnit(height), | 
|             }" | 
|             @change="change" | 
|             :circular="circular" | 
|             :interval="interval" | 
|             :duration="duration" | 
|             :autoplay="autoplay" | 
|             :current="current" | 
|             :currentItemId="currentItemId" | 
|             :previousMargin="$u.addUnit(previousMargin)" | 
|             :nextMargin="$u.addUnit(nextMargin)" | 
|             :acceleration="acceleration" | 
|             :displayMultipleItems="displayMultipleItems" | 
|             :easingFunction="easingFunction" | 
|         > | 
|             <swiper-item | 
|                 class="u-swiper__wrapper__item" | 
|                 v-for="(item, index) in list" | 
|                 :key="index" | 
|             > | 
|                 <view | 
|                     class="u-swiper__wrapper__item__wrapper" | 
|                     :style="[itemStyle(index)]" | 
|                 > | 
|                     <!-- 在nvue中,image图片的宽度默认为屏幕宽度,需要通过flex:1撑开,另外必须设置高度才能显示图片 --> | 
|                     <image | 
|                         class="u-swiper__wrapper__item__wrapper__image" | 
|                         v-if="getItemType(item) === 'image'" | 
|                         :src="getSource(item)" | 
|                         :mode="imgMode" | 
|                         @tap="clickHandler(index)" | 
|                         :style="{ | 
|                             height: $u.addUnit(height), | 
|                             borderRadius: $u.addUnit(radius) | 
|                         }" | 
|                     ></image> | 
|                     <video | 
|                         class="u-swiper__wrapper__item__wrapper__video" | 
|                         v-if="getItemType(item) === 'video'" | 
|                         :id="`video-${index}`" | 
|                         :enable-progress-gesture="false" | 
|                         :src="getSource(item)" | 
|                         :poster="getPoster(item)" | 
|                         :title="showTitle && $u.test.object(item) && item.title ? item.title : ''" | 
|                         :style="{ | 
|                             height: $u.addUnit(height) | 
|                         }" | 
|                         controls | 
|                         @tap="clickHandler(index)" | 
|                     ></video> | 
|                     <text | 
|                         v-if="showTitle && $u.test.object(item) && item.title && $u.test.image(getSource(item))" | 
|                         class="u-swiper__wrapper__item__wrapper__title u-line-1" | 
|                     >{{ item.title }}</text> | 
|                 </view> | 
|             </swiper-item> | 
|         </swiper> | 
|         <view class="u-swiper__indicator" :style="[$u.addStyle(indicatorStyle)]"> | 
|             <slot name="indicator"> | 
|                 <u-swiper-indicator | 
|                     v-if="!loading && indicator && !showTitle" | 
|                     :indicatorActiveColor="indicatorActiveColor" | 
|                     :indicatorInactiveColor="indicatorInactiveColor" | 
|                     :length="list.length" | 
|                     :current="currentIndex" | 
|                     :indicatorMode="indicatorMode" | 
|                 ></u-swiper-indicator> | 
|             </slot> | 
|         </view> | 
|     </view> | 
| </template> | 
|   | 
| <script> | 
|     import props from './props.js'; | 
|     /** | 
|      * Swiper 轮播图 | 
|      * @description 该组件一般用于导航轮播,广告展示等场景,可开箱即用, | 
|      * @tutorial https://www.uviewui.com/components/swiper.html | 
|      * @property {Array}            list                    轮播图数据 | 
|      * @property {Boolean}            indicator                是否显示面板指示器(默认 false ) | 
|      * @property {String}            indicatorActiveColor    指示器非激活颜色(默认 '#FFFFFF' ) | 
|      * @property {String}            indicatorInactiveColor    指示器的激活颜色(默认 'rgba(255, 255, 255, 0.35)' ) | 
|      * @property {String | Object}    indicatorStyle            指示器样式,可通过bottom,left,right进行定位 | 
|      * @property {String}            indicatorMode            指示器模式(默认 'line' ) | 
|      * @property {Boolean}            autoplay                是否自动切换(默认 true ) | 
|      * @property {String | Number}    current                    当前所在滑块的 index(默认 0 ) | 
|      * @property {String}            currentItemId            当前所在滑块的 item-id ,不能与 current 被同时指定 | 
|      * @property {String | Number}    interval                滑块自动切换时间间隔(ms)(默认 3000 ) | 
|      * @property {String | Number}    duration                滑块切换过程所需时间(ms)(默认 300 ) | 
|      * @property {Boolean}            circular                播放到末尾后是否重新回到开头(默认 false ) | 
|      * @property {String | Number}    previousMargin            前边距,可用于露出前一项的一小部分,nvue和支付宝不支持(默认 0 ) | 
|      * @property {String | Number}    nextMargin                后边距,可用于露出后一项的一小部分,nvue和支付宝不支持(默认 0 ) | 
|      * @property {Boolean}            acceleration            当开启时,会根据滑动速度,连续滑动多屏,支付宝不支持(默认 false ) | 
|      * @property {Number}            displayMultipleItems    同时显示的滑块数量,nvue、支付宝小程序不支持(默认 1 ) | 
|      * @property {String}            easingFunction            指定swiper切换缓动动画类型, 只对微信小程序有效(默认 'default' ) | 
|      * @property {String}            keyName                    list数组中指定对象的目标属性名(默认 'url' ) | 
|      * @property {String}            imgMode                    图片的裁剪模式(默认 'aspectFill' ) | 
|      * @property {String | Number}    height                    组件高度(默认 130 ) | 
|      * @property {String}            bgColor                    背景颜色(默认     '#f3f4f6' ) | 
|      * @property {String | Number}    radius                    组件圆角,数值或带单位的字符串(默认 4 ) | 
|      * @property {Boolean}            loading                    是否加载中(默认 false ) | 
|      * @property {Boolean}            showTitle                是否显示标题,要求数组对象中有title属性(默认 false ) | 
|      * @event {Function(index)}    click    点击轮播图时触发    index:点击了第几张图片,从0开始 | 
|      * @event {Function(index)}    change    轮播图切换时触发(自动或者手动切换)    index:切换到了第几张图片,从0开始 | 
|      * @example    <u-swiper :list="list4" keyName="url" :autoplay="false"></u-swiper> | 
|      */ | 
|     export default { | 
|         name: 'u-swiper', | 
|         mixins: [uni.$u.mpMixin, uni.$u.mixin, props], | 
|         data() { | 
|             return { | 
|                 currentIndex: 0 | 
|             } | 
|         }, | 
|         watch: { | 
|             current(val, preVal) { | 
|                 if(val === preVal) return; | 
|                 this.currentIndex = val; // 和上游数据关联上 | 
|             } | 
|         }, | 
|         computed: { | 
|             itemStyle() { | 
|                 return index => { | 
|                     const style = {} | 
|                     // #ifndef APP-NVUE || MP-TOUTIAO | 
|                     // 左右流出空间的写法不支持nvue和头条 | 
|                     // 只有配置了此二值,才加上对应的圆角,以及缩放 | 
|                     if (this.nextMargin && this.previousMargin) { | 
|                         style.borderRadius = uni.$u.addUnit(this.radius) | 
|                         if (index !== this.currentIndex) style.transform = 'scale(0.92)' | 
|                     } | 
|                     // #endif | 
|                     return style | 
|                 } | 
|             } | 
|         }, | 
|         methods: { | 
|       getItemType(item) { | 
|         if (typeof item === 'string') return uni.$u.test.video(this.getSource(item)) ? 'video' : 'image' | 
|         if (typeof item === 'object' && this.keyName) { | 
|           if (!item.type) return uni.$u.test.video(this.getSource(item)) ? 'video' : 'image' | 
|           if (item.type === 'image') return 'image' | 
|           if (item.type === 'video') return 'video' | 
|           return 'image' | 
|         } | 
|       }, | 
|             // 获取目标路径,可能数组中为字符串,对象的形式,额外可指定对象的目标属性名keyName | 
|             getSource(item) { | 
|                 if (typeof item === 'string') return item | 
|                 if (typeof item === 'object' && this.keyName) return item[this.keyName] | 
|                 else uni.$u.error('请按格式传递列表参数') | 
|                 return '' | 
|             }, | 
|             // 轮播切换事件 | 
|             change(e) { | 
|                 // 当前的激活索引 | 
|                 const { | 
|                     current | 
|                 } = e.detail | 
|                 this.pauseVideo(this.currentIndex) | 
|                 this.currentIndex = current | 
|                 this.$emit('change', e.detail) | 
|             }, | 
|             // 切换轮播时,暂停视频播放 | 
|             pauseVideo(index) { | 
|                 const lastItem = this.getSource(this.list[index]) | 
|                 if (uni.$u.test.video(lastItem)) { | 
|                     // 当视频隐藏时,暂停播放 | 
|                     const video = uni.createVideoContext(`video-${index}`, this) | 
|                     video.pause() | 
|                 } | 
|             }, | 
|             // 当一个轮播item为视频时,获取它的视频海报 | 
|             getPoster(item) { | 
|                 return typeof item === 'object' && item.poster ? item.poster : '' | 
|             }, | 
|             // 点击某个item | 
|             clickHandler(index) { | 
|                 this.$emit('click', index) | 
|             } | 
|         }, | 
|     } | 
| </script> | 
|   | 
| <style lang="scss" scoped> | 
|     @import "../../libs/css/components.scss"; | 
|   | 
|     .u-swiper { | 
|         @include flex; | 
|         justify-content: center; | 
|         align-items: center; | 
|         position: relative; | 
|         overflow: hidden; | 
|   | 
|         &__wrapper { | 
|             flex: 1; | 
|   | 
|             &__item { | 
|                 flex: 1; | 
|   | 
|                 &__wrapper { | 
|                     @include flex; | 
|                     position: relative; | 
|                     overflow: hidden; | 
|                     transition: transform 0.3s; | 
|                     flex: 1; | 
|   | 
|                     &__image { | 
|                         flex: 1; | 
|                     } | 
|   | 
|                     &__video { | 
|                         flex: 1; | 
|                     } | 
|   | 
|                     &__title { | 
|                         position: absolute; | 
|                         background-color: rgba(0, 0, 0, 0.3); | 
|                         bottom: 0; | 
|                         left: 0; | 
|                         right: 0; | 
|                         font-size: 28rpx; | 
|                         padding: 12rpx 24rpx; | 
|                         color: #FFFFFF; | 
|                         flex: 1; | 
|                     } | 
|                 } | 
|             } | 
|         } | 
|   | 
|         &__indicator { | 
|             position: absolute; | 
|             bottom: 10px; | 
|         } | 
|     } | 
| </style> |