You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							502 lines
						
					
					
						
							12 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							502 lines
						
					
					
						
							12 KiB
						
					
					
				
								<template>
							 | 
						|
								  <view>
							 | 
						|
								    <view class="ui-swiper" :class="[props.mode, props.bg, props.ui]">
							 | 
						|
								      <swiper
							 | 
						|
								        :circular="props.circular"
							 | 
						|
								        :current="state.cur"
							 | 
						|
								        :autoplay="props.autoplay && !state.videoPlaySataus"
							 | 
						|
								        :interval="props.interval"
							 | 
						|
								        :duration="props.duration"
							 | 
						|
								        @transition="transition"
							 | 
						|
								        @animationfinish="animationfinish"
							 | 
						|
								        :style="customStyle"
							 | 
						|
								        @change="swiperChange"
							 | 
						|
								      >
							 | 
						|
								        <swiper-item
							 | 
						|
								          class="swiper-item"
							 | 
						|
								          v-for="(item, index) in props.list"
							 | 
						|
								          :key="index"
							 | 
						|
								          :class="{ cur: state.cur == index }"
							 | 
						|
								          @tap="onSwiperItem(item)"
							 | 
						|
								        >
							 | 
						|
								          <view class="ui-swiper-main">
							 | 
						|
								            <image
							 | 
						|
								              v-if="item.type === 'image'"
							 | 
						|
								              class="swiper-image"
							 | 
						|
								              :mode="props.imageMode"
							 | 
						|
								              :src="item.src"
							 | 
						|
								              width="100%"
							 | 
						|
								              height="100%"
							 | 
						|
								              @load="onImgLoad"
							 | 
						|
								            ></image>
							 | 
						|
								            <su-video
							 | 
						|
								              v-else
							 | 
						|
								              :ref="(el) => (refs.videoRef[`video_${index}`] = el)"
							 | 
						|
								              :poster="sheep.$url.cdn(item.poster)"
							 | 
						|
								              :src="sheep.$url.cdn(item.src)"
							 | 
						|
								              :index="index"
							 | 
						|
								              :moveX="state.moveX"
							 | 
						|
								              :initialTime="item.currentTime || 0"
							 | 
						|
								              :height="seizeHeight"
							 | 
						|
								              @videoTimeupdate="videoTimeupdate"
							 | 
						|
								            ></su-video>
							 | 
						|
								          </view>
							 | 
						|
								        </swiper-item>
							 | 
						|
								      </swiper>
							 | 
						|
								      <template v-if="!state.videoPlaySataus">
							 | 
						|
								        <view class="ui-swiper-dot" :class="props.dotStyle" v-if="props.dotStyle != 'tag'">
							 | 
						|
								          <view
							 | 
						|
								            class="line-box"
							 | 
						|
								            v-for="(item, index) in props.list"
							 | 
						|
								            :key="index"
							 | 
						|
								            :class="[state.cur == index ? 'cur' : '', props.dotCur]"
							 | 
						|
								          ></view>
							 | 
						|
								        </view>
							 | 
						|
								        <view class="ui-swiper-dot" :class="props.dotStyle" v-if="props.dotStyle == 'tag'">
							 | 
						|
								          <view
							 | 
						|
								            class="ui-tag radius-lg"
							 | 
						|
								            :class="[props.dotCur]"
							 | 
						|
								            style="pointer-events: none; padding: 0 10rpx"
							 | 
						|
								          >
							 | 
						|
								            <view style="transform: scale(0.7)">{{ state.cur + 1 }} / {{ props.list.length }}</view>
							 | 
						|
								          </view>
							 | 
						|
								        </view>
							 | 
						|
								      </template>
							 | 
						|
								    </view>
							 | 
						|
								  </view>
							 | 
						|
								</template>
							 | 
						|
								
							 | 
						|
								<script setup>
							 | 
						|
								  /**
							 | 
						|
								   * 轮播组件
							 | 
						|
								   *
							 | 
						|
								   * @property {Boolean} circular = false  	- 是否采用衔接滑动,即播放到末尾后重新回到开头
							 | 
						|
								   * @property {Boolean} autoplay = true  	- 是否自动切换
							 | 
						|
								   * @property {Number} interval = 5000  		- 自动切换时间间隔
							 | 
						|
								   * @property {Number} duration = 500  		- 滑动动画时长,app-nvue不支持
							 | 
						|
								   * @property {Array} list = [] 				- 轮播数据
							 | 
						|
								   * @property {String} ui = ''  				- 样式class
							 | 
						|
								   * @property {String} mode  				- 模式
							 | 
						|
								   * @property {String} dotStyle  			- 指示点样式
							 | 
						|
								   * @property {String} dotCur= 'ui-BG-Main' 	- 当前指示点样式,默认主题色
							 | 
						|
								   * @property {String} bg  					- 背景
							 | 
						|
								   * @property {String} height = 300  		- 组件高度
							 | 
						|
								   * @property {String} imgHeight = 300   	- 图片高度
							 | 
						|
								   *
							 | 
						|
								   * @example list = [{url:'跳转路径',urlType:'跳转方式',type:'轮播类型',src:'轮播内容地址',poster:'视频必传'}]
							 | 
						|
								   */
							 | 
						|
								
							 | 
						|
								  import { reactive, computed } from 'vue';
							 | 
						|
								  import sheep from '@/sheep';
							 | 
						|
								  import { clone } from 'lodash-es';
							 | 
						|
								
							 | 
						|
								  // 数据
							 | 
						|
								  const state = reactive({
							 | 
						|
								    imgHeight: 0,
							 | 
						|
								    cur: 0,
							 | 
						|
								    moveX: 0,
							 | 
						|
								    videoPlaySataus: false,
							 | 
						|
								    heightList: [],
							 | 
						|
								  });
							 | 
						|
								
							 | 
						|
								  const refs = reactive({
							 | 
						|
								    videoRef: {},
							 | 
						|
								  });
							 | 
						|
								
							 | 
						|
								  // 接收参数
							 | 
						|
								
							 | 
						|
								  const props = defineProps({
							 | 
						|
								    circular: {
							 | 
						|
								      type: Boolean,
							 | 
						|
								      default: true,
							 | 
						|
								    },
							 | 
						|
								    autoplay: {
							 | 
						|
								      type: Boolean,
							 | 
						|
								      default: false,
							 | 
						|
								    },
							 | 
						|
								    interval: {
							 | 
						|
								      type: Number,
							 | 
						|
								      default: 3000,
							 | 
						|
								    },
							 | 
						|
								    duration: {
							 | 
						|
								      type: Number,
							 | 
						|
								      default: 500,
							 | 
						|
								    },
							 | 
						|
								    mode: {
							 | 
						|
								      type: String,
							 | 
						|
								      default: 'default',
							 | 
						|
								    },
							 | 
						|
								    imageMode: {
							 | 
						|
								      type: String,
							 | 
						|
								      default: 'scaleToFill',
							 | 
						|
								    },
							 | 
						|
								    list: {
							 | 
						|
								      type: Array,
							 | 
						|
								      default() {
							 | 
						|
								        return [];
							 | 
						|
								      },
							 | 
						|
								    },
							 | 
						|
								    dotStyle: {
							 | 
						|
								      type: String,
							 | 
						|
								      default: 'long', //default long tag
							 | 
						|
								    },
							 | 
						|
								    dotCur: {
							 | 
						|
								      type: String,
							 | 
						|
								      default: 'ss-bg-opactity-block',
							 | 
						|
								    },
							 | 
						|
								    bg: {
							 | 
						|
								      type: String,
							 | 
						|
								      default: 'bg-none',
							 | 
						|
								    },
							 | 
						|
								    height: {
							 | 
						|
								      type: Number,
							 | 
						|
								      default: 0,
							 | 
						|
								    },
							 | 
						|
								    imgHeight: {
							 | 
						|
								      type: Number,
							 | 
						|
								      default: 0,
							 | 
						|
								    },
							 | 
						|
								    imgTopRadius: {
							 | 
						|
								      type: Number,
							 | 
						|
								      default: 0,
							 | 
						|
								    },
							 | 
						|
								    imgBottomRadius: {
							 | 
						|
								      type: Number,
							 | 
						|
								      default: 0,
							 | 
						|
								    },
							 | 
						|
								    isPreview: {
							 | 
						|
								      type: Boolean,
							 | 
						|
								      default: false,
							 | 
						|
								    },
							 | 
						|
								    seizeHeight: {
							 | 
						|
								      type: Number,
							 | 
						|
								      default: 200,
							 | 
						|
								    },
							 | 
						|
								  });
							 | 
						|
								
							 | 
						|
								  // current 改变时会触发 change 事件
							 | 
						|
								  const swiperChange = (e) => {
							 | 
						|
								    if (e.detail.source !== 'touch' && e.detail.source !== 'autoplay') return;
							 | 
						|
								    state.cur = e.detail.current;
							 | 
						|
								    state.videoPlaySataus = false;
							 | 
						|
								    if (props.list[state.cur].type === 'video') {
							 | 
						|
								      refs.videoRef[`video_${state.cur}`].pausePlay();
							 | 
						|
								    }
							 | 
						|
								  };
							 | 
						|
								  // 点击轮播组件
							 | 
						|
								  const onSwiperItem = (item) => {
							 | 
						|
								    if (item.type === 'video') {
							 | 
						|
								      state.videoPlaySataus = true;
							 | 
						|
								    } else {
							 | 
						|
								      sheep.$router.go(item.url);
							 | 
						|
								      onPreview();
							 | 
						|
								    }
							 | 
						|
								  };
							 | 
						|
								
							 | 
						|
								  const onPreview = () => {
							 | 
						|
								    if (!props.isPreview) return;
							 | 
						|
								    let previewImage = clone(props.list);
							 | 
						|
								    previewImage.forEach((item, index) => {
							 | 
						|
								      if (item.type === 'video') {
							 | 
						|
								        previewImage.splice(index, 1);
							 | 
						|
								      }
							 | 
						|
								    });
							 | 
						|
								    uni.previewImage({
							 | 
						|
								      urls:
							 | 
						|
								        previewImage.length < 1
							 | 
						|
								          ? [props.src]
							 | 
						|
								          : previewImage.reduce((pre, cur) => {
							 | 
						|
								              pre.push(cur.src);
							 | 
						|
								              return pre;
							 | 
						|
								            }, []),
							 | 
						|
								      current: state.cur,
							 | 
						|
								      // longPressActions: {
							 | 
						|
								      //   itemList: ['发送给朋友', '保存图片', '收藏'],
							 | 
						|
								      //   success: function (data) {
							 | 
						|
								      //     console.log('选中了第' + (data.tapIndex + 1) + '个按钮,第' + (data.index + 1) + '张图片');
							 | 
						|
								      //   },
							 | 
						|
								      //   fail: function (err) {
							 | 
						|
								      //     console.log(err.errMsg);
							 | 
						|
								      //   },
							 | 
						|
								      // },
							 | 
						|
								    });
							 | 
						|
								  };
							 | 
						|
								  //
							 | 
						|
								
							 | 
						|
								  // swiper-item 的位置发生改变时会触发 transition
							 | 
						|
								  const transition = (e) => {
							 | 
						|
								    // #ifdef APP-PLUS
							 | 
						|
								    state.moveX = e.detail.dx;
							 | 
						|
								    // #endif
							 | 
						|
								  };
							 | 
						|
								
							 | 
						|
								  // 动画结束时会触发 animationfinish
							 | 
						|
								  const animationfinish = (e) => {
							 | 
						|
								    state.moveX = 0;
							 | 
						|
								  };
							 | 
						|
								
							 | 
						|
								  const videoTimeupdate = (e) => {
							 | 
						|
								    props.list[state.cur].currentTime = e.detail.currentTime;
							 | 
						|
								  };
							 | 
						|
								
							 | 
						|
								  // 自动计算高度
							 | 
						|
								  const customStyle = computed(() => {
							 | 
						|
								    let height;
							 | 
						|
								
							 | 
						|
								    // 固定高度情况
							 | 
						|
								    if (props.height !== 0) {
							 | 
						|
								      height = props.height;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    // 自动高度情况
							 | 
						|
								    if (props.height === 0) {
							 | 
						|
								      // 图片预加载占位高度
							 | 
						|
								      if (state.imgHeight !== 0) {
							 | 
						|
								        height = state.imgHeight;
							 | 
						|
								      } else if (props.seizeHeight !== 0) {
							 | 
						|
								        height = props.seizeHeight;
							 | 
						|
								      }
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    return {
							 | 
						|
								      height: height + 'rpx',
							 | 
						|
								    };
							 | 
						|
								  });
							 | 
						|
								
							 | 
						|
								  // 计算轮播图片最大高度
							 | 
						|
								  function onImgLoad(e) {
							 | 
						|
								    if (props.height === 0) {
							 | 
						|
								      let newHeight = (e.detail.height / e.detail.width) * 750;
							 | 
						|
								      if (state.imgHeight < newHeight) {
							 | 
						|
								        state.imgHeight = newHeight;
							 | 
						|
								      }
							 | 
						|
								    }
							 | 
						|
								  }
							 | 
						|
								</script>
							 | 
						|
								
							 | 
						|
								<style lang="scss" scoped>
							 | 
						|
								  .ui-swiper {
							 | 
						|
								    position: relative;
							 | 
						|
								
							 | 
						|
								    .ui-swiper-main {
							 | 
						|
								      width: 100%;
							 | 
						|
								      height: 100%;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    .ui-swiper-main .swiper-image {
							 | 
						|
								      width: 100%;
							 | 
						|
								      height: 100%;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    .ui-swiper-dot {
							 | 
						|
								      position: absolute;
							 | 
						|
								      width: 100%;
							 | 
						|
								      bottom: 20rpx;
							 | 
						|
								      height: 30rpx;
							 | 
						|
								      display: flex;
							 | 
						|
								      align-items: center;
							 | 
						|
								      justify-content: center;
							 | 
						|
								
							 | 
						|
								      &.default .line-box {
							 | 
						|
								        display: inline-flex;
							 | 
						|
								        border-radius: 50rpx;
							 | 
						|
								        width: 6px;
							 | 
						|
								        height: 6px;
							 | 
						|
								        border: 2px solid transparent;
							 | 
						|
								        margin: 0 10rpx;
							 | 
						|
								        opacity: 0.3;
							 | 
						|
								        position: relative;
							 | 
						|
								        justify-content: center;
							 | 
						|
								        align-items: center;
							 | 
						|
								
							 | 
						|
								        &.cur {
							 | 
						|
								          width: 8px;
							 | 
						|
								          height: 8px;
							 | 
						|
								          opacity: 1;
							 | 
						|
								          border: 0px solid transparent;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        &.cur::after {
							 | 
						|
								          content: '';
							 | 
						|
								          border-radius: 50rpx;
							 | 
						|
								          width: 4px;
							 | 
						|
								          height: 4px;
							 | 
						|
								          background-color: #fff;
							 | 
						|
								        }
							 | 
						|
								      }
							 | 
						|
								
							 | 
						|
								      &.long .line-box {
							 | 
						|
								        display: inline-block;
							 | 
						|
								        border-radius: 100rpx;
							 | 
						|
								        width: 6px;
							 | 
						|
								        height: 6px;
							 | 
						|
								        margin: 0 10rpx;
							 | 
						|
								        opacity: 0.3;
							 | 
						|
								        position: relative;
							 | 
						|
								
							 | 
						|
								        &.cur {
							 | 
						|
								          width: 24rpx;
							 | 
						|
								          opacity: 1;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        &.cur::after {
							 | 
						|
								        }
							 | 
						|
								      }
							 | 
						|
								
							 | 
						|
								      &.line {
							 | 
						|
								        bottom: 20rpx;
							 | 
						|
								
							 | 
						|
								        .line-box {
							 | 
						|
								          display: inline-block;
							 | 
						|
								          width: 30px;
							 | 
						|
								          height: 3px;
							 | 
						|
								          opacity: 0.3;
							 | 
						|
								          position: relative;
							 | 
						|
								
							 | 
						|
								          &.cur {
							 | 
						|
								            opacity: 1;
							 | 
						|
								          }
							 | 
						|
								        }
							 | 
						|
								      }
							 | 
						|
								
							 | 
						|
								      &.tag {
							 | 
						|
								        justify-content: flex-end;
							 | 
						|
								        position: absolute;
							 | 
						|
								        bottom: 20rpx;
							 | 
						|
								        right: 20rpx;
							 | 
						|
								      }
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    &.card {
							 | 
						|
								      .swiper-item {
							 | 
						|
								        width: 610rpx !important;
							 | 
						|
								        left: 70rpx;
							 | 
						|
								        box-sizing: border-box;
							 | 
						|
								        padding: 20rpx 0rpx 60rpx;
							 | 
						|
								        overflow: initial;
							 | 
						|
								      }
							 | 
						|
								
							 | 
						|
								      .swiper-item .ui-swiper-main {
							 | 
						|
								        width: 100%;
							 | 
						|
								        display: block;
							 | 
						|
								        height: 100%;
							 | 
						|
								        transform: scale(0.9);
							 | 
						|
								        transition: all 0.2s ease-in 0s;
							 | 
						|
								        position: relative;
							 | 
						|
								        background-size: cover;
							 | 
						|
								
							 | 
						|
								        .swiper-image {
							 | 
						|
								          height: 100%;
							 | 
						|
								        }
							 | 
						|
								      }
							 | 
						|
								
							 | 
						|
								      .swiper-item .ui-swiper-main::before {
							 | 
						|
								        content: '';
							 | 
						|
								        display: block;
							 | 
						|
								        background: inherit;
							 | 
						|
								        filter: blur(5px);
							 | 
						|
								        position: absolute;
							 | 
						|
								        width: 100%;
							 | 
						|
								        height: 100%;
							 | 
						|
								        top: 10rpx;
							 | 
						|
								        left: 10rpx;
							 | 
						|
								        z-index: -1;
							 | 
						|
								        opacity: 0.3;
							 | 
						|
								        transform-origin: 0 0;
							 | 
						|
								        transform: scale(1, 1);
							 | 
						|
								      }
							 | 
						|
								
							 | 
						|
								      .swiper-item.cur .ui-swiper-main {
							 | 
						|
								        transform: scale(1);
							 | 
						|
								        transition: all 0.2s ease-in 0s;
							 | 
						|
								      }
							 | 
						|
								
							 | 
						|
								      .ui-swiper-dot.tag {
							 | 
						|
								        position: absolute;
							 | 
						|
								        bottom: 85rpx;
							 | 
						|
								        right: 75rpx;
							 | 
						|
								      }
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    &.hotelCard {
							 | 
						|
								      .swiper-item {
							 | 
						|
								        width: 650rpx !important;
							 | 
						|
								        left: 30rpx;
							 | 
						|
								        box-sizing: border-box;
							 | 
						|
								        padding: 0rpx 0rpx 50rpx;
							 | 
						|
								        overflow: initial;
							 | 
						|
								      }
							 | 
						|
								
							 | 
						|
								      .swiper-item .ui-swiper-main {
							 | 
						|
								        width: 100%;
							 | 
						|
								        display: block;
							 | 
						|
								        height: 100%;
							 | 
						|
								        transform: scale(0.9);
							 | 
						|
								        opacity: 0.8;
							 | 
						|
								        transition: all 0.2s ease-in 0s;
							 | 
						|
								        position: relative;
							 | 
						|
								        background-size: cover;
							 | 
						|
								
							 | 
						|
								        .swiper-image {
							 | 
						|
								          width: 100%;
							 | 
						|
								          height: 400rpx;
							 | 
						|
								        }
							 | 
						|
								      }
							 | 
						|
								
							 | 
						|
								      .swiper-item .ui-swiper-main::before {
							 | 
						|
								        content: '';
							 | 
						|
								        display: block;
							 | 
						|
								        background: inherit;
							 | 
						|
								        filter: blur(5px);
							 | 
						|
								        position: absolute;
							 | 
						|
								        width: 100%;
							 | 
						|
								        height: 100%;
							 | 
						|
								        top: 10rpx;
							 | 
						|
								        left: 10rpx;
							 | 
						|
								        z-index: -1;
							 | 
						|
								        opacity: 0.3;
							 | 
						|
								        transform-origin: 0 0;
							 | 
						|
								        transform: scale(1, 1);
							 | 
						|
								      }
							 | 
						|
								
							 | 
						|
								      .swiper-item.cur .ui-swiper-main {
							 | 
						|
								        transform: scale(1);
							 | 
						|
								        transition: all 0.2s ease-in 0s;
							 | 
						|
								        opacity: 1;
							 | 
						|
								      }
							 | 
						|
								
							 | 
						|
								      .ui-swiper-dot {
							 | 
						|
								        display: none;
							 | 
						|
								      }
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    &.hotelDetail {
							 | 
						|
								      .swiper-item {
							 | 
						|
								        width: 690rpx !important;
							 | 
						|
								        left: 30rpx;
							 | 
						|
								        box-sizing: border-box;
							 | 
						|
								        padding: 20rpx 0rpx;
							 | 
						|
								        overflow: initial;
							 | 
						|
								      }
							 | 
						|
								
							 | 
						|
								      .swiper-item .ui-swiper-main {
							 | 
						|
								        width: 100%;
							 | 
						|
								        display: block;
							 | 
						|
								        height: 100%;
							 | 
						|
								        transform: scale(0.96);
							 | 
						|
								        transition: all 0.2s ease-in 0s;
							 | 
						|
								        position: relative;
							 | 
						|
								        background-size: cover;
							 | 
						|
								
							 | 
						|
								        .swiper-image {
							 | 
						|
								          height: 100%;
							 | 
						|
								        }
							 | 
						|
								      }
							 | 
						|
								
							 | 
						|
								      .swiper-item.cur .ui-swiper-main {
							 | 
						|
								        transform: scale(0.96);
							 | 
						|
								        transition: all 0.2s ease-in 0s;
							 | 
						|
								      }
							 | 
						|
								    }
							 | 
						|
								  }
							 | 
						|
								</style>
							 |