vue中手写一个放大镜功能
有的时候需要对图片进行放大,类似于电商的商品放大功能,于是在这个想法上写了一个放大镜的功能,并且在放大镜的基础上新添加了一些小功能,下面开始吧!
放大镜是封装的组件的形式,用的时候只需要传入图片,和放大倍数的图片即可。
首先前提写了一个监听屏幕大小然后改变图片大小的功能,不让图片超出屏幕的大小;
需要安装一个插件element-resize-detector-- “^1.2.1”
let _this = this; //this重定向
var elementResizeDetectorMaker = require("element-resize-detector");
// 创建实例
var erd = elementResizeDetectorMaker();
// 创建实例带参
elementResizeDetectorMaker({
strategy: "scroll",
callOnAdd: true,
debug: true
});
//监听id为pic-img的元素 大小变化
erd.listenTo(document.getElementById("pic-img"), function(element) {
var width = element.offsetWidth; //容器宽
var height = element.offsetHeight; //容器高
_this.divSize = { x: width, y: height };
});
然后就是放大镜的功能,废话少说,直接上全部代码
<template>
<div class="img">
<div class="pic-img" id="pic-img">
<div
class="img-container"
style="width: 1000px"
@mousemove="!moveEvent && mouseMove($event)"
@mouseleave="!leaveEvent && mouseLeave($event)"
:style="imgStyle"
>
<img ref="img" :src="url" />
<!-- 图片内部盒子 -->
<div
v-show="xixi"
v-if="!hideZoom&&imgLoadedFlag"
:class="['img-selector', { circle: type === 'circle' }]"
:style="[
imgSelectorSize,
imgSelectorPosition,
!outShow && imgSelectorBg,
!outShow && imgBgPosition,
]"
></div>
</div>
<!-- 图片外部盒子 -->
<div
v-if="outShow"
v-show="!hideOutShow"
class="img-out-show"
:style="[imgOutShowSize, imgSelectorBg, imgBgPosition]"
></div>
</div>
<div class="option_img">
<div class="operation">
<img v-show="allshow" @click="eye(0)" src="./img//open.png" alt title="显示放大" />
<img v-show="!allshow" @click="eye(1)" src="./img//zoom in_no.png" alt title="不显示放大" />
<img src="./img/inside.png" alt v-show="part" @click="mode(0)" title="内部放大" />
<img src="./img//outer.png" alt v-show="!part" @click="mode(1)" title="外部放大" />
<p @click="magnification">
<span>×{{ multiple }}</span>
</p>
</div>
</div>
</div>
</template>
<script>
export default {
name: "vue-photo-zoom-pro",
data() {
return {
//全显全不显
classData: {
type: 1,
id: 100
},
fourShow: false,
allshow: true,
part: true, //内部放大还是外部放大
multiple: 2, //倍数
num: 0, //记录题目
xixi: false,
hideZoom: false,
scale: 2,
divSize: {},
imgSize: {}, //记录图片的大小
outShow: false,
selector: {
width: 166, //图片上面覆盖框大小
halfWidth: 83,
top: 0,
left: 0,
bgTop: 0,
bgLeft: 0,
rightBound: 0,
bottomBound: 0,
absoluteLeft: 0,
absoluteTop: 0
},
imgInfo: {},
hideOutShow: true,
imgLoadedFlag: true, //用来判断图片加载
screenWidth: document.body.clientWidth,
timer: null
};
},
props: {
url: {
type: String
},
highUrl: {
type: String
},
type: {
type: String,
default: "square",
validator: function(value) {
return ["circle", "square"].indexOf(value) !== -1;
}
},
moveEvent: {
type: [Object, MouseEvent],
default: null
},
leaveEvent: {
type: [Object, MouseEvent],
default: null
}
},
watch: {
moveEvent(e) {
this.mouseMove(e);
},
leaveEvent(e) {
this.mouseLeave(e);
},
url() {
this.imgLoadedFlag = true;
}
},
computed: {
//定义图片大小
imgStyle() {
var w, h;
var imgK = this.imgSize.width / this.imgSize.height;
var boxK = this.divSize.x / this.divSize.y;
if (imgK > boxK) {
if (this.imgSize.width > this.divSize.x) {
w = this.divSize.x;
h = parseInt(
(this.divSize.x / this.imgSize.width) * this.imgSize.height
);
} else if (this.imgSize.width < this.divSize.x) {
w = this.imgSize.width;
h = this.imgSize.height;
}
} else if (imgK < boxK) {
if (this.imgSize.height > this.divSize.y) {
h = this.divSize.y;
w = parseInt(
(this.divSize.y / this.imgSize.height) * this.imgSize.width
);
} else if (this.imgSize.height < this.divSize.y) {
w = this.imgSize.width;
h = this.imgSize.height;
}
}
return `width:${w}px;height:${h}px`;
},
imgSelectorPosition() {
let { top, left } = this.selector;
return {
top: `${top}px`,
left: `${left}px`
};
},
imgSelectorSize() {
let width = this.selector.width;
return {
width: `${width}px`,
height: `${width}px`
};
},
imgOutShowSize() {
let {
selector: { width }
} = this;
return {
width: `${width * this.multiple}px`,
height: `${width * this.multiple}px`
};
},
imgSelectorBg() {
let {
scale,
imgInfo: { height, width }
} = this;
return {
backgroundImage: `url(${this.highUrl || this.url})`,
backgroundSize: `${width * scale}px ${height * scale}px`
};
},
imgBgPosition() {
let { bgLeft, bgTop } = this.selector;
return {
backgroundPosition: `${bgLeft}px ${bgTop}px`
};
}
},
mounted() {
let _this = this; //this重定向
var elementResizeDetectorMaker = require("element-resize-detector");
// 创建实例
var erd = elementResizeDetectorMaker();
// 创建实例带参
elementResizeDetectorMaker({
strategy: "scroll",
callOnAdd: true,
debug: true
});
//监听id为pic-img的元素 大小变化
erd.listenTo(document.getElementById("pic-img"), function(element) {
var width = element.offsetWidth; //容器宽
var height = element.offsetHeight; //容器高
_this.divSize = { x: width, y: height };
});
},
methods: {
//全显全不显
eye(val) {
if (val) {
this.allshow = true;
this.hideZoom = false;
} else {
this.allshow = false;
this.hideZoom = true;
}
},
mode(val) {
//内部放大还是外部放大
if (val) {
this.part = true;
this.outShow = false;
} else {
this.part = false;
this.outShow = true;
}
},
magnification() {
if (this.multiple < 3) {
this.multiple++;
this.scale = this.multiple;
} else {
this.multiple = 2;
this.scale = this.multiple;
}
},
imgLoaded() {
let imgInfo = this.$refs["img"].getBoundingClientRect();
if (JSON.stringify(this.imgInfo) == JSON.stringify(imgInfo)) {
// 位置不变不更新
return;
}
this.imgLoadedFlag = true;
let { width, height, left, top } = (this.imgInfo = imgInfo);
let selector = this.selector;
let { width: selectorWidth, halfWidth: selectorHalfWidth } = selector;
let { scrollLeft, scrollTop } = document.documentElement;
selector.rightBound = width - selectorWidth;
selector.bottomBound = height - selectorWidth;
selector.absoluteLeft = left + selectorHalfWidth + scrollLeft;
selector.absoluteTop = top + selectorHalfWidth + scrollTop;
},
reset() {
Object.assign(this.selector, {
top: 0,
left: 0,
bgLeft: 0,
bgTop: 0
});
},
mouseMove(e) {
this.xixi = true;
if (!this.hideZoom && this.imgLoadedFlag) {
this.imgLoaded(); //防止img位置变化
let { pageX, pageY } = e;
let { scale, selector } = this;
let {
halfWidth,
absoluteLeft,
absoluteTop,
rightBound,
bottomBound
} = selector;
let x = pageX - absoluteLeft; // 选择器的x坐标 相对于图片
let y = pageY - absoluteTop; // 选择器的y坐标
if (this.outShow) {
halfWidth = 0;
this.hideOutShow = false;
}
selector.top = y > 0 ? (y < bottomBound ? y : bottomBound) : 0;
selector.left = x > 0 ? (x < rightBound ? x : rightBound) : 0;
selector.bgLeft = halfWidth - (halfWidth + x) * scale; // 选择器图片的坐标位置
selector.bgTop = halfWidth - (halfWidth + y) * scale;
}
},
mouseLeave() {
if (this.outShow) {
this.hideOutShow = true;
}
this.xixi = false;
}
}
};
</script>
<style scoped>
.img {
width: 70%;
height: 100%;
float: left;
}
.pic-img {
width: 100%;
height: 85%;
display: flex;
justify-content: center;
align-items: center;
background-color: #eee;
box-shadow: 0 0 5px #ccc;
}
.option_img {
width: 100%;
height: 90px;
background: linear-gradient(180deg, #fdfdfd 0%, #e2e2e2 86%, #f7f6f6 100%);
border: 1px solid #d9d9d9;
}
.operation {
width: 360px;
height: 70px;
margin: 10px auto;
position: relative;
background-size: 100% 100%;
}
.operation input {
width: 50px;
height: 50px;
border: none;
border-radius: 50%;
}
.operation > p {
width: 70px;
height: 70px;
line-height: 40px;
font-size: 28px;
color: #7dc5eb;
cursor: pointer;
float: left;
margin-top: 2px;
}
.operation > p > span {
display: inline-block;
border-radius: 50%;
margin-top: 7px;
width: 40px;
height: 40px;
border: 3px solid #038cf4;
color: #038cf4;
}
.operation > img {
width: 70px;
height: 70px;
float: left;
cursor: pointer;
float: left;
margin-left: 2px;
margin-top: 2px;
}
.img-container {
position: relative;
}
.img-container > img {
/* image-orientation: 0deg; */
/* image-orientation: none; */
}
.img-selector {
background-color: rgba(0, 0, 0, 0.6);
position: absolute;
background-repeat: no-repeat;
pointer-events: none;
cursor: move;
border: 1px solid rgba(0, 0, 0, 0.1);
z-index: 99;
/* display: none; */
}
.img-selector.circle {
border-radius: 50%;
}
.img-out-show {
position: absolute;
bottom: 0;
right: 0;
background-repeat: no-repeat;
transform: translate(100%, 0);
border: 1px solid rgba(0, 0, 0, 0.1);
}
img {
width: 100%;
height: 100%;
}
</style>
最后父组件引用的时候:
<template>
<div id="app">
<HelloWorld :url="url" :highUrl="highUrl"/>
</div>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue'
export default {
name: 'App',
data(){
return{
url:require("./components/img/2.jpg"),
highUrl: require("./components/img/2.jpg"),
}
},
components: {
HelloWorld
}
}
</script>