以下是最终的vue版本,光滑流畅,99%还原京东放大镜甚至更好,不会出现多次操作会变卡的问题

1.vue版本

6/23日更新,处理图片尺寸过小无法通过拖动实现放大移动效果的问题

7/18日更新,关于视频处理,不需要引入视频的小伙伴可以注释掉代码中关于视频插件的部分

//安装 视频插件
npm install vue-video-player


//main.js全局注册
import VideoPlayer from 'vue-video-player'
import 'video.js/dist/video-js.css'
Vue.use(VideoPlayer)
<template>
  <div id="magnifier" class="preview">
    <div
      class="small-box"
      @mouseover="smallBoxOver"
      @mousemove="smallBoxMove($event)"
      @mouseleave="smallLeave"
    >
      <VideoPlayer v-if="isShowVideo" class="videoPlayer" :video="videoObj"></VideoPlayer>
      <img :src="theImg" v-else />
      <span class="hover"></span>
    </div>
    <div class="thumbnail-box">
      <a class="btn btn-prev" @click="prev"></a>
      <a class="btn btn-next" @click="next"></a>

      <div class="list">
        <ul class="wrapper">
          <li
            class="item"
            v-for="(item, index) in pictureList"
            :key="index"
            @mouseover="chooseImg(item,index)"
            @mouseleave="leaveImg(index)"
            :class="activeIndex===index?'item-cur':''"
          >
            <img :src="item" />
          </li>
        </ul>
      </div>
    </div>
    <div class="big-box">
      <img :src="theImg" />
    </div>
  </div>
</template>

<script>
import $ from 'jquery'
import 'jquery'
import VideoPlayer from '@/components/video/video'
// import VideoPlayer from '@/components/video/simpleVideo'

