Vue3实现图片滚轮缩放和拖拽
在项目开发中遇到一个需求:
1:用鼠标滚轮可对图片进行缩放处理
2:点击按钮可对图片进行缩放处理
3:可对图片进行拖拽处理
我在开发中通过自己实现与百度查看优秀的铁子进行了两种类型的使用

<template>
<div ref="imgWrap" class="wrap" @mousewheel.prevent="rollImg">
<img :src="url" alt ref="image" @mousedown.prevent="moveImg" />
</div>
</template>
<script setup>
import { ref } from 'vue'
const url = ref("https://w.wallhaven.cc/full/8o/wallhaven-8oky1j.jpg") const image = ref(null)
const rollImg = (e) => {
let transform = image.value.style.transform
let zoom = transform.indexOf("scale") != -1 ? +transform.split("(")[1].split(")")[0] : 1
zoom += e.wheelDelta / 1200
if (zoom > 0.1 && zoom < 2) {
image.value.style.transform = "scale(" + zoom + ")"
}
} const imgWrap = ref(null)
const moveImg = (e) => {
let wrap = imgWrap.value
let img = image.value
let x = e.pageX - img.offsetLeft
let y = e.pageY - img.offsetTop
// 添加鼠标移动事件
wrap.addEventListener('mousemove', move)
function move(e) {
img.style.left = e.pageX - x + 'px'
img.style.top = e.pageY - y + 'px'
}
// 添加鼠标抬起事件,鼠标抬起,将事件移除
img.addEventListener('mouseup', () => {
wrap.removeEventListener('mousemove', move)
})
// 鼠标离开父级元素,把事件移除
wrap.addEventListener('mouseout', () => {
wrap.removeEventListener('mousemove', move)
})
}
</script> <style lang='less' scoped>
.wrap {
position: relative;
width: 100vw;
height: 100vh;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
}
img {
position: absolute;
cursor: move;
}
</style>
顺便又写了个vue2 的
<template>
<!-- 舆图库详情页 -->
<div class="mainPage"> <div class="watchMap">
<div class="imgBox" ref="maskBox" @mousedown="onmousedownHandle">
<img :src="data:imageUrl" alt="" :style="{
width: imgW + 'px',
height: imgH + 'px',
top: top + 'px',
left: left + 'px',
transform: scale,
}" />
</div> <div class="Tools">
<div class="Tools-item" @click="imgScaleHandle(0.25)">
大
</div>
<div class="Tools-item" @click="imgScaleHandle(-0.25)">
小
</div>
<div class="Tools-item">
藏
</div>
<div class="Tools-item" @click="
downloadByBlob(
'https://img2.baidu.com/it/u=1395980100,2999837177&fm=253&fmt=auto&app=120&f=JPEG?w=1200&h=675',
'name'
)
">
下载
</div>
</div>
</div> </div>
</template> <script>
export default { data() {
return {
imageUrl:
"https://img2.baidu.com/it/u=1395980100,2999837177&fm=253&fmt=auto&app=120&f=JPEG?w=1200&h=675", imgW: 0,
imgH: 0,
deg: 0,
top: 0,
left: 0,
scale: "scale(1)",
size: 0,
mousewheelevt: null,
};
}, mounted() {
//初始化图片
this.initImage(); // 兼容火狐浏览器
this.mousewheelevt = /Firefox/i.test(navigator.userAgent)
? "DOMMouseScroll"
: "mousewheel";
// 为空间区域绑定鼠标滚轮事件 =》 处理函数是wheelHandle
// 如果你监听了window的scroll或者touchmove事件,你应该把passive设置为true,这样滚动就会流畅很多
this.$refs.maskBox.addEventListener(this.mousewheelevt, this.wheelHandle);
},
beforeDestroy() {
//取消监听
this.$refs.maskBox.removeEventListener(
this.mousewheelevt,
this.wheelHandle
);
},
created() {
this.handleReset();
},
methods: {
/**
*
* 下載圖片
* **/ downloadByBlob(url, name) {
let image = new Image();
image.setAttribute("crossOrigin", "anonymous");
image.src = url;
image.onload = () => {
let canvas = document.createElement("canvas");
canvas.width = image.width;
canvas.height = image.height;
let ctx = canvas.getContext("2d");
ctx.drawImage(image, 0, 0, image.width, image.height);
canvas.toBlob((blob) => {
let url = URL.createObjectURL(blob);
this.download(url, name);
// 用完释放URL对象
URL.revokeObjectURL(url);
});
};
},
download(href, name) {
let eleLink = document.createElement("a");
eleLink.download = name;
eleLink.href = href;
eleLink.click();
eleLink.remove();
}, /**
* 重置
*/
handleReset() {
this.imgW = 0;
this.imgH = 0;
this.top = 0;
this.left = 0;
this.deg = 0;
this.scale = "scale(1)";
this.size = 0;
this.initImage();
},
/**
* 获取图片的url
* @param {string} url
*/
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 whRatio = realWidth / realHeight;
const hwRatio = realHeight / realWidth; //获取盒子的大小
const boxW = this.$refs.maskBox.clientWidth;
const boxH = this.$refs.maskBox.clientHeight; if (realWidth >= realHeight) {
this.imgH = hwRatio * boxW;
const nih = this.imgH;
if (nih > boxH) {
this.imgH = boxH;
this.imgW = whRatio * boxH;
} else {
this.imgW = boxW;
}
this.top = (boxH - this.imgH) / 2;
this.left = (boxW - this.imgW) / 2;
} else {
this.imgW = (boxH / realHeight) * realWidth;
this.imgH = boxH;
this.left = (boxW - this.imgW) / 2;
}
},
imgScaleHandle(zoom) {
this.size += zoom;
if (this.size < -0.5) {
this.size = -0.5;
}
this.scale = `scale(${1 + this.size}) rotateZ(${this.deg}deg)`;
},
/**
* 鼠标滚动 实现放大缩小
*/
wheelHandle(e) {
e.preventDefault();
const ev = e || window.event; // 兼容性处理 => 火狐浏览器判断滚轮的方向是属性 detail,谷歌和ie浏览器判断滚轮滚动的方向是属性 wheelDelta
// dir = -dir; // dir > 0 => 表示的滚轮是向上滚动,否则是向下滚动 => 范围 (-120 ~ 120)
const dir = ev.detail ? ev.detail * -120 : ev.wheelDelta;
//滚动的数值 / 2000 => 表示滚动的比例,用此比例作为图片缩放的比例
this.imgScaleHandle(dir / 2000);
},
/**
* 处理图片拖动
*/
onmousedownHandle(e) {
const that = this;
this.$refs.maskBox.onmousemove = function (el) {
const ev = el || window.event; // 阻止默认事件
ev.preventDefault();
that.left += ev.movementX;
that.top += ev.movementY;
};
this.$refs.maskBox.onmouseup = function () {
// 鼠标抬起时将操作区域的鼠标按下和抬起事件置为null 并初始化
that.$refs.maskBox.onmousemove = null;
that.$refs.maskBox.onmouseup = null;
};
if (e.preventDefault) {
e.preventDefault();
} else {
return false;
}
},
},
};
</script> <style lang="scss" scoped>
.world_map {
width: 1200px;
margin: 41px auto; .name {
width: 95px;
margin: 0 auto;
font-size: 22px;
font-family: "st";
font-weight: bold;
color: pink;
line-height: 30px;
letter-spacing: 1px;
}
} .watchMap {
width: 1200px;
height: 662px;
background: pink;
position: relative;
// overflow: hidden;
margin-left: 360px; .imgBox {
width: 100%;
height: 100%;
overflow: hidden;
position: relative; img {
cursor: move;
position: absolute;
}
} .Tools {
width: 43px;
min-height: 100px;
position: absolute;
right: -50px;
top: 0;
user-select: none; .Tools-item {
width: 100%;
height: 44px;
background: pink;
margin-bottom: 5px;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer; } .Tools-item:hover{
background-color: red;
color: #fff;
}
}
}
</style>

