vue-piczoom 基于vue2.x的电商图片放大镜插件,修复了图片放大的一些bug,看懂的就看看,看不懂的就算了,太忙没时间写笔记备注了,可以自己用对比工具去看下修改了哪些
<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>
<div class="edit-wrap" v-if="showEidt">
<span class="rotate-left" @click="rotate('left')"></span>
<span class="rotate-right" @click="rotate('right')"></span>
</div>
</div>
</template>
<script>
import {mapState} from "vuex"
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 {
id:null,
cover:null,
imgbox:null,
imgwrap:null,
orginUrl:null,
bigImgUrl:null,
bigOrginUrl:null,
imgUrl:null,
img:null,
canvas:null,
canvasStyleTop:0,
ctx:null,
rectTimesX:0,
rectTimesY:0,
imgTimesX:0,
imgTimesY:0,
init:false,
step:0,
bigStep:0,
vertical:false,
showImg:true,
domImg:null,
canvasDiffHeight:0,
searchDom:null
}
},
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.domImg = new Image();
this.domImg.src = this.bigUrl?this.bigUrl:this.url;
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()
})
this.searchDom = document.querySelector('.search');
this.searchDom.addEventListener('scroll',()=>{
let scrollStyleTop = (this.canvasStyleTop - this.searchDom.scrollTop) + this.canvasDiffHeight +'px';
this.canvas.style.top = scrollStyleTop;
})
},
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.parentNode.removeChild(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.canvasStyleTop=this.getOffset(this.imgbox).top
// this.canvas.style.top=this.imgbox.offsetTop+'px'
this.canvas.style.border='1px solid #eee'
this.canvas.style.zIndex='99999'
console.log(this.canvas.height)
this.domImg.onload = () => {
if(this.domImg.height > this.domImg.width){
let domImgScale = this.domImg.height / 480;
let styleWidth = this.domImg.width / domImgScale;
this.cover.style.width=(styleWidth/this.scale)+'px'
this.cover.style.height=(this.imgbox.offsetHeight/this.scale)+'px'
this.canvas.style.top=this.getOffset(this.imgbox).top - this.searchDom.scrollTop +'px'
this.canvas.width = styleWidth;
this.canvas.height=this.imgbox.offsetHeight
}else{
let domImgScale = this.domImg.width / 446;
let styleHeight = this.domImg.height / domImgScale;
this.cover.style.width=(this.imgbox.offsetWidth/this.scale)+'px';
this.cover.style.height=(styleHeight/this.scale)+'px';
this.canvas.width=this.imgbox.offsetWidth;
this.canvas.height = styleHeight;
this.canvasDiffHeight = (480-styleHeight) / 2;
this.canvas.style.top=this.getOffset(this.imgbox).top + this.canvasDiffHeight - this.searchDom.scrollTop + 'px'
console.log(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);
},
getOffset(Node, offset) {
if (!offset) {
offset = {};
offset.top = 0;
offset.left = 0;
}
if (Node == document.body) {//当该节点为body节点时,结束递归
return offset;
}
offset.top += Node.offsetTop;
offset.left += Node.offsetLeft;
return this.getOffset(Node.offsetParent, offset);//向上累加offset里的值
},
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 searchDom = document.querySelector('.search');
let range={
minX:imgwrap.left,
maxX:imgwrap.left+this.imgwrap.offsetWidth-this.cover.offsetWidth,
minY:imgwrap.top-searchDom.scrollTop,
maxY:imgwrap.top-searchDom.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-searchDom.scrollLeft),
startY=pos.y-(imgwrap.top-searchDom.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);
},
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'
},
mouseleave(){
if(!this.init){
return false
}
this.cover.style.display='none'
this.canvas.style.display='none'
},
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%;
display: flex;
justify-content: center;
align-items: center;
overflow: hidden;
position: relative;
.edit-wrap{
position: absolute;
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{
max-height: 100%;
max-width: 100%;
};
.mouse-cover{
position: fixed;
background-color: rgba(0,0,0,0.5);
cursor:move
};
.mouse-cover-canvas{
position:fixed;
left:100%;
top:0;
width:100%;
height:100%;
}
&.vertical{
img{
max-height: 100%;
max-width: 100%;
}
}
}
</style>