export default {
  data() {
    return {
      theImg: '', // 当前选中的图片
      activeIndex: 0,
      isShowVideo: false,
      goodVideo: '',
      videoObj: {
        type: 'video/mp4',
        src: require('../../assets/video/jabil.mp4')
      },
      pictureList: [
        'http://mp.ofweek.com/Upload/News/Img/member645/201711/17170046839337.jpg',

        'http://image.buy.ccb.com/merchant/201703/904919627/1522929521661_4.jpg',

        'http://image5.suning.cn/uimg/b2c/newcatentries/0070130691-000000000826244625_5_800x800.jpg',

        'http://img12.360buyimg.com/n5/s450x450_jfs/t9952/98/2269407420/279171/6137fe2f/59f28b2bN6959e086.jpg',

        'http://d.ifengimg.com/w600/p0.ifengimg.com/pmop/2017/1213/A4037864F6728F006B67AAEC51EC8A485F320FD2_size93_w1024_h734.jpeg',

        'http://d.ifengimg.com/w600/p0.ifengimg.com/pmop/2017/1213/A4037864F6728F006B67AAEC51EC8A485F320FD2_size93_w1024_h734.jpeg'
      ],
      $elem: '',
      $smallBox: '',
      $smallBox_pic: '',
      $smallBox_mask: '',
      $thumbnailBox: '',
      $thumbnailBox_prev: '',
      $thumbnailBox_next: '',
      $thumbnailBox_wrapper: '',
      $thumbnailBox_item: '',
      $thumbnailBox_pic: '',
      $bigBox: '',
      $bigBox_pic: ''
    }
  },
  components: {
    VideoPlayer
  },
  props: {
    imageArr: {
      type: [Array, Object],
      default: () => []
    }
  },
  created() {
    this.theImg = this.imageArr[0]
  },
  mounted() {
    this.initPreview()
  },
  methods: {
    playVideo() {
      this.isShowVideo = true
    },
    initPreview() {
      this.$elem = $('#magnifier')
      this.$smallBox = this.$elem.find('.small-box')
      this.$smallBox_pic = this.$smallBox.find('img')
      this.$smallBox_mask = this.$smallBox.find('.hover')
      this.$thumbnailBox = this.$elem.find('.thumbnail-box')
      this.$thumbnailBox_prev = this.$thumbnailBox.find('.btn-prev')
      this.$thumbnailBox_next = this.$thumbnailBox.find('.btn-next')
      this.$thumbnailBox_wrapper = this.$thumbnailBox.find('.wrapper')
      this.$thumbnailBox_item = this.$thumbnailBox.find('.item')
      this.$thumbnailBox_pic = this.$thumbnailBox.find('img')
      this.$bigBox = this.$elem.find('.big-box')
      this.$bigBox_pic = this.$bigBox.find('img')
    },
    moveBigPic() {
      // 改变大图
      let scaleX =
        this.$smallBox_mask.position().left /
        (this.$smallBox.width() - this.$smallBox_mask.width())
      let scaleY =
        this.$smallBox_mask.position().top /
        (this.$smallBox.height() - this.$smallBox_mask.height())
      let scroll_l = scaleX * (this.$bigBox_pic.width() - this.$bigBox.width())
      let scroll_t =
        scaleY * (this.$bigBox_pic.height() - this.$bigBox.height())
      this.$bigBox.stop(true)
      this.$bigBox.scrollLeft(scroll_l).scrollTop(scroll_t)
    },
    setMask() {
      // 设置 mask 宽高
      //   let mask_w =
      //     this.$smallBox.width() /
      //     (this.$bigBox_pic.width() / this.$bigBox.width()) /
      //     2.5
      //   let mask_h =
      //     this.$smallBox.height() /
      //     (this.$bigBox_pic.height() / this.$bigBox.height()) /
      //     2.5
      //   //   this.$smallBox_mask.stop(true)
      //   this.$smallBox_mask.css({ width: mask_w, height: mask_h })
      //   this.$smallBox_mask.css({ height: '121.5px', width: '121.5px' })
    },
    smallBoxOver() {
      this.$bigBox.show()
      this.$smallBox_mask.show()
      this.setMask()
      this.$smallBox.stop(true)
    },
    smallBoxMove(ev) {
      //   console.log('ev.clientX', ev.clientX)
      let oEvent = ev || window.event
      let offset_pos = {
        left:
          oEvent.clientX -
          this.$smallBox.offset().left -
          this.$smallBox_mask.width() / 2,
        top:
          oEvent.clientY -
          this.$smallBox.offset().top -
          this.$smallBox_mask.height() / 2 +
          $(window).scrollTop()
      }
      if (offset_pos.left < 0) {
        offset_pos.left = 0
      } else if (
        offset_pos.left >
        this.$smallBox.width() - this.$smallBox_mask.width()
      ) {
        offset_pos.left = this.$smallBox.width() - this.$smallBox_mask.width()
      }
      if (offset_pos.top < 0) {
        offset_pos.top = 0
      } else if (
        offset_pos.top >
        this.$smallBox.height() - this.$smallBox_mask.height()
      ) {
        offset_pos.top = this.$smallBox.height() - this.$smallBox_mask.height()
      }

      this.$smallBox_mask.css(offset_pos)
      //   this.$smallBox_mask.css({ height: '121.5px', width: '121.5px' })

      this.moveBigPic()
    },
    smallLeave() {
      this.$smallBox_mask.hide()
      this.$bigBox.hide()
    },
    prev() {
      this.$thumbnailBox_wrapper.animate({ marginLeft: 0 })
    },
    next() {
      let ov_pic = this.$thumbnailBox_item.length - 5
      let ov_dis = ov_pic * 78
      this.$thumbnailBox_wrapper.stop(true)
      if (ov_pic > 0) {
        this.$thumbnailBox_wrapper.animate({ marginLeft: -ov_dis })
      }
    },
    leaveImg(index) {},
    chooseImg(item, index) {
      this.theImg = item
      this.activeIndex = index
    }
  }
}
</script>

<style lang="less" scoped>
/deep/ .vjs_video_3-dimensions.vjs-fluid {
  padding-top: 100% !important;
}
.videoPlayer {
  height: 100%;
  width: 100%;
}

.thumbnail-box {
  position: relative;
  width: 100%;
  height: 62px;
  .btn-prev {
    left: 0;
    background: url(../../assets/img/fjd/images/btn_prev.png) no-repeat;
  }
  .btn-next {
    right: 0;
    background: url(../../assets/img/fjd/images/btn_next.png) no-repeat;
  }
  .btn {
    position: absolute;
    top: 50%;
    width: 22px;
    height: 32px;
    margin-top: -16px;
  }
  .list {
    overflow: hidden;
    width: 390px;
    margin: 0 auto;
    height: 58px;
  }
  .wrapper {
    width: 100000px;
  }
  .list .item {
    float: left;
    margin: 0 11.9px;
    img {
      border: 2px solid #fff;
      height: 50px;
      width: 50px;
    }
  }

  .list .item-cur img {
    border: 2px solid #e53e41;
  }
}

