<template>
<div :ref="id" class="magnifier-box" :class="vertical?'vertical':''" @mousemove="mousemove" @mouseover="mouseover" @mouseleave="mouseleave">
<img v-show="showImg" :src="imgUrl" alt="">
<div class="mouse-cover"></div>
</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
},
domId: {
type: String,
default: null
}
},
data() {
return {
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
}
},
watch: {
url: function(val) {
this.imgUrl = val
this.orginUrl = val
this.initTime()
},
bigUrl: function(val) {
this.bigImgUrl = val
this.bigOrginUrl = val
this.initTime()
}
},
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
},
mounted() {
this.$nextTick(() => {
this.initTime()
})
},
methods: {
initTime() {
this.init = false
const 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.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'
this.domId ? document.getElementById(this.domId).append(this.canvas) : 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'
const 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
const thumb = box.querySelector('img')
setTimeout(() => {
this.rectTimesX = (this.imgbox.offsetWidth / this.scale) / thumb.offsetWidth
this.rectTimesY = (this.imgbox.offsetHeight / this.scale) / thumb.offsetHeight
}, 20)
}
},
mousemove(e) {
if (!this.init) {
return false
}
const _this = this
// 获取实际的offset
function offset(curEle) {
var totalLeft = null; var totalTop = null; var 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)
}
}
const oEvent = e || event
const pos = getXY(oEvent)
const imgwrap = offset(this.imgwrap)
const 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)
const startX = pos.x - (imgwrap.left - document.documentElement.scrollLeft)
const 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)
},
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;
}
img{
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{
height: 100%;
width: auto
}
}
}
</style>