(一)vue实战——商品放大镜组件封装及效果实现

前言

本节内容以vue为基础,实现一个商品放大镜组件的封装,及动画效果实现,通过本节内容,我们也可以实现其它h5相关的功能需求。商品放大镜功能在实际开发中还是有广泛需求的,尤其在商城项目中,为了更好的使用该功能,作者将该商品放大镜功能封装为一个组件,便于使用和维护。效果如下:

正文

  • 创建一个商品放大镜的组件goods-magnifier-zoom.vue

  •  封装商品放大镜组件

说明:

①通过注册鼠标的移入、移出、移动事件,实现商品放大镜的效果

<div id="smallPic" @mouseover="handlerMouseOver" @mouseleave="handlerMouseLeave"
             @mousemove="handlerMouseMove">

 

②通过父子组件实现图片数据的传递

props: {
    imgList: {
      type: Array,
      required: true,
      default: [],
    },
  },

③使用scss实现样式布局设置

<style scoped lang="scss">

④完整组件封装实现 

<template>
  <div class="container">
    <div id="goodsZoom">
      <div id="zoomTop">
        <!--        小图框-->
        <div id="smallPic" @mouseover="handlerMouseOver" @mouseleave="handlerMouseLeave"
             @mousemove="handlerMouseMove">
          <img :src="smallImgSrc">
          <!--          蒙版元素-->
          <div id="mask" v-show="show"></div>
        </div>
        <!--        大图框-->
        <div id="bigPic" v-show="show">
          <img :src="bigImgSrc" id="bigImg">
        </div>
      </div>
      <div id="zoomBottom">
        <a href="javascript:;" class="prev" @click="handlerPrev"> < </a>
        <div id="picList">
          <ul>
            <li v-for="(item,index) in imgList" @click="thumbnailClick(item)">
              <img :src="item.s">
            </li>
          </ul>
        </div>
        <a href="javascript:;" class="next" @click="handlerNext"> > </a>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: "goods-magnifier-zoom",
  props: {
    imgList: {
      type: Array,
      required: true,
      default: [],
    },
  },
  data() {
    return {
      show: false,//是否显示
      bigImgSrc: '',
      smallImgSrc: '',
      start: 0,
    }
  },
  created() {
    if (this.imgList.length > 0) {
      this.bigImgSrc = this.imgList[0].b;
      this.smallImgSrc = this.imgList[0].s;
    }

  },
  methods: {
    //鼠标移入事件
    handlerMouseOver() {
      this.show = true;
    },
    //鼠标移出事件
    handlerMouseLeave() {
      this.show = false;
    },
    //鼠标移动事件
    handlerMouseMove(data) {
      const smallPic = document.getElementById("smallPic");
      const bigPic = document.getElementById("bigPic");
      const bigImg = document.getElementById("bigImg");
      const zoomTop = document.getElementById("zoomTop");
      const mask = document.getElementById("mask");
      //蒙版边界设置
      let left = data.clientX - smallPic.getBoundingClientRect().left - mask.offsetWidth / 2;
      let top = data.clientY - smallPic.getBoundingClientRect().top - mask.offsetHeight / 2;
      //边界判断
      if (left < 0) {
        left = 0;
      } else if (left > smallPic.clientWidth - mask.offsetWidth) {
        left = smallPic.clientWidth - mask.offsetWidth;
      }
      if (top < -1) {
        top = -1;
      } else if (top > smallPic.clientHeight - mask.offsetHeight) {
        top = smallPic.clientHeight - mask.offsetHeight;
      }
      mask.style.left = left + "px";
      mask.style.top = top + "px";
      let scale = (smallPic.clientWidth - mask.offsetWidth) / (bigImg.offsetWidth - bigPic.clientWidth);
      console.log(scale);
      bigImg.style.left = -left / scale + "px";
      bigImg.style.top = -top / scale + "px";
    },
    //缩略图点击效果
    thumbnailClick(data) {
      this.bigImgSrc = data.b;
      this.smallImgSrc = data.s;
    },
    //点击前一个
    handlerPrev() {
      let ul = document.querySelector('#goodsZoom #zoomBottom #picList ul');
      let liNodes = document.querySelectorAll('#goodsZoom #zoomBottom #picList li');
      if (liNodes.length === 0) {
        return;
      }
      //步长
      let step = (liNodes[0].offsetWidth + 20) * 2;
      this.start -= step;
      if (this.start < 0) {
        this.start = 0;
      }
      ul.style.left = -this.start + "px";
    },
    //点击下一个
    handlerNext() {
      let ul = document.querySelector('#goodsZoom #zoomBottom #picList ul');
      let liNodes = document.querySelectorAll('#goodsZoom #zoomBottom #picList li');
      if (liNodes.length === 0) {
        return;
      }
      //步长
      let step = (liNodes[0].offsetWidth + 20) * 2;
      //总体运动的距离值 = ul的宽度 - div框的宽度 = (图片的总数 - div中显示的数量) * (li的宽度 + 20)
      let endPosition = (liNodes.length - 5) * (liNodes[0].offsetWidth + 20);
      this.start += step;
      if (this.start > endPosition) {
        this.start = endPosition;
      }
      ul.style.left = -this.start + "px";
    },
  },
};
</script>