写在最后,
图片的拖拽和缩放动态的给图片赋值宽高和位置
Vue3实现图片滚轮缩放和拖拽的更多相关文章
- C#pictureBox滚轮缩放与拖拽
[转载]C#pictureBox滚轮缩放与拖拽 [转载]C#中图像平移.缩放的实现技巧 [转载]c# 通过鼠标拖动.放大图片,GDI绘图通过鼠标拖动.放大
- C# 之文件拖拽和pixturBox缩放与拖拽
文件拖拽: 效果:将一个文件拖拽到窗体的某个控件时,将该控件的路径显示在该控件上,只要拿到了路径自然可以读取文件中的内容了. 将一个控件的属性AllowDrop设置为true,然后添加DragDrop ...
- flutter实现可缩放可拖拽双击放大的图片功能
flutter实现可缩放可拖拽双击放大的图片功能 可缩放可拖拽的功能,可实现图片或者其他widget的缩放已经拖拽并支持双击放大的功能 我们知道官方提供了双击缩放,但是不支持拖拽的功能,我们要实现向百 ...
- 缩放系列(三):一个可以手势缩放、拖拽、旋转的layout
弄了一个下午,终于搞出来了,PowerfulLayout 下面是一个功能强大的改造的例子: 可以实现以下需求: 1.两个手指进行缩放布局 2.所有子控件也随着缩放, 3.子控件该有的功能不能丢失(像b ...
- Android 自定义ImageView支持缩放,拖拽,方便复用
今天刚发了一篇关于ImageView的缩放和拖拽的博客,然后我想了下,将他自定义下,方便我们来复用这个imageView,效果我就不多说了,http://blog.csdn.net/xiaanming ...
- AJ学IOS(36)UI之手势事件旋转_缩放_拖拽
AJ分享,必须精品 效果 完成一个图片的捏合缩放,拖拽,旋转动作. 设计思路 拖拽: 首先是最简单的拖拽 //拖拽 -(void)panTest { UIPanGestureRecognizer *p ...
- C#实现GDI+基本图的缩放、拖拽、移动
C#实现GDI+基本图的缩放.拖拽.移动示例代码如下: using System;using System.Collections.Generic;using System.ComponentMode ...
- 在viewPager中双指缩放图片,双击缩放图片,单指拖拽图片
我们就把这个问题叫做图片查看器吧,它的主要功能有: (项目地址:https://github.com/TZHANHONG/ImageViewer/releases/tag/1.0,里面的MyImage ...
- C# 图片缩放,拖拽后保存成图片的功能
窗体界面部分如下: 鼠标的缩放功能需要手动在 OpertaionImg.Designer.cs 文件里面添加一句代码,具体代码如下: //picturePhoto显示图片的控件 this.pictur ...
- vue富文本编辑器vue-quill-editor使用总结(包含图片上传,拖拽,放大和缩小)
vue-quill-editor是vue很好的富文本编辑器,富文本的功能基本上都支持,样式是黑白色,简洁大方. 第一步下载 vue-quill-editor: npm i vue-quill-edit ...
随机推荐
- Servlet中访问路径配置为/*时,使用请求转发造成内存溢出
一.问题由来 最近在测试Servlet的请求转发功能,准备抽取一个公共的PageJumpTestServlet,用来做页面跳转功能. 这样不用每次在测试的时候,都单独写一个Servlet用来做页面跳转 ...
- IIS web.config 跨域设置 不包含 options的设置 thinkphp tp3 跨域
web.config <?xml version="1.0" encoding="UTF-8"?> <configuration> &l ...
- cpp面向对象
面向对象编程 目录 面向对象编程 类 拷贝构造函数 常量函数 友元 友元函数 友元类 静态成员 重载函数 函数重载 操作符重载 继承 多态 虚函数 虚析构函数 1.虚析构函数的作用:避免内存泄漏. 2 ...
- 03.Android崩溃Crash库之ExceptionHandler分析
目录总结 00.异常处理几个常用api 01.UncaughtExceptionHandler 02.Java线程处理异常分析 03.Android中线程处理异常分析 04.为何使用setDefaul ...
- 使用JMeter从JSON响应的URL参数中提取特定值
在使用Apache JMeter进行API测试时,我们经常需要从JSON格式的响应中提取特定字段的值.这可以通过使用JMeter内置的JSON提取器和正则表达式提取器来完成.以下是一个具体的例子,展示 ...
- 开发必会系列:为什么要用spring
Spring是于2003 年兴起的一个轻量级的Java 开发框架,开源的,由Rod Johnson 在其著作Expert One-On-One J2EE Development and Design中 ...
- Redis源码学习(1)──字符串
redis 版本:5.0 本文代码在Redis源码中的位置:redis/src/sds.c.redis/src/sds.h 源码整体结构 src:核心实现代码,用 C 语言编写 tests:单元测试代 ...
- C# 人脸检测 人脸比对 活体检测 口罩检测 年龄预测 性别预测 眼睛状态检测
基于以下开源软件做了一个Demo GitHub - ViewFaceCore/ViewFaceCore: C# 超简单的离线人脸识别库.( 基于 SeetaFace6 ) 效果 代码 using Sy ...
- 软件发布版本号命名风格(GUN)
GUN风格: (1)产品初版时,版本号可以为0.1或0.1.0,也可以为1.0或1.0.0: (2)当产品进行了局部修改或bug修正时,主版本号和子版本号都不变,修正版本号+1: (3)当产品在原有的 ...
- IntelliJ IDEA 设置类和方法注释
一.在创建类和文件的时候加注释 1.创建类 在右侧输入: 1 /** 2 * 3 * @author ${USER} 4 * @date ${YEAR}-${MONTH}-${DAY} ${TIME} ...