在项目开发中遇到一个需求:

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实现图片滚轮缩放和拖拽的更多相关文章

  1. C#pictureBox滚轮缩放与拖拽

    [转载]C#pictureBox滚轮缩放与拖拽 [转载]C#中图像平移.缩放的实现技巧 [转载]c# 通过鼠标拖动.放大图片,GDI绘图通过鼠标拖动.放大

  2. C# 之文件拖拽和pixturBox缩放与拖拽

    文件拖拽: 效果:将一个文件拖拽到窗体的某个控件时,将该控件的路径显示在该控件上,只要拿到了路径自然可以读取文件中的内容了. 将一个控件的属性AllowDrop设置为true,然后添加DragDrop ...

  3. flutter实现可缩放可拖拽双击放大的图片功能

    flutter实现可缩放可拖拽双击放大的图片功能 可缩放可拖拽的功能,可实现图片或者其他widget的缩放已经拖拽并支持双击放大的功能 我们知道官方提供了双击缩放,但是不支持拖拽的功能,我们要实现向百 ...

  4. 缩放系列(三):一个可以手势缩放、拖拽、旋转的layout

    弄了一个下午,终于搞出来了,PowerfulLayout 下面是一个功能强大的改造的例子: 可以实现以下需求: 1.两个手指进行缩放布局 2.所有子控件也随着缩放, 3.子控件该有的功能不能丢失(像b ...

  5. Android 自定义ImageView支持缩放,拖拽,方便复用

    今天刚发了一篇关于ImageView的缩放和拖拽的博客,然后我想了下,将他自定义下,方便我们来复用这个imageView,效果我就不多说了,http://blog.csdn.net/xiaanming ...

  6. AJ学IOS(36)UI之手势事件旋转_缩放_拖拽

    AJ分享,必须精品 效果 完成一个图片的捏合缩放,拖拽,旋转动作. 设计思路 拖拽: 首先是最简单的拖拽 //拖拽 -(void)panTest { UIPanGestureRecognizer *p ...

  7. C#实现GDI+基本图的缩放、拖拽、移动

    C#实现GDI+基本图的缩放.拖拽.移动示例代码如下: using System;using System.Collections.Generic;using System.ComponentMode ...

  8. 在viewPager中双指缩放图片,双击缩放图片,单指拖拽图片

    我们就把这个问题叫做图片查看器吧,它的主要功能有: (项目地址:https://github.com/TZHANHONG/ImageViewer/releases/tag/1.0,里面的MyImage ...

  9. C# 图片缩放,拖拽后保存成图片的功能

    窗体界面部分如下: 鼠标的缩放功能需要手动在 OpertaionImg.Designer.cs 文件里面添加一句代码,具体代码如下: //picturePhoto显示图片的控件 this.pictur ...

  10. vue富文本编辑器vue-quill-editor使用总结(包含图片上传,拖拽,放大和缩小)

    vue-quill-editor是vue很好的富文本编辑器,富文本的功能基本上都支持,样式是黑白色,简洁大方. 第一步下载 vue-quill-editor: npm i vue-quill-edit ...

随机推荐

  1. aardio用udp获取最佳本机IP地址

    此方法在有多个网络接口的时候,例如部分虚拟网卡的情况,获取最合适的本地ip. 用UDP连接虚假IP地址以获取返回的本机IP import wsock.udp.client; import consol ...

  2. ETL工具-KETTLE教程实例实战2----环境介绍

    一.整体结构图 Kettle 是"Kettle E.T.T.L. Envirnonment"只取首字母的缩写,这意味着它被设计用来帮助你实现你的ETTL 需要:抽取.转换.装入和加 ...

  3. JNI中AttachCurrentThread和DetachCurrentThread的问题

    在<Java与CC++交互JNI编程>中有讲过AttachCurrentThread和DetachCurrentThread的使用. 我们知道在jni中我们可以使用pthread或者std ...

  4. 干货分享 | 3个Zbrush实用减面工具分享

    一.使用Sculptris Pro Sculptris Pro是zbrush中的一个功能按钮,点击此工具按钮,同时将笔刷转换至standard笔刷,即可减去需要平滑的面. 点击开启Sculptris ...

  5. python基础四(字符编码)

    一 了解字符编码的知识储备 计算机基础知识 文本编辑器存取文件的原理(nodepad++,pycharm,word) #1.打开编辑器就打开了启动了一个进程,是在内存中的,所以,用编辑器编写的内容也都 ...

  6. 记录--用JS轻松实现一个录音、录像、录屏的工具库

    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 前言 最近项目遇到一个要在网页上录音的需求,在一波搜索后,发现了 react-media-recorder 这个库.今天就跟大家一起研究一 ...

  7. 开发必会系列:JavaEE持久层框架对比与hibernate主键生成策略总结

    一.持久层框架对比 ORM框架:即对象关系映射.它把数据库表映射到pojo类,然后通过对类的操作来实现对数据库的增删改查,sql语句自动生成. 对于代码开发者来说,就是在代码里先创建数据库连接对象,然 ...

  8. vue中$forceUpdate()的使用

    刷新数组的作用 this.$forceUpdate(); 具体请看:vue中$forceUpdate()的使用 - 简书 (jianshu.com)

  9. verilog之readmemb

    verilog之readmemb 1.基本作用 用于读取存储器的值的系统函数.这里首先要知道什么是存储器.在verilog中,有一些比较大的数据是需要存储的,一般需要使用存储器,语法结构类似二维数组. ...

  10. 英语文档阅读之Zynq-7000 All Programmable SoC

    Read "Zynq-7000 All programmable Soc" 1.Table of Contents 首先是目录,可以看到是标准的总分结构.开头介绍了Zynq的各种功 ...