<style scoped lang="scss">
.container {
  margin: 5px 0 15px;
  overflow: hidden;

  #goodsZoom {
    #zoomTop {
      width: 400px;
      position: relative;

      #smallPic {
        width: 400px;
        height: 400px;
        border: 1px solid #dfdfdf;
        position: relative;

        img {

        }

        #mask {
          width: 200px;
          height: 200px;
          background: rgba(255, 255, 255, .5);
          border: 1px solid #ddd;
          position: absolute;
          left: 0px;
          top: -1px;
        }
      }

      #bigPic {
        width: 400px;
        height: 400px;
        border: 1px solid #ddd;
        left: 420px;
        top: 0px;
        position: absolute;
        overflow: hidden;

        #bigImg {
          width: 800px;
          height: 800px;
          position: absolute;
          left: 0px;
          top: 0px;
        }
      }
    }

    #zoomBottom {
      width: 400px;
      margin-top: 5px;

      a {
        width: 10px;
        height: 54px;
        border: 1px solid #ccc;
        background: #ebebeb;
        text-align: center;
        line-height: 54px;
        float: left;
        text-decoration: none;

        &:first-child {
          margin-right: 4px;
        }
      }

      #picList {
        width: 372px;
        height: 56px;
        float: left;
        overflow: hidden;
        position: relative;

        ul {
          white-space: nowrap;
          font-size: 0px;
          position: absolute;
          left: 0px;
          transition: 0.5s;

          li {
            width: 50px;
            height: 50px;
            border: 1px solid #ccc;
            padding: 2px;
            margin-right: 20px;
            display: inline-block;

            img {
              width: 50px;
              height: 50px;
            }
          }
        }
      }
    }
  }
}
</style>
  • 创建一个测试页面GoodsZoom.vue,使用components引入组件 

①引入组件

import goodsMagnifierZoom from '@/components/goods-magnifier-zoom.vue';

export default {
  name: "GoodsZoom",
  components: {
    goodsMagnifierZoom: goodsMagnifierZoom,
  }
}

 

②使用组件

<goods-magnifier-zoom :imgList="imgList"></goods-magnifier-zoom>

③完整代码实现

<template>
  <div class="container">
    <div class="title">
      <span>商品放大镜</span>
      <el-divider direction="vertical"></el-divider>
      <router-link to="home">
        <span style="font-size: 18px;">退出</span>
      </router-link>
    </div>
    <el-divider>Test Staring</el-divider>
    <goods-magnifier-zoom :imgList="imgList"></goods-magnifier-zoom>
  </div>
</template>

<script>
import goodsMagnifierZoom from '@/components/goods-magnifier-zoom.vue';

export default {
  name: "GoodsZoom",
  data() {
    return {
      imgList: [
        {b: require('@/assets/nav/b1.png'), s: require('@/assets/nav/s1.png')},
        {b: require('@/assets/nav/b2.png'), s: require('@/assets/nav/s2.png')},
        {b: require('@/assets/nav/b3.png'), s: require('@/assets/nav/s3.png')},
        {b: require('@/assets/nav/b1.png'), s: require('@/assets/nav/s1.png')},
        {b: require('@/assets/nav/b2.png'), s: require('@/assets/nav/s2.png')},
        {b: require('@/assets/nav/b3.png'), s: require('@/assets/nav/s3.png')},
        {b: require('@/assets/nav/b1.png'), s: require('@/assets/nav/s1.png')},
        {b: require('@/assets/nav/b2.png'), s: require('@/assets/nav/s2.png')},
        {b: require('@/assets/nav/b3.png'), s: require('@/assets/nav/s3.png')},
        {b: require('@/assets/nav/b1.png'), s: require('@/assets/nav/s1.png')},
        {b: require('@/assets/nav/b2.png'), s: require('@/assets/nav/s2.png')},
        {b: require('@/assets/nav/b3.png'), s: require('@/assets/nav/s3.png')},
        {b: require('@/assets/nav/b1.png'), s: require('@/assets/nav/s1.png')},
        {b: require('@/assets/nav/b2.png'), s: require('@/assets/nav/s2.png')},
        {b: require('@/assets/nav/b3.png'), s: require('@/assets/nav/s3.png')}
      ],
    }
  },
  components: {
    goodsMagnifierZoom: goodsMagnifierZoom,
  }
}
</script>

<style scoped lang="scss">
.container {
  padding: 10px;
  overflow: hidden;

  .title {
    font-size: 20px;
    font-weight: bold;
  }
}

</style>

  • 启动项目 
  • 访问页面测试组件效果

①默认效果

 ②鼠标移入效果

③鼠标移动效果

④点击缩略图,切换商品

⑤切换缩略图

结语

至此,关于本节内容到这里就结束了,我们下期见。。。记得点赞、关注、收藏,你的支持就是我最大的创作动力。

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

厉害哥哥吖

您的支持是我创作下去的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值