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

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. Windows10 windows installer卸载或安装不了软件怎么办?

    先说我的方法:        1.把安装出现问题的软件或者想要卸载的软件的安装目录下的所有文件都删除.        2.用清理软件清理一下垃圾,包括注册表,这里我自己使用的是火绒->安全工具- ...

  2. git 全局用户名改为英文,中文生成的git记录文件 不能有中文,现场反馈 git config user.name

    设置用户名和邮箱 git config --global user.name "username" git config --global user.email useremail ...

  3. iview 日期组件 清空后验证没报红,需要在onChange 进行单独 validateField,因为空字符串校验没有触发

    // 日期组件的 onChange this.yourObj.xxxTime = item this.$refs.yourForm.validateField('xxxTime')

  4. C++学习笔记之指针引用

    目录 指针 指针定义 左值与右值 指针数组与数组指针 const与指针 指针的指针 NULL指针 内存泄漏(Memory Leak)问题 智能指针 引用 指针 指针定义 指针定义的基本形式:指针本身就 ...

  5. Python isinstance() 函数含义及用法解析

    描述 isinstance() 函数来判断一个对象是否是一个已知的类型,类似 type(). isinstance() 与 type() 区别: type() 不会认为子类是一种父类类型,不考虑继承关 ...

  6. Android 获取设备的亮度百分比

    一般的屏幕亮度都是0-255,而小米手机的高版本不一样 为了使亮度调节更加细腻, MIUI对原生亮度级别进行了扩展, 由原有的255级调整根据不同屏幕分别支持255/1023/2047/4095级.开 ...

  7. electron 下网页获取 micphone 权限

    网页获取麦克风或摄像头权限我们只需调用 navigator.mediaDevices.getUserMedia 方法就可唤起浏览器用户授权 const useMicphone = async () = ...

  8. 记录--Event Loop事件循环、微任务、宏任务

    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 前言 JS是一门单线程语言,单线程就意味着,所有的任务需要排队,前一个任务结束,才会执行下一个任务.这样所导致的问题是:如果JS执行的时间 ...

  9. MongoDB java.lang.ClassCastException: java.lang.Double cannot be cast to java.lang.Integer

    详细报错如下: java.lang.ClassCastException: java.lang.Double cannot be cast to java.lang.Integer     at or ...

  10. 二.安装ifconfig命令

    二.安装ifconfig命令 1.ifconfig命令是设置或显示网络接口的程序,可以显示出我们机器的网卡信息,可是有些时候最小化安装CentOS等Linux发行版的时候会默认不安装ifconfig等 ...