图片预览组件 (放大 缩小 旋转 鼠标拖动)
1.图片预览组件 (放大 缩小 旋转 鼠标拖动)
效果图
其中的图片初始化 不需要 如果需要可自行修改一下
**完整代码如下 **
点击查看代码
<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>
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~