123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473 |
- <template>
- <view class="swiperContent">
- <swiper
- @transition='transition'
- @change="change"
- @animationfinish="animationfinish"
- :indicator-dots="indicatorDots"
- :indicator-active-color="indicatorActiveColor"
- :indicator-color="indicatorColor"
- :autoplay="autoplay && !videoPlaySataus"
- :current="activeCurrent"
- :interval="interval"
- :duration="duration"
- :circular="circular"
- :vertical="vertical"
- :previous-margin="effect3d ? effect3dMargin : previousMargin"
- :next-margin="effect3d ? effect3dMargin : nextMargin"
- :display-multiple-items="displayMultipleItems"
- :skip-hidden-item-layout="skipHiddenItemLayout"
- :style="{'height':swiperHeight+'px','border-radius': contentRadius,'overflow': 'hidden'}"
- :class="{
- 'effect3D':effect3d && displayMultipleItems ==1,
- 'effect3D-X':effect3d && !vertical,
- 'effect3D-Y':effect3d && vertical}"
- class="z-screen-swiper">
- <swiper-item
- class="z-swiper-item"
- v-for="(item,index) in swiperList"
- :key="index"
- :class="{'active-swiper':activeCurrent===index}"
- :style="{'backgroundColor':`${bgColor}`}"
- @tap="clickItem(index)">
- <view class="swiper-box" :style="{'backgroundColor':`${bgColorItem}`}">
- <view
- class="swiper-top"
- :class="{'isFloat':topFloat}"
- @click="$emit('clickTop',{item,index})">
- <slot :row='item' :index='index' name="top">
- <!-- 顶部占位 无值则不占位 -->
- <view v-if="item[topTextKey]"
- :style="{'text-align':`${topTextAlign}`,
- 'color':`${topColor}`,
- 'background-color':`${topBackground}`}">
- <text v-text="item[topTextKey]"></text>
- </view>
- </slot>
- </view>
- <view class="swiper-content">
- <slot :row='item' :index='index'>
- <image v-if="item.type==='image'" :src="item[imageKey]" :mode='imgMode'>
- <template v-if="item.type==='video'">
- <!-- :style="{'height':fullScreen ? '':'100%' }" 解决非全屏video显示问题 -->
- <video
- :style="{'height':fullScreen ? '':'100%'}"
- @play='play'
- @pause='pause'
- @timeupdate='timeupdate'
- :initial-time='item.currentTime || 0 '
- enable-play-gesture
- :enable-progress-gesture='false'
- x5-video-player-type="h5"
- x-webkit-airplay="allow"
- objectFit="contain"
- webkit-playsinline="true"
- :id="`video_${index}`"
- :src="item[videoKey]"
- :poster="item.poster"
- controls>
- <!-- #ifdef APP-PLUS -->
- <cover-view :style="{ transform: 'translateX(' + moveX + 'px)'}"></cover-view>
- <!-- #endif -->
- </video>
- </template>
- </slot>
- </view>
- <view
- class="swiper-fotter"
- :class="{'isFloat':fotterFloat}"
- @click="$emit('clickBottom',{item,index})">
- <slot :row='item' :index='index' name="fotter">
- <!-- 底部盒子 不传值则不占位 -->
- <view v-if="item[bottomTextKey]"
- :style="{'text-align':`${bottomTextAlign}`,
- 'color':`${bottomColor}`,
- 'background-color':`${bottomBackground}`}">
- <text v-text="item[bottomTextKey]"></text>
- </view>
- </slot>
- </view>
- </view>
- </swiper-item>
- </swiper>
- <!-- indicatorDots 原生指示器开启时不显示下面自定义指示器
- vertical为true 垂直方向 只写了支持右侧定位
- -->
- <view
- v-if="!indicatorDots"
- :style="{'margin':`0 ${effect3dMargin}`}"
- :class="['dot',vertical ? 'verticalDot':`${indicatorPos}`]"
- >
- <slot :list='list' :total='list.length' :activeIndex='activeCurrent' name="dot">
- <!-- 指示器自定义-返回列表数据list 数组长度total 选中项索引activeIndex -->
- <template v-if="mode==='number'">
- <view>
- {{activeCurrent+1}}/{{list.length}}
- </view>
- </template>
- <template v-else>
- <view
- v-for="(item,index) in list"
- :key="index"
- @click="activeCurrent=index"
- :style="{'background-color': activeCurrent==index ? indicatorActiveColor:indicatorColor}"
- :class="['dotItem',`${mode}`, `${ activeCurrent==index ? 'defautActive':'' }` ]">
- <span v-if="mode ==='index'">{{index+1}}</span>
- </view>
- </template>
- </slot>
- </view>
- </view>
- </template>
- <script>
- export default {
- name:'z-swiper',
- props: {
- list:{//滑块视图容器数据
- type:Array,
- default:_=>[
- {
- type:'video',
- topTip:'顶部提示',
- poster:'https://img2.baidu.com/it/u=2141851239,1037607188&fm=26&fmt=auto&gp=0.jpg',
- src:'https://bjetxgzv.cdn.bspapp.com/VKCEYUGU-uni-app-doc/a876efc0-4f35-11eb-97b7-0dc4655d6e68.mp4',
- bottomTip:'底部提示',
- },
- {type:'image', src:'https://img0.baidu.com/it/u=875130878,1196408569&fm=11&fmt=auto&gp=0.jpg'},
- {type:'image', src:'https://img2.baidu.com/it/u=293682470,1155349941&fm=26&fmt=auto&gp=0.jpg'},
- {type:'image', src:'https://img0.baidu.com/it/u=3464142916,229554071&fm=26&fmt=auto&gp=0.jpg'},
- {
- type:'video',
- currentTime:120,//初始帧时间---默认缓存存储
- poster:'https://img1.baidu.com/it/u=1297253752,1185196455&fm=26&fmt=auto&gp=0.jpg',
- src:'https://bjetxgzv.cdn.bspapp.com/VKCEYUGU-uni-app-doc/a876efc0-4f35-11eb-97b7-0dc4655d6e68.mp4',
- },
- {type:'image', src:'https://img1.baidu.com/it/u=2057763469,3313822915&fm=26&fmt=auto&gp=0.jpg'},
- {type:'image', src:'https://img0.baidu.com/it/u=1570602913,157918019&fm=26&fmt=auto&gp=0.jpg'},
- ]
- },
- videoKey:{ type:String, default:'src'},// 视频映射的键
- imageKey:{ type:String, default:'src'},//图片映射的键
- indicatorPos:{ type:String, default:'bottomCenter'},//指示器的位置:topLeft/topCenter/topRight/bottomLeft/bottomCenter/bottomRight
- mode:{ type:String, default:'round' },//指示器样式: default circle round index number none时不显示
- fullScreen:{ type:Boolean, default:false }, //是否全屏
- navHeight:{type:Number, default:44},//顶部导航高度,默认44---垂直全屏状态无导航栏可设置为0
- height:{ type:Number, default:160 },//swiper 高度单位px
- contentRadius:{ type:String, default:'0rpx' },//盒子圆角设置
- topFloat:{ type:Boolean, default:true },//顶部不占位-浮动定位
- fotterFloat:{ type:Boolean, default:true },//底部不占位-浮动定位
- effect3d:{ type:Boolean, default:false },//是否开启3D效果 注:只有在displayMultipleItems=1时有效
- effect3dMargin:{type: String, default: '40rpx'},//effect3d=true模式下前后间距接受px和rpx值
- imgMode:{type: String, default: 'scaleToFill'},//图片的裁剪模式,详见https://uniapp.dcloud.io/component/image
- bgColor:{type: String, default: '#f3f4f6'},//swiper背景色
- bgColorItem:{type: String, default: 'rgba(0,0,0,0)'},//swiper当前项背景色
-
- //顶部与底部设置-注:-顶部与底部根据需求自己拓展---也可用插槽自定义内容
- topTextKey:{ type:String, default:'topTip'},//顶部文字说明映射的键
- topColor:{ type:String, default:'#FFF'},//顶部文字颜色
- topBackground:{ type:String, default:'rgba(0, 0, 0, 0)'},//顶部背景色
- topTextAlign:{ type:String, default:'left'},//顶部文字位置
- bottomTextKey:{ type:String, default:'bottomTip'},//底部文字说明映射的键
- bottomColor:{ type:String, default:'#00F'},//底部文字颜色
- bottomBackground:{ type:String, default:'rgba(0, 0, 0, 0)'},//底部背景色
- bottomTextAlign:{ type:String, default:'left'},//底部文字位置
- //---end
-
- // ---swiper原生属性-参考https://uniapp.dcloud.io/component/swiper
- skipHiddenItemLayout:{ //是否跳过未显示的滑块布局,设为 true 可优化复杂情况下的滑动性能,但会丢失隐藏状态滑块的布局信息
- type:Boolean,
- default:false
- },
- displayMultipleItems:{ type:Number,default:1 },//同时显示的滑块数量
- nextMargin:{ // 后边距,可用于露出后一项的一小部分,接受 px 和 rpx 值 头条小程序不支持
- type:String,
- default:'0rpx'
- },
- previousMargin:{//前边距,可用于露出前一项的一小部分,接受 px 和 rpx 值头条小程序不支持
- type:String,
- default:'0rpx'
- },
- vertical:{ type:Boolean, default:false },//滑动方向是否为纵向 卡牌不支持纵向以及同时显示的2块以上滑块数量
- circular:{ type:Boolean, default:true },//是否采用衔接滑动
- duration:{ type:Number, default:400 },// 滑动动画时长
- interval:{ type:Number, default:2500 },// 自动切换时间间隔
- current:{ type:Number, default:0 },// 初始化时,默认显示第几项
- autoplay:{ type:Boolean, default:true },// 是否自动切换
- indicatorDots: { type: Boolean, default: false },//是否显示面板指示点--默认关闭使用自定义指示器mode设置指示器,原生指示器为true时 则不显示自定义指示器
- indicatorColor:{ type:String, default:'rgba(0,0,0,0.3)' },// 指示点颜色
- indicatorActiveColor: { type: String, default: '#F1F1F1' },// 选中项指示点颜色
- },
- data() {
- return {
- swiperList:[],//列表数据
- videoContent:'',//视频实例
- videoPlaySataus:false, //视频播放状态---默认禁用
- activeCurrent:0,//当前选中索引
- swiperHeight:0, //轮播图高度
- moveX:0,
- }
- },
- watch: {
- height:{//swiper高度
- handler(newValue) {
- this.swiperHeight = newValue
- },
- immediate:true
- },
- current:{//初始化选中项
- handler(newValue) {
- this.activeCurrent = newValue
- },
- immediate:true
- },
- list:{//初始化数据列表--- 处理vue不能直接改变prpos属性
- handler(newValue) {
- this.swiperList = newValue || []
- },
- immediate:true
- },
- fullScreen:{
- handler(newValue) {
- if(this.fullScreen){//全屏设置---默认初始化设置一次
- uni.getSystemInfo({
- success:(e)=>{
- console.log('e',e);
- this.swiperHeight = e.screenHeight - this.navHeight
- // #ifdef APP-PLUS || MP-WEIXIN
- this.swiperHeight = e.screenHeight - this.navHeight - e.statusBarHeight
- // #endif
- }
- })
- }else{
- this.swiperHeight = this.height
- }
- },
- immediate:true
- }
- },
- methods: {
- play(e){
- this.videoPlaySataus = true
- },
- pause(){
- this.videoPlaySataus = false
- },
- timeupdate(e){//播放进度变化时触发--更新播放缓存
- this.$set(this.swiperList[this.activeCurrent],'currentTime',e.detail.currentTime)
- },
- clickItem(index){
- if(this.list.length>0){
- this.$emit('clickItem',this.list[index])
- }
- },
- change(e){//轮播改变触发
- try{// 切换前暂停之前视频
- let preSwiper = this.swiperList[this.activeCurrent]
- if(preSwiper.type==='video'){
- uni.createVideoContext(`video_${this.activeCurrent}`,this).pause();
- }
- }catch(e){
- //TODO handle the exception
- }
- this.videoPlaySataus = false //自动切换关闭视频播放状态
- this.activeCurrent = e.detail.current;
- this.$emit('change',e)
- },
- animationfinish(e){//动画结束后调用
- this.moveX = 0
- this.$emit('animationfinish',e)
- },
- transition(e){//滑动
- // #ifdef APP-PLUS
- this.moveX = e.detail.dx
- // #endif
- }
- }
- }
- </script>
- <style lang="scss" scoped>
- .swiperContent{//容器
- width:100%;
- position: relative;
- // background-color: #ccc;
- .z-screen-swiper {//轮播图
- min-height: 320rpx;
- // background-color: rgb(211, 235, 107); //--调试样式
- box-sizing: border-box;
- .z-swiper-item{
- box-sizing: border-box;
- overflow: initial;
- .swiper-box{//轮播图内容
- // background-color: #e7ca8f;//--调试样式
- // background-color: rgba(0,0,0,0.1);//swiper当前项 背景色---已改为配置
- box-sizing: border-box;
- width: 100%;
- height: 100%;
- overflow: hidden;
- display: flex;
- flex-direction: column;
- justify-content: space-between;
- position: relative;
- color: #FFF;
- .swiper-top{
- top: 0;
- // background-color: rgba(0,0,0,0.2);//背景色---已改为配置
- }
- .swiper-content{
- // background-color: rgb(61, 41, 175);
- flex: 1;
- display: flex;
- flex-direction: column;
- justify-content: center;
- image{
- width:100%;
- height: 100%;
- max-height: 100%;
- }
- video {// 视频默认不全屏高度---防止全屏swiper滑动切换
- width: 100%;
- max-height: 100%;
- // pointer-events: auto;
- }
- }
- .swiper-fotter{
- bottom: 0;
- // background-color: rgba(0, 0, 0, 0.2); //背景色---已改为配置
- }
- .isFloat{//是否浮动 顶部、底部定位
- position: absolute;
- left: 0;
- right: 0;
- z-index: 999;
- }
- }
- }
- }
- .effect3D{//3d模式样式
- .z-swiper-item{//3d模式基础样式
- .swiper-box{
- border-radius: 10rpx;
- opacity: 0.7;
- transition: all 0.1s ease-in 0s;
- }
- }
- &.effect3D-X{
- .z-swiper-item{ //选项卡间隔
- padding: 0 10rpx;
- }
- .swiper-box{
- transform: scale(1,0.9);
- }
- }
- &.effect3D-Y{
- .z-swiper-item{ //选项卡间隔
- padding:10rpx 0;
- }
- .swiper-box{
- transform: scale(0.9,1);
- }
- }
- .active-swiper{//选中样式恢复
- .swiper-box{
- transform:initial;
- opacity: 1;
- transition: all 0.1s ease-in 0s;
- }
- }
-
- }
- .dot{//指示器
- position: absolute;
- // z-index: 9999;
- display: flex;
- color: #FFF;
- .dotItem{//指示器 颜色与形状
- background-color: #fff;
- font-size: 24rpx;
- color: #e2e2e2;
- margin-right: 10rpx;
- &.default{ /*默认条状 */
- height: 8rpx;
- width: 40rpx;
- }
- &.circle{ /* 圆 */
- height: 20rpx;
- width: 20rpx;
- border-radius: 50%;
- }
- &.index{ /* 数字索引 */
- height: 30rpx;
- width: 30rpx;
- display: flex;
- justify-content: center;
- align-content: center;
- border-radius: 50%;
- }
- &.defautActive{//选中项设置
- transition: background-color 0.3s ease-out 0s; //选中动画
- }
- &.round{ /* 弧形 */
- height: 20rpx;
- width: 20rpx;
- border-radius: 50%;
- &.defautActive{//弧形选中项设置
- width: 60rpx;
- height: 20rpx;
- border-radius: 10px;
- transition: background-color 0.3s ease-out 0s; //
- }
- }
- }
- // 定位位置
- &.verticalDot{//垂直方向 只写了支持右侧定位
- right: 20rpx;
- top: 50%;
- transform: translateY(-50%);
- display: block;
- margin: 0 !important;
- .dotItem{
- margin: 0;
- margin-bottom: 10rpx;
- &.round{ /* 弧形 */
- height: 20rpx;
- width: 20rpx;
- border-radius: 50%;
- &.defautActive{//弧形选中
- width: 20rpx;
- height: 60rpx;
- border-radius: 10px;
- }
- }
- }
- }
- &.bottomLeft{//左上角
- left: 20rpx;
- bottom: 20rpx;
- }
- &.bottomCenter{//
- left: 50%;
- bottom: 20rpx;
- transform: translateX(-50%);
- }
- &.bottomRight{
- right: 20rpx;
- bottom: 20rpx;
- }
- &.topLeft{
- left: 20rpx;
- top: 10rpx;
- }
- &.topCenter{
- left: 50%;
- top: 10rpx;
- transform: translateX(-50%);
- }
- &.topRight{
- right: 20rpx;
- top: 10rpx;
- }
- }
- }
- </style>
|