效果: PicZoom.vue(图片放大组件)
<template> <div class="magnifier-box" :class="vertical?'vertical':''" :ref="id" @mousemove="mousemove" @mouseover="mouseover" @mouseleave="mouseleave" > <img v-show="showImg" :src="imgUrl" alt /> <div class="mouse-cover"></div> <img :src="bigImage" class="big-image" v-show="showImage" /> </div> </template> <script> export default { props: { scale: { type: Number, default: 2.5 }, url: { type: String, required: true }, bigUrl: { type: String, default: null }, scroll: { type: Boolean, default: false }, showEidt: { type: Boolean, default: false } }, data() { return { bigImage: null, showImage: null, id: null, cover: null, imgbox: null, imgwrap: null, orginUrl: null, bigImgUrl: null, bigOrginUrl: null, imgUrl: null, img: null, canvas: null, ctx: null, rectTimesX: 0, rectTimesY: 0, imgTimesX: 0, imgTimesY: 0, init: false, step: 0, bigStep: 0, vertical: false, showImg: true }; }, created() { var $chars = "ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678"; /****默认去掉了容易混淆的字符oOLl,9gq,Vv,Uu,I1****/ var maxPos = $chars.length; var str = ""; for (let i = 0; i < 10; i++) { str += $chars.charAt(Math.floor(Math.random() * maxPos)); } this.id = str; this.imgUrl = this.url; this.orginUrl = this.url; this.bigImgUrl = this.bigUrl; this.bigOrginUrl = this.bigUrl; }, watch: { url: function(val) { this.imgUrl = val; this.orginUrl = val; this.initTime(); }, bigUrl: function() { this.bigImgUrl = bigUrl; this.bigOrginUrl = bigUrl; this.initTime(); } }, mounted() { this.$nextTick(() => { this.initTime(); }); }, methods: { initTime() { this.init = false; let box = this.$refs[this.id]; this.imgbox = box; this.cover = box.querySelector(".mouse-cover"); this.cover.style.width = this.imgbox.offsetWidth / this.scale + "px"; this.cover.style.height = this.imgbox.offsetHeight / this.scale + "px"; this.cover.style.left = "-100%"; this.cover.style.top = "-100%"; this.imgwrap = box.querySelector("img"); let imgsrc; if (this.bigImgUrl) { imgsrc = this.bigImgUrl; } else { imgsrc = this.imgUrl; } this.img = new Image(); this.img.src = imgsrc; this.img.onload = () => { (this.rectTimesX = this.imgbox.offsetWidth / this.scale / this.imgwrap.offsetWidth), (this.rectTimesY = this.imgbox.offsetHeight / this.scale / this.imgwrap.offsetHeight); (this.imgTimesX = this.img.width / this.imgwrap.offsetWidth), (this.imgTimesY = this.img.height / this.imgwrap.offsetHeight); this.vertical = this.img.width < this.img.height; this.init = true; }; if (this.canvas) { this.canvas = null; } this.canvas = document.createElement("canvas"); this.canvas.className = "mouse-cover-canvas"; this.canvas.style.position = "absolute"; this.canvas.style.left = this.imgbox.offsetLeft + this.imgbox.offsetWidth + 10 + "px"; this.imgbox.offsetLeft + this.imgbox.offsetWidth + 10 + "px"; this.canvas.style.top = this.imgbox.offsetTop + "px"; this.canvas.style.border = "1px solid #eee"; this.canvas.style.zIndex = "99999"; this.canvas.height = this.imgbox.offsetHeight; this.canvas.width = this.imgbox.offsetWidth; this.canvas.style.display = "none"; // document.body.append(this.canvas); this.ctx = this.canvas.getContext("2d"); this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); }, initBox() { this.showImg = false; this.canvas.style.display = "none"; let box = this.$refs[this.id]; let imgsrc; if (this.bigImgUrl) { imgsrc = this.bigImgUrl; } else { imgsrc = this.imgUrl; } this.img = new Image(); this.img.src = imgsrc; this.img.onload = () => { this.vertical = this.img.width < this.img.height; this.showImg = true; let thumb = box.querySelector("img"); setTimeout(() => { (this.rectTimesX = this.imgbox.offsetWidth / this.scale / box.querySelector("img").offsetWidth), (this.rectTimesY = this.imgbox.offsetHeight / this.scale / box.querySelector("img").offsetHeight); }, 20); }; }, mousemove(e) { if (!this.init) { return false; } let _this = this; //获取实际的offset function offset(curEle) { var totalLeft = null, totalTop = null, par = curEle.offsetParent; //首先加自己本身的左偏移和上偏移 totalLeft += curEle.offsetLeft; totalTop += curEle.offsetTop; //只要没有找到body,我们就把父级参照物的边框和偏移也进行累加 while (par) { if (navigator.userAgent.indexOf("MSIE 8.0") === -1) { //累加父级参照物的边框 totalLeft += par.clientLeft; totalTop += par.clientTop; } //累加父级参照物本身的偏移 totalLeft += par.offsetLeft; totalTop += par.offsetTop; par = par.offsetParent; } return { left: totalLeft, top: totalTop }; } function getXY(eve) { return { x: eve.clientX - _this.cover.offsetWidth / 2, y: eve.clientY - _this.cover.offsetHeight / 2 }; } let oEvent = e || event; let pos = getXY(oEvent); let imgwrap = offset(this.imgwrap); let range = { minX: imgwrap.left, maxX: imgwrap.left + this.imgwrap.offsetWidth - this.cover.offsetWidth, minY: imgwrap.top - document.documentElement.scrollTop, maxY: imgwrap.top - document.documentElement.scrollTop + this.imgwrap.offsetHeight - this.cover.offsetHeight }; if (pos.x > range.maxX) { pos.x = range.maxX; } if (pos.x < range.minX) { pos.x = range.minX; } if (pos.y > range.maxY) { pos.y = range.maxY; } if (pos.y < range.minY) { pos.y = range.minY; } this.cover.style.left = pos.x + "px"; this.cover.style.top = pos.y + "px"; this.ctx.clearRect( 0, 0, this.imgwrap.offsetWidth, this.imgwrap.offsetHeight ); let startX = pos.x - (imgwrap.left - document.documentElement.scrollLeft), startY = pos.y - (imgwrap.top - document.documentElement.scrollTop); this.ctx.drawImage( this.img, startX * this.imgTimesX, startY * this.imgTimesY, this.img.width * this.rectTimesX, this.img.height * this.rectTimesY, 0, 0, this.imgbox.offsetWidth, this.imgbox.offsetHeight ); this.bigImage = this.canvas.toDataURL("image/png"); }, mouseover(e) { if (!this.init) { return false; } e = e || event; if (!this.scroll) { e.currentTarget.addEventListener( "mousewheel", function(ev) { ev.preventDefault(); }, false ); e.currentTarget.addEventListener( "DOMMouseScroll", function(ev) { ev.preventDefault(); }, false ); } this.cover.style.display = "block"; this.canvas.style.display = "block"; this.showImage = true; }, mouseleave() { if (!this.init) { return false; } this.cover.style.display = "none"; this.canvas.style.display = "none"; this.showImage = false; }, rotate(direction) { var orginImg = new Image(); orginImg.crossOrigin = "Anonymous"; orginImg.src = this.orginUrl; orginImg.onload = () => { this.rotateImg(orginImg, direction, this.step); }; if (this.bigOrginUrl) { var bigOrginImg = new Image(); orginImg.crossOrigin = "Anonymous"; bigOrginImg.src = this.bigOrginUrl; bigOrginImg.onload = () => { this.rotateImg(bigOrginImg, direction, this.bigStep, true); }; } }, rotateImg(img, direction, step, isBig = false) { var min_step = 0; var max_step = 3; if (img == null) return; //img的高度和宽度不能在img元素隐藏后获取,否则会出错 var height = img.height; var width = img.width; if (step == null) { step = min_step; } if (direction == "right") { step++; //旋转到原位置,即超过最大值 step > max_step && (step = min_step); } else { step--; step < min_step && (step = max_step); } var canvas = document.createElement("canvas"); //旋转角度以弧度值为参数 var degree = (step * 90 * Math.PI) / 180; var ctx = canvas.getContext("2d"); canvas.width = height; canvas.height = width; ctx.rotate(degree); ctx.drawImage(img, 0, -height); switch (step) { case 0: canvas.width = width; canvas.height = height; ctx.drawImage(img, 0, 0); break; case 1: canvas.width = height; canvas.height = width; ctx.rotate(degree); ctx.drawImage(img, 0, -height); break; case 2: canvas.width = width; canvas.height = height; ctx.rotate(degree); ctx.drawImage(img, -width, -height); break; case 3: canvas.width = height; canvas.height = width; ctx.rotate(degree); ctx.drawImage(img, -width, 0); break; } var newImg = canvas.toDataURL(); if (isBig) { this.bigImgUrl = newImg; this.bigStep = step; this.initBox(); } else { this.imgUrl = newImg; this.step = step; this.$nextTick(() => { this.initBox(); }); } } } }; </script> <style lang="scss" scoped> .magnifier-box { width: 100%; height: 100%; text-align: center; overflow: hidden; .edit-wrap { top: 5px; right: 0; z-index: 9999999; background: rgba(0, 0, 0, 0.4); padding: 5px 15px 0 15px; border-radius: 15px; .rotate-left { display: inline-block; cursor: pointer; width: 16px; height: 16px; /*background: url(../rotate.png);*/ background-size: 100% 100%; -moz-transform: scaleX(-1); -webkit-transform: scaleX(-1); -o-transform: scaleX(-1); transform: scaleX(-1); /*IE*/ filter: FlipH; } .rotate-right { margin-left: 10px; cursor: pointer; display: inline-block; width: 16px; height: 16px; /*background: url(../rotate.png);*/ background-size: 100% 100%; } } img { width: 100%; } .mouse-cover { position: fixed; background-color: rgba(0, 0, 0, 0.5); cursor: move; } /deep/.mouse-cover-canvas { position: fixed; left: 100%; top: 200px !important; width: 100%; height: 100%; } &.vertical { img { height: 100%; width: auto; } } } .big-image { border: 1px solid #eee; display: block; width: 498px; height: 498px; top: -1px; position: absolute; left: 498px; z-index: 99; } </style>Carousel.vue(缩略图组件)
<template> <div> <div class="pic-box"> <pic-zoom :url="pImgSrc" :scale="3"></pic-zoom> </div> <div class="box"> <el-carousel height="96px" indicator-position="none" :interval="0"> <el-carousel-item v-for="(item,i) in imagesList" :key="i"> <div v-for="(img,index) in item.imgUrl" :key="index" @click="getIndex(img.url)" class="img-url" > <img :src="img.url" /> </div> </el-carousel-item> </el-carousel> </div> </div> </template> <script> import PicZoom from "./PicZoom"; export default { name: "Carousel", components: { PicZoom }, data() { return { pImgSrc: "" }; }, props: { imgSrc: { type: String, default: "" }, imagesList: { type: Array, default: function() { return []; } } }, methods: { getIndex(imgSrc) { this.pImgSrc = imgSrc; } }, watch: { imgSrc: { handler(aImgSrc, pImgSrc) { this.pImgSrc = aImgSrc; }, immediate: true } } }; </script> <style lang="scss" scoped> .box { width: 500px; height: 100px; overflow: hidden; margin-top: 10px; ul { position: absolute; width: 2000px; li { display: inline-block; list-style: none; width: 90px; height: 90px; background-color: white; margin-top: 15px; border: 1px solid #eee; overflow: hidden; margin-right: 10px; img { width: 100%; } } } } .pic-box { position:relative; width: 498px; height: 498px; border: 1px solid #eee; } /deep/ .mouse-cover-canvas { top: 200px !important; margin-top: 200px; } .img-url { display: inline-block; border: 1px solid #eee; margin-right: 10px; &:nth-child(5) { margin-right: 0; } img { width: 90px; } } </style>index.vue 页面引用代码:
<Carousel :imgSrc="imgSrc" :imagesList="imagesList" />js部分:
import Carousel from "@/components/main/Carousel.vue"; export default { components: { Carousel, }, data() { return { imgSrc: require("../../../assets/images/bp002-1.jpg"), //默认显示大图 imagesList: [ //缩略图: { imgUrl: [ { url: require("../../../assets/images/bp002-1.jpg") }, { url: require("../../../assets/images/bp002-2.jpg") }, { url: require("../../../assets/images/bp002-3.jpg") }, { url: require("../../../assets/images/bp002-4.jpg") }, { url: require("../../../assets/images/bp002-5.jpg") } ] } ], }; }, };