基于ant design vue +swiper做的轮播放大功能

<template>
  <div class="goods-swiper-box" :style="{ width: boxWidth + 'px' }">
    <div
      class="image-box"
      :style="{
        width: boxWidth + 'px',
        height: boxHeight + 'px',
      }"
    >
      <van-swipe
        class="swiper"
        :autoplay="autoPlayFlag ? '' : 3000"
        @change="bigImgChange"
        :show-indicators="false"
        ref="topImageSwiper"
      >
        <van-swipe-item
          class="inner-image-box"
          :style="{
            width: boxWidth + 'px',
            height: boxHeight + 'px',
          }"
          v-for="(item, index) in imageList || ['', '']"
          :key="item.picID"
        >
          <div
            class="image-box-inner"
            :class="'box-image' + index"
            :key="item.picID"
            :style="{
              height: boxHeight + 'px',
              'line-height': boxHeight + 'px',
            }"
          >
            <img
              :src="item.picUrl"
              :class="'image' + index"
              alt=""
              :ref="'midelImg' + index"
              @mouseover="handOver"
              @mouseout="handOut"
            />
          </div>
        </van-swipe-item>
      </van-swipe>
      <div
        v-show="showMoveBox"
        class="swiper-shadow"
        :style="{
          width: boxWidth + 'px',
          height: boxHeight + 'px',
        }"
      >
        <div
          class="swiper-img-box"
          :style="bigBoxStyle"
          @mousemove="handMove"
          @mouseover="handOver"
          @mouseout="handOut"
        >
          <img :src="activeImgUrl" alt="" :style="bigBoxStyle" />
          <div
            class="shadow"
            :style="shandowStyle"
            @click="showImagePrivew"
          ></div>
          <div class="top-btn top-prev">
            <img src="@/assets/image/back.png" alt="" @click="topChange(-1)" />
          </div>
          <div class="top-btn top-next">
            <img src="@/assets/image/next.png" alt="" @click="topChange(1)" />
          </div>
        </div>
      </div>
      <div
        v-show="showMoveBox"
        class="big-image-box"
        :style="{
          width: boxWidth + 'px',
          height: boxHeight + 'px',
        }"
      >
        <!-- v-show="showMoveBox" -->
        <div class="inner-big-box" :style="bigBoxStyle">
          <img
            :src="activeImgUrl"
            alt=""
            :style="{ ...bigImgStyle, ...moveBigStyle }"
            class=""
          />
        </div>
      </div>
    </div>
    <div class="imgTip" :style="{ width: boxWidth + 'px' }">
      {{
        showMoveBox
          ? $t("detailPage.afterMoveTip")
          : $t("detailPage.beforeMoveTip")
      }}
    </div>
    <div class="small-image-box">
      <a-icon
        class="bottom-btn bottom-prev"
        type="left"
        :style="{
          height: boxHeight / smallMultiple + 'px',
          lineHeight: boxHeight / smallMultiple + 'px',
        }"
        @click="smallImgChange(-1)"
      />
      <swiper
        class="swiper"
        :options="swiperOption"
        ref="bottomImageSwiper"
        :style="{
          height: boxHeight / smallMultiple + 'px',
          width: boxWidth - 100 + 'px',
        }"
      >
        <swiper-slide
          v-for="(item, index) in imageList || ['', '']"
          :key="item.picID"
          :class="activeIndex == index ? 'small-img-active' : ''"
        >
          <img alt="" :src="item.picUrl" @click="jumpImage(index)" />
        </swiper-slide>

        <div class="swiper-pagination" slot="pagination"></div>
      </swiper>
      <a-icon
        class="bottom-btn bottom-next"
        @click="smallImgChange(1)"
        :style="{
          height: boxHeight / smallMultiple + 'px',
          lineHeight: boxHeight / smallMultiple + 'px',
        }"
        type="right"
      />
    </div>
  </div>
</template>

<script>
import { Carousel } from "ant-design-vue";
import swiperMixins from "./swiper-mixin";
export default {
  mixins: [swiperMixins],
  components: {
    "a-carousel": Carousel,
  },
};
</script>

