bug
jiangping
2023-11-07 64b432916af9c9218ab3f3eca614e26c542142ae
minipro_standard/uni_modules/uview-ui/components/u-swiper/u-swiper.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,255 @@
<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>