图片预览组件 (放大 缩小 旋转 鼠标拖动)
效果图
其中的图片初始化 不需要 如果需要可自行修改一下
**完整代码如下 **
点击查看代码
<template>
<transition name="zoom">
<div class="previewImage_wrapper" ref="previewImage_wrapper" @wheel="handleScroll">
<div class="previewImage_image" ref="previewImage_image" @mousedown="onmousedownHandle">
<img ref="previewImage_img"
:style="{
top: top + 'px',
left: left + 'px',
}"
@click="initImage(previewImgList )"
:src="previewImgList || ''" />
</div>
<div class="previewImage_toolbar">
<span class="title">{{ title }} {{ currentIndex }}</span>
<div class="toolbar">
<span class="previewImage_btn" @click="shrinkHandle">-</span>
<span class="previewImage_btn" @click="largeHandle">+</span>
<span class="previewImage_btn" @click="turnLeftHandle">↺</span>
<span class="previewImage_btn" @click="initImgHandle">▣</span>
<span class="previewImage_btn" @click="turnRightHandle">↻</span>
</div>
</div>
</div>
</transition>
</template>
<script>
export default {
name: 'picture-view',
props: {
previewImgList: {
// url数组
type: String,
default: '',
},
currentIndex: {
// 当前图片索引
type: String,
default: 0,
},
title: {
type: String,
default: '',
},
},
data() {
return {
imageUrl: '',
imgW: 0,
imgH: 0,
top: 0,
left: 0,
mousewheelevt: null,
imgHandle: {
// 图片控制
scale: 1,
rotate: 0,
},
};
},
mounted() {
this.imageUrl = this.previewImgList;
this.initImage();
this.mousewheelevt = /Firefox/i.test(navigator.userAgent) ? 'DOMMouseScroll' : 'mousewheel';
this.$refs.previewImage_image.addEventListener(this.mousewheelevt, { passive: true });
},
beforeDestroy() {
this.$refs.previewImage_image.removeEventListener(this.mousewheelevt, { passive: true });
},
methods: {
/* 获取图片真实高宽 */
getImgSize(url) {
return new Promise((resolve, reject) => {
let imgObj = new Image();
imgObj.src = url;
imgObj.onload = () => {
resolve({ width: imgObj.width, height: imgObj.height });
};
});
},
/* 初始化图片 */
async initImage() {
if (!this.imageUrl) {
return;
}
let { width, height } = await this.getImgSize(this.imageUrl);
// let realWidth = width;
// let realHeight = height;
// const picBoxW = this.$refs.previewImage_image.clientWidth;
// const picBboxH = this.$refs.previewImage_image.clientHeight;
// const WRatio = picBoxW / realWidth;
// const HRatio = picBboxH / realHeight;
/* 横图 使用宽度比例 */
// if (realWidth >= realHeight) {
// this.imgW = realWidth * WRatio;
// this.imgH = realHeight * WRatio;
// this.top = (picBboxH - this.imgH) / 2;
// this.left = (picBoxW - this.imgW) / 2;
// /* 竖图 */
// } else {
// this.left = (picBoxW - this.imgW) / 2;
// this.imgW = realWidth * HRatio;
// this.imgH = realHeight * HRatio;
// }
},
onmousedownHandle(e) {
const that = this;
const element = this.$refs.previewImage_image;
const imgEle = this.$refs.previewImage_img;
element.onmousemove = function (el) {
const ev = el || window.event;
// 阻止默认事件
ev.preventDefault();
that.left += ev.movementX;
that.top += ev.movementY;
};
element.onmouseup = function () {
element.onmousemove = null;
element.onmouseup = null;
};
if (e.preventDefault) {
e.preventDefault();
} else {
return false;
}
},
// 向左翻转
async turnLeftHandle() {
this.imgHandle.rotate = this.imgHandle.rotate - 90;
await this.$nextTick();
const element = this.$refs.previewImage_img;
element.style.transform = `scale(${this.imgHandle.scale}) rotate(${this.imgHandle.rotate}deg)`;
},
// 向右翻转
async turnRightHandle() {
this.imgHandle.rotate = this.imgHandle.rotate + 90;
await this.$nextTick();
const element = this.$refs.previewImage_img;
element.style.transform = `scale(${this.imgHandle.scale}) rotate(${this.imgHandle.rotate}deg)`;
},
// 初始化还原图片缩放旋转控制
async initImgHandle() {
this.imgHandle = {
scale: 1,
rotate: 0,
};
this.top = 0,
this.left = 0,
// this.initImage()
await this.$nextTick();
const element = this.$refs.previewImage_img;
element.style.transform = `scale(${this.imgHandle.scale}) rotate(${this.imgHandle.rotate}deg)`;
},
// 放大图片
async largeHandle() {
this.imgHandle.scale = Number((this.imgHandle.scale + 0.2).toFixed(2)); // 使用toFixed防止小数点精度不准
const element = this.$refs.previewImage_img;
element.style.transform = `scale(${this.imgHandle.scale}) rotate(${this.imgHandle.rotate}deg)`;
},
// 缩小图片
async shrinkHandle() {
if (this.imgHandle.scale === 0.2) {
// 最低缩放到0.2倍
return;
}
this.imgHandle.scale = Number((this.imgHandle.scale - 0.2).toFixed(2)); // 使用toFixed防止小数点精度不准
const element = this.$refs.previewImage_img;
element.style.transform = `scale(${this.imgHandle.scale}) rotate(${this.imgHandle.rotate}deg)`;
},
// 上一张图片
prevImage() {
if (this.currentIndex === 0) {
this.currentIndex = this.previewImgList.length - 1;
} else {
this.currentIndex--;
}
this.initImgHandle();
},
// 下一张图片
nextImage() {
if (this.currentIndex === this.previewImgList.length - 1) {
this.currentIndex = 0;
} else {
this.currentIndex++;
}
this.initImgHandle();
},
},
};
</script>
<style lang="scss" scoped>
.title{
color: #fff;
font-size: 24px;
font-weight: 700;
}
.previewImage_wrapper {
width: 100%;
height: 100%;
.previewImage_image {
width: 100%;
height: 100%;
position: relative;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
img {
position: absolute;
width: 100%;
height: 100%;
object-fit: scale-down;
transition: transform 0.3s ease;
}
}
.previewImage_navigation {
&_left {
position: absolute;
left: 15px;
top: 50%;
transform: translate(0, -50%);
transition: transform 0.2s ease-out;
}
&_right {
position: absolute;
right: 15px;
top: 50%;
transform: translate(0, -50%);
transition: transform 0.2s ease-out;
}
&_left:hover,
&_right:hover {
transform: translate(0, -50%) scale(1.2);
}
}
.previewImage_toolbar {
position: absolute;
top: 0px;
left: 50%;
width: 100%;
height: 50px;
transform: translate(-50%, 0);
display: flex;
align-items: center;
justify-content: space-around;
background: rgba($color: #606266, $alpha: 0.5);
.toolbar {
display: flex;
align-items: center;
justify-content: space-between;
}
span {
margin-right: 10px;
transition: transform 0.2s ease-out;
&:hover {
transform: scale(1.1);
}
}
span:last-child {
margin-right: 0;
}
}
.previewImage_btn {
width: 40px;
height: 40px;
display: flex;
align-items: center;
justify-content: center;
font-size: 24px;
font-weight: 700;
color: #fff;
border-radius: 50%;
cursor: pointer;
user-select: none; //for chrome
-moz-user-select:none;//for firefox
}
}
.zoom-enter,
.zoom-leave-to {
// 元素进入和离开时的动作
transform: scale(0);
}
.zoom-enter-active,
.zoom-leave-active {
// 元素进入和离开时的过渡动画定义
transition: transform 0.3s;
}
.slide-enter,
.slide-leave-to {
// 元素进入和离开时的动作
transform: translateX(100%);
}
.slide-enter-active,
.slide-leave-active {
// 元素进入和离开时的过渡动画定义
transition: transform 0.3s ease-in-out;
}
</style>