| 
						 | 
						<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>
  |