<style lang="scss" scoped>
.goods-swiper-box {
  .image-box {
    background-color: #fff;
    position: relative;

    .swiper-shadow {
      background-color: #fff;
      position: absolute;
      top: 0;
      left: 0;
      z-index: 90;
      &:hover .top-btn {
        display: block;
      }
      .top-btn {
        position: absolute;
        top: 50%;
        transform: translateY(-50%);
        display: none;
        z-index: 91;
      }
      .top-next {
        right: 0;
      }
      .swiper-img-box {
        position: absolute;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        margin: auto;
        .shadow {
          position: absolute;
          background-color: gray;
          opacity: 0.4;
          z-index: 91;
          top: 0;
          left: 0;
          width: 100px;
          height: 100px;
        }
        img {
          height: 100%;
          width: 100%;
        }
      }
    }
    .inner-image-box {
      display: flex;
      border-radius: 8px;
      overflow: hidden;
      justify-content: center;
      align-content: center;
      background-color: #fff;
      .image-box-inner {
        position: absolute;
        height: auto;
        img {
          width: auto;
          height: auto;
          max-height: 100%;
          max-width: 100%;
        }
      }
    }

    .big-image-box {
      position: absolute;
      left: 105%;
      top: 0;
      display: flex;
      z-index: 999;
      justify-content: center;
      align-content: center;
      overflow: hidden;
      .inner-big-box {
        position: absolute;
        top: 0;
        left: 0;
        bottom: 0;
        right: 0;
        margin: auto;
        overflow: hidden;
        img {
          position: absolute;
        }
      }
    }
  }
  .imgTip {
    line-height: 32px;
    margin: 10px 0;
    text-align: center;
    width: 566px;
  }
  .small-image-box {
    width: 100%;
    display: flex;
    justify-content: space-between;
    align-content: center;
    .bottom-btn {
      width: 50px;
      text-align: center;
    }
    .small-img-active {
      border: 1px solid #333;
      border-radius: 4px;
    }
    ::v-deep .swiper-slide {
      display: flex;
      align-items: center;
      justify-content: center;
      cursor: pointer;
      img {
        width: auto;
        height: auto;
        max-width: 100%;
        max-height: 100%;
      }
    }
  }
}
</style>
export default {
    props: {
        boxWidth: {
            type: Number,
            default:566
        },
        boxHeight: {
            type: Number,
            default:566
        },
        imageList: {
            type: Array,
            default: () => {
                return [
                    {
                        altPmt: "",
                        picID: "vueTest/1/produce-image_69f8c9a6-61c1-43e7-9456-234a2c6b2839_173031x.png",
                        picUrl: "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fc-ssl.duitang.com%2Fuploads%2Fitem%2F202002%2F09%2F20200209191658_jmu8V.jpeg&refer=http%3A%2F%2Fc-ssl.duitang.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1653210861&t=d6141f92fa3f93e6baeab3372266389f",
                        thnUrl: "",
                    },
                    {
                        altPmt: "",
                        picID: "vueTest/1/produce-image_69f8c9a6-61",
                        picUrl: "https://sqbucket-us.oss-us-west-1.aliyuncs.com/vueTest/1/produce-image_116b3911-0f27-4894-821f-940088ba0ea7_173031x.png",
                        thnUrl: "",
                    },
                   
                    {
                        altPmt: '',
                        picUrl: 'https://w.wallhaven.cc/full/j3/wallhaven-j379gy.png',
                        thnUrl: "",
                        picID: 2
                    },
                    {
                        altPmt: '',
                        picUrl: 'http://sqbucket-us.oss-us-west-1.aliyuncs.com/vueTest/1/produce-image_dd9c2786-459e-4904-bb12-f9f5507665b4_139686x.png',
                        thnUrl: "",
                        picID: 3
                    }, {
                        altPmt: '',
                        picUrl: 'http://sqbucket-us.oss-us-west-1.aliyuncs.com/vueTest/1/produce-image_73293336-fca8-4b67-9dee-253bd189a087_121645x.png',
                        thnUrl: "",
                        picID: 4
                    }
                ]
            }
        },
        multiple: {
            type: Number,
            default:2
    },
    smallMultiple: {
      type: Number,
      default:5
        },
        smallPosition: {
            type: String,
            default:'bottom'
        },
        swiperOption: {
            type: Object,
            default: () => {
                return {
                    slidesPerView: 4,
                  loop: false,
                    spaceBetween: 16,
                    prevButton: ".swiper-button-prev",
                  nextButton: ".swiper-button-next",
                  on: {
                    click: function (index) {
                  //  console.log(index)
                    }
                  }
                }
            }
          },
    },
    data() {
        return {
            swiperOptionTop: {
              spaceBetween: 30,
              centeredSlides: true,
          autoplay: {
            delay: 2500,
            disableOnInteraction: false
          },
          pagination: {
            el: '.swiper-pagination',
            clickable: true
          },
          navigation: {
            nextEl: '.swiper-button-next',
            prevEl: '.swiper-button-prev'
            },
          loop:true
              },
            activeIndex: 0,
            autoPlayFlag: false,
            activeImgUrl: "",
            showMoveBox: false,
            shandowStyle: {
                width: '283px',
                height: '283px',
                transform: null,
                x: 283,
                y:283,
            },
            bigBoxStyle: {
                width: '566px',
                height:'566px',  
            },
            bigImgStyle: {
                width: '1132px',
                height:'1132px',  
            },
          initPlace: null,
          outPlace:null,
            moveBigStyle: {
                top: 0,
                left: 0,
            },
            timer: null,
            imageLeftPosition: 0,
          imageEndPosition: 0,
          ratio: 1,
            l:0,
        }
  },
  watch: {
    // imageList: {
    //   handler(val) {
    //     var that = this;
    //   //   this.$nextTick(() => {
    //   //       this.$refs.topImageSwiper.resize()
    //   //  })
    //     setTimeout(() => {
    //       console.log("宝宝行业规范行业",that.$refs.topImageSwiper)
    //       that.$refs.topImageSwiper.resize()
    //     }, 500);
    //   },
    //   // deep: true,
    //   immediate:true
    // },

    },
    created () {
      this.activeImgUrl = this.imageList[this.activeIndex].picUrl;
  },
    methods: {
      handMove(e) {
        this.initPlace = this.$el.getElementsByClassName('swiper-img-box')[0].getBoundingClientRect();
            let objX = e.clientX - this.initPlace.left;
            let objY = e.clientY - this.initPlace.top;
            // 计算初始的遮罩左上角的坐标
            let maskX = objX - this.shandowStyle.x/this.multiple;
            let maskY = objY -  this.shandowStyle.y/this.multiple;
            // 判断是否超出界限,并纠正
            maskY = maskY < 0 ? 0 : maskY;
            maskX = maskX <0 ? 0 : maskX;
            if (maskY + this.shandowStyle.y >= this.initPlace.height) {
              maskY = this.initPlace.height - this.shandowStyle.y;
            }
            if (maskX + this.shandowStyle.x >= this.initPlace.width) {
              maskX = this.initPlace.width - this.shandowStyle.x
            }
            // 遮罩移动
        this.shandowStyle.transform = `translate(${maskX}px, ${maskY}px)`;
            // 背景图移动
            this.moveBigStyle.left = - maskX * this.multiple + "px";
            this.moveBigStyle.top = - maskY * this.multiple +"px";
      },
      handOut() {
       this.showMoveBox = false;
     this.autoPlayFlag = false;
     },
      handOver() {
            this.getWidthAndHeight();
            this.showMoveBox = true;
            this.autoPlayFlag = true;
       },
      bigImgChange(index) {
        this.activeIndex = index;
        this.activeImgUrl = this.imageList[this.activeIndex].picUrl;
      },
      getWidthAndHeight() {
        this.ratio = this.$refs['midelImg' + this.activeIndex][0].naturalWidth / this.$refs['midelImg' + this.activeIndex][0].naturalHeight;
        let width = 0, height = 0;
        if (this.ratio == this.boxWidth/this.boxHeight) {
          height = this.boxHeight;
          width = this.boxWidth;
        } else if (this.ratio < this.boxWidth/this.boxHeight) {
          height = this.boxHeight;
          width = this.boxHeight * this.ratio;
        } else {
          height = this.boxWidth / this.ratio;
          width = this.boxWidth;
        }
        this.bigBoxStyle = {
          width:width+'px',
          height:height+"px"
        }
        this.shandowStyle = {
          width:width/this.multiple+'px',
          height:height/this.multiple + "px",
          transform: null,
          x: width/this.multiple,
         y:height/this.multiple
        },
          this.bigImgStyle = {
          width: width * this.multiple + 'px',
           height:height*this.multiple+'px'
          }
      },
      topChange(val) {
        if (val == -1) {
          this.$refs.topImageSwiper.prev()
        } else {
          this.$refs.topImageSwiper.next()
        }
      },
      smallImgChange(val) {
        if (val == -1) {
          this.$refs.bottomImageSwiper.$swiper.slidePrev()
        } else {
          this.$refs.bottomImageSwiper.$swiper.slideNext()
        }
      },
      jumpImage(index) {
        this.activeIndex = index;
        this.$refs.topImageSwiper.swipeTo(index)
      },
      showImagePrivew() {
        this.$emit('showImagePrivew', this.activeIndex)
      }
    }
  
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值