ul,
li {
  list-style: none;
}
#magnifier {
  position: relative;
  width: 450px;
}
.small-box {
  position: relative;
  width: 450px;
  height: 450px;
  margin-bottom: 20px;
  border: 1px solid #eee;
  img {
    display: block;
    object-fit: fill;
    width: 100%;
    height: 100%;
  }
  .hover {
    display: none;
    position: absolute;
    left: 0;
    top: 0;
    width: 125px;
    height: 125px;
    border: 1px solid #aaa;
    background: #0099ff;
    opacity: 0.5;
    cursor: move;
  }
}

.big-box {
  display: none;
  overflow: hidden;
  position: absolute;
  left: 451px;
  top: 0;
  width: 540px;
  height: 540px;
  border: 1px solid #e4e4e4;
  z-index: 999;
  img {
    display: block;
    height: 128%;
  }
}

.preview {
  .preview-btn {
    position: absolute;
    z-index: 5;
    bottom: 62px;
    left: 0;
    width: 100%;
    display: -webkit-box;
    display: -webkit-flex;
    display: -ms-flexbox;
    display: flex;
    justify-content: center;
    text-align: center;
    li {
      display: inline-block;
      margin: 0 5px;
      vertical-align: text-top;
    }
    .video-icon {
      cursor: pointer;
      display: inline-block;
      z-index: 999;
      width: 50px;
      height: 50px;
      background: url(//static.360buyimg.com/item/unite/1.0.101/components/default/preview/i/main-circles.png)
        0 -55px no-repeat;
    }
    .video-icon:hover {
      background: url(//static.360buyimg.com/item/unite/1.0.101/components/default/preview/i/main-circles.png) -55px -55px
        no-repeat;
    }
  }
}
</style>

2. JQ版本

<template>
  <div id="magnifier">
    <!-- <div class="small-box" @mouseover="smallBoxOver" @mousemove="smallBoxMove"> -->
    <div class="small-box">
      <img :src="theImg" />
      <span class="hover"></span>
    </div>
    <div class="thumbnail-box">
      <!-- <a href="javascript:;" class="btn btn-prev" @click="prev"></a>
      <a href="javascript:;" class="btn btn-next" @click="next"></a>-->
      <a href="javascript:;" class="btn btn-prev"></a>
      <a href="javascript:;" class="btn btn-next"></a>
      <div class="list">
        <ul class="wrapper">
          <li
            class="item"
            v-for="(item, index) in pictureList"
            :key="index"
            @mouseenter="chooseImg(item)"
          >
            <img :src="item.url" />
          </li>
        </ul>
      </div>
    </div>

    <!-- 缩略图容器 -->
    <div class="carousel" style="display:none;">
      <!-- 左箭头 -->
      <div class="left_arrow arrow" @click="leftArrowClick"></div>
      <!-- 缩略图展示盒子 -->
      <div class="show_box">
        <ul class="picture_container" ref="middlePicture">
          <li
            class="picture_item"
            @mouseover="tabPicture(item)"
            v-for="(item, index) in pictureList"
            :key="index"
          >
            <img :src="item.url" class="small_img" alt />
          </li>
        </ul>
      </div>
      <!-- 向右箭头 -->
      <div class="right_arrow arrow" @click="rightArrowClick"></div>
    </div>
    <div class="big-box">
      <img :src="theImg" />
    </div>
  </div>
</template>

<script>
import $ from 'jquery'
import jQuery from 'jquery'
import 'jquery'
import '../ProductPreview/fjd/magnifier'

export default {
  data() {
    return {
      theImg: '', // 当前选中的图片
      pictureList: [
        {
          url:
            'http://mp.ofweek.com/Upload/News/Img/member645/201711/17170046839337.jpg'
        },
        {
          url:
            'http://image.buy.ccb.com/merchant/201703/904919627/1522929521661_4.jpg'
        },
        {
          url:
            'http://image5.suning.cn/uimg/b2c/newcatentries/0070130691-000000000826244625_5_800x800.jpg'
        },
        {
          url:
            'http://img12.360buyimg.com/n5/s450x450_jfs/t9952/98/2269407420/279171/6137fe2f/59f28b2bN6959e086.jpg'
        },
        {
          url:
            'http://d.ifengimg.com/w600/p0.ifengimg.com/pmop/2017/1213/A4037864F6728F006B67AAEC51EC8A485F320FD2_size93_w1024_h734.jpeg'
        },
        {
          url:
            'http://d.ifengimg.com/w600/p0.ifengimg.com/pmop/2017/1213/A4037864F6728F006B67AAEC51EC8A485F320FD2_size93_w1024_h734.jpeg'
        }
      ]
      // $elem: '',
      // $smallBox: '',
      // $smallBox_pic: '',
      // $smallBox_mask: '',
      // $thumbnailBox: '',
      // $thumbnailBox_prev: '',
      // $thumbnailBox_next: '',
      // $thumbnailBox_wrapper: '',
      // $thumbnailBox_item: '',
      // $thumbnailBox_pic: '',
      // $bigBox: '',
      // $bigBox_pic: ''
    }
  },
  created() {
    this.theImg = this.pictureList[0].url
  },
  mounted() {},
  methods: {
    chooseImg(item) {
      this.theImg = item.url
    },
    // 切换图片
    tabPicture(item) {
      this.middleImg = item.url
    },
    // 点击左边箭头
    leftArrowClick() {
      if (this.middleLeft < 0) {
        // 每次向右平移一个图片盒子的宽度
        this.middleLeft += this.itemWidth
        $('.picture_container').animate(
          {
            left: this.middleLeft
          },
          500
        )
      }
    },
    // 点击右边箭头
    rightArrowClick() {
      // 每次向左平移一个盒子的宽度,最多移动的宽度为(图片数组长度-4)*每张缩略图的宽度
      if (this.middleLeft > -this.itemWidth * (this.pictureList.length - 4)) {
        this.middleLeft -= this.itemWidth
        $('.picture_container').animate(
          {
            left: this.middleLeft
          },
          500
        )
      }
      console.log(this.middleLeft)
    }
  }
}
</script>

<style lang="less" scoped>
.thumbnail-box .btn-prev {
  left: 0;
  background: url(../../assets/img/fjd/images/btn_prev.png) no-repeat;
}
.thumbnail-box .btn-next {
  right: 0;
  background: url(../../assets/img/fjd/images/btn_next.png) no-repeat;
}

ul,
li {
  list-style: none;
}

#magnifier {
  position: relative;
  width: 450px;
}
.small-box {
  position: relative;
  width: 450px;
  height: 450px;
  margin-bottom: 20px;
  border: 1px solid #eee;
}
.small-box img {
  display: block;
  object-fit: fill;
  width: 100%;
  height: 100%;
}
.small-box .hover {
  display: none;
  position: absolute;
  left: 0;
  top: 0;
  width: 200px;
  height: 200px;
  border: 1px solid #aaa;
  background: #0099ff;
  opacity: 0.5;
  cursor: move;
}
.thumbnail-box {
  position: relative;
  width: 100%;
  height: 62px;
}
.thumbnail-box .btn {
  position: absolute;
  top: 50%;
  width: 22px;
  height: 32px;
  margin-top: -16px;
}

.thumbnail-box .list {
  overflow: hidden;
  width: 390px;
  margin: 0 auto;
  height: 58px;
}
.thumbnail-box .wrapper {
  width: 100000px;
}
.thumbnail-box .list .item {
  float: left;
  margin: 0 11.9px;
}
.thumbnail-box .list .item-cur {
}
.thumbnail-box .list .item img {
  border: 2px solid #fff;
  height: 50px;
  width: 50px;
}
.thumbnail-box .list .item-cur img {
  border: 2px solid #e53e41;
}
.big-box {
  display: none;
  overflow: hidden;
  position: absolute;
  left: 451px;
  top: 0;
  width: 540px;
  height: 540px;
  border: 1px solid #e4e4e4;
  z-index: 999;
}
.big-box img {
  display: block;
}
</style>

magnifier.js 

import jQuery from 'jquery'
import $ from 'jquery'
$(function() {
  $('#magnifier').magnifier()
})
;(function($, window, document, undefined) {
  let Magnifier = function(elem) {
    const self = this
    this.$elem = elem
    this.$smallBox = this.$elem.find('.small-box')
    this.$smallBox_pic = this.$smallBox.find('img')
    this.$smallBox_mask = this.$smallBox.find('.hover')
    this.$thumbnailBox = this.$elem.find('.thumbnail-box')
    this.$thumbnailBox_prev = this.$thumbnailBox.find('.btn-prev')
    this.$thumbnailBox_next = this.$thumbnailBox.find('.btn-next')
    this.$thumbnailBox_wrapper = this.$thumbnailBox.find('.wrapper')
    this.$thumbnailBox_item = this.$thumbnailBox.find('.item')
    this.$thumbnailBox_pic = this.$thumbnailBox.find('img')
    this.$bigBox = this.$elem.find('.big-box')
    this.$bigBox_pic = this.$bigBox.find('img')
  }

  Magnifier.prototype = {
    moveBigPic: function() {
      // 改变大图
      let scaleX =
        this.$smallBox_mask.position().left /
        (this.$smallBox.width() - this.$smallBox_mask.width())
      let scaleY =
        this.$smallBox_mask.position().top /
        (this.$smallBox.height() - this.$smallBox_mask.height())
      let scroll_l = scaleX * (this.$bigBox_pic.width() - this.$bigBox.width())
      let scroll_t =
        scaleY * (this.$bigBox_pic.height() - this.$bigBox.height())
      this.$bigBox.stop(true)
      this.$bigBox.scrollLeft(scroll_l).scrollTop(scroll_t)
    },

    // changeSrouce: function(index, cur_src) {
    //   // 改变大小图地址
    //   this.$smallBox_pic.attr('src', cur_src)
    //   this.$bigBox_pic.attr('src', 'images/big_' + (index + 1) + '.jpg')
    // },
    changeSrouce: function(index, cur_src) {
      // 改变大小图地址
      // this.$smallBox_pic.attr('src', cur_src)
      // this.$bigBox_pic.attr('src', cur_src)
    },

    setMask: function() {
      // 设置 mask 宽高
      let mask_w =
        this.$smallBox.width() /
        (this.$bigBox_pic.width() / this.$bigBox.width()) /
        2.5
      let mask_h =
        this.$smallBox.height() /
        (this.$bigBox_pic.height() / this.$bigBox.height()) /
        2.5
      this.$smallBox_mask.stop(true)
      this.$smallBox_mask.css({ width: mask_w, height: mask_h })
    },

    inital: function() {
      // 初始化
      const self = this

      this.$thumbnailBox_next.click(function() {
        let ov_pic = self.$thumbnailBox_item.length - 5
        let ov_dis = ov_pic * 78
        self.$thumbnailBox_wrapper.stop(true)

        if (ov_pic > 0) {
          self.$thumbnailBox_wrapper.animate({ marginLeft: -ov_dis })
        }
      })

      this.$thumbnailBox_prev.click(function() {
        // self.$thumbnailBox_wrapper.stop(true)
        self.$thumbnailBox_wrapper.animate({ marginLeft: 0 })
      })

      this.$thumbnailBox_item.mouseover(function() {
        let cur_src = $(this).attr('data-src')

        self.$thumbnailBox_item.removeClass('item-cur')

        $(this).addClass('item-cur')

        // self.changeSrouce($(this).index(), cur_src)
      })

      this.$smallBox.hover(
        function() {
          self.$bigBox.show()
          self.$smallBox_mask.show()
          self.setMask()
          $(this).stop(true)
          $(this).mousemove(function(ev) {
            let oEvent = ev || window.event
            let offset_pos = {
              left:
                oEvent.clientX -
                $(this).offset().left -
                self.$smallBox_mask.width() / 2,
              top:
                oEvent.clientY -
                $(this).offset().top -
                self.$smallBox_mask.height() / 2 +
                $(window).scrollTop(),
            }

            if (offset_pos.left < 0) {
              offset_pos.left = 0
            } else if (
              offset_pos.left >
              $(this).width() - self.$smallBox_mask.width()
            ) {
              offset_pos.left = $(this).width() - self.$smallBox_mask.width()
            }
            if (offset_pos.top < 0) {
              offset_pos.top = 0
            } else if (
              offset_pos.top >
              $(this).height() - self.$smallBox_mask.height()
            ) {
              offset_pos.top = $(this).height() - self.$smallBox_mask.height()
            }

            self.$smallBox_mask.css(offset_pos)

            self.moveBigPic()
          })
        },
        function() {
          self.$smallBox_mask.hide()
          self.$bigBox.hide()
        }
      )
    },

    constructor: Magnifier,
  }

  $.fn.magnifier = function() {
    var magnifier = new Magnifier(this)

    return magnifier.inital()
  }
})(jQuery, window, document)

原html插件,纯jq,学习用

链接:https://pan.baidu.com/s/16hEc-VtP--p_nZOdsMwi8w 
提取码:ex37

 

Logo

前往低代码交流专区

更多推荐