Vue2 实现图片的拖拽、缩放、旋转

news2024/11/18 15:48:50

本文是基于vue2 实现图片的拖拽、旋转、鼠标滚动放大缩小等功能。

效果图

分步骤实现

在这里看下 拖拽、旋转、缩放的几个方法

1.获取图片的实际宽高

getImgSize(url) {return new Promise((resolve, reject) => {let imgObj = new Image();imgObj.src = url;imgObj.onload = () => {resolve({width: imgObj.width,height: imgObj.height,});};});
}, 

2.根据盒子的大小、图片的大小来计算 要显示多大的图片

 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;}}, 

在这里主要是根据图片的宽高 ,以及盒子的大小来计算 盒子中展示多大的图片,将图片按照比例缩放后展示到盒子中。

3.拖拽图片

主要是监听@mousedown事件

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;}
}, 

4. 旋转图片

handleRotate() {this.deg += 90;if (this.deg >= 360) {this.deg = 0;}this.size = 0;this.scale = `scale(1) rotateZ(${this.deg}deg)`;
}, 

5.监听鼠标的滚动,进行缩放图片

在 mounted() 中监听鼠标的滚动事件

mounted() {// 兼容火狐浏览器this.mousewheelevt = /Firefox/i.test(navigator.userAgent)? "DOMMouseScroll" : "mousewheel";// 为空间区域绑定鼠标滚轮事件 =》 处理函数是wheelHandle// 如果你监听了window的scroll或者touchmove事件,你应该把passive设置为true,这样滚动就会流畅很多this.$refs.maskBox.addEventListener(this.mousewheelevt, this.wheelHandle, {passive:true});
}, 

处理鼠标的滚动事件

wheelHandle(e) {// 兼容性处理 => 火狐浏览器判断滚轮的方向是属性 detail,谷歌和ie浏览器判断滚轮滚动的方向是属性 wheelDeltaconst ev = e || window.event;// dir = -dir; // dir > 0 => 表示的滚轮是向上滚动,否则是向下滚动 => 范围 (-120 ~ 120)const dir = ev.detail ? ev.detail * -120 : ev.wheelDelta;//滚动的数值 / 2000 => 表示滚动的比例,用此比例作为图片缩放的比例this.imgScaleHandle(dir / 2000);
}, 

放大缩小图片

/**
 * 图片的缩放
 * zoom >0 放大
 * zoom <0 缩小
 */
imgScaleHandle(zoom) {this.size += zoom;if (this.size < -0.5) {this.size = -0.5;}this.scale = `scale(${1 + this.size}) rotateZ(${this.deg}deg)`;
}, 

页面销毁的时候 注意要取消鼠标的监听事件

beforeDestroy() {//取消监听this.$refs.maskBox.removeEventListener(this.mousewheelevt,this.wheelHandle,{passive:true});
}, 

以上就是主要实现功能的方法

完整代码

<template><div class="home"><div class="btn-area"><button @click="switchImgHandle(1)">竖图</button><button @click="switchImgHandle(2)">横图</button><button @click="handleRotate">旋转</button><button @click="imgScaleHandle(0.25)">放大</button><button @click="imgScaleHandle(-0.25)">缩小</button><button @click="handleReset">重置</button></div><div class="image-box" ref="maskBox" @mousedown="onmousedownHandle"><img :src="imageUrl" alt="" :style="{width: imgW + 'px', height: imgH + 'px',top: top + 'px', left: left + 'px', transform: scale, }" /></div></div>
</template>

<script>
export default {name: "HomeView",data() {return {imageUrl: "",imageUrl1: require("@/assets/img1.jpg"),imageUrl2: require("@/assets/img2.jpg"),imgW: 0,imgW: 0,imgH: 0,deg: 0,top: 0,left: 0,scale: "scale(1)",size: 0,mousewheelevt: null,};},mounted() {this.imageUrl = this.imageUrl1;//初始化图片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, { passive:true});},beforeDestroy() {//取消监听this.$refs.maskBox.removeEventListener(this.mousewheelevt,this.wheelHandle,{passive:true});},methods: {/** * 切换图片 *flag: 1竖图 2 横图 */switchImgHandle(flag) {if (flag === 1) {this.imageUrl = this.imageUrl1;} else {this.imageUrl = this.imageUrl2;}this.handleReset();},/** * 获取图片的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;}},/** * 旋转 */handleRotate() {this.deg += 90;if (this.deg >= 360) {this.deg = 0;}this.size = 0;this.scale = `scale(1) rotateZ(${this.deg}deg)`;},/** * 图片的缩放 *zoom >0 放大 *zoom <0 缩小 */imgScaleHandle(zoom) {this.size += zoom;if (this.size < -0.5) {this.size = -0.5;}this.scale = `scale(${1 + this.size}) rotateZ(${this.deg}deg)`;},/** * 重置 */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();},/** * 鼠标滚动 实现放大缩小 */wheelHandle(e) {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 scoped>
.home {width: 1000px;margin: 50px auto;
}
.btn-area {display: flex;justify-content: center;width: 100%;margin-bottom: 50px;
}
.btn-area button {width: 100px;height: 40px;font-size: 18px;margin-right: 10px;
}
.image-box {position: relative;margin: 0 auto;width: 1000px;height: 700px;border: 1px solid #333;overflow: hidden;
}
.image-box img {position: absolute;cursor: pointer;
}
</style> 

最后

整理了一套《前端大厂面试宝典》,包含了HTML、CSS、JavaScript、HTTP、TCP协议、浏览器、VUE、React、数据结构和算法,一共201道面试题,并对每个问题作出了回答和解析。

有需要的小伙伴,可以点击文末卡片领取这份文档,无偿分享

部分文档展示:



文章篇幅有限,后面的内容就不一一展示了

有需要的小伙伴,可以点下方卡片免费领取

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/409475.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

插槽(slot)的基本使用

插槽&#xff08;slot&#xff09;的基本使用 一、插槽的作用 在开发中&#xff0c;我们会经常封装一个个可复用的组件&#xff1a; 前面我们会通过props传递给组件一些数据&#xff0c;让组件来进行展示&#xff1b; 但是为了让这个组件具备更强的通用性&#xff0c;我们不能…

Ubuntu搭建web站点并发布公网访问【内网穿透】

文章目录前言1. 本地环境服务搭建2. 局域网测试访问3. 内网穿透3.1 ubuntu本地安装cpolar3.2 创建隧道3.3 测试公网访问4. 配置固定二级子域名4.1 保留一个二级子域名4.2 配置二级子域名4.3 测试访问公网固定二级子域名前言 网&#xff1a;我们通常说的是互联网&#xff1b;站…

Vue3中使用vant(踩坑日记....)

我照着视频中老师教的方式去使用vant(和官网教程一样)&#xff0c;发现样式根本不起作用&#xff08;想截个图来着&#xff0c;但是vite热更新太厉害了&#xff0c;找不到了哈哈哈&#xff09;&#xff0c;然后又反复看了视频一遍&#xff0c;检查自己插件啥的而又没有安装好&a…

【TypeScript基础】TypeScript之常用类型(上)

前言 博主主页&#x1f449;&#x1f3fb;蜡笔雏田学代码 专栏链接&#x1f449;&#x1f3fb;【TypeScript专栏】 上篇文章大概了解了一下TypeScript&#xff0c;&#x1f449;&#x1f3fb;详细内容请阅读【TypeScript介绍】一文带你初步了解TypeScript 今天开始学习学习Type…

html实现用户注册页面(生日实现年月日的三级联动)

注册页面 期待效果如下&#xff1a; 初始代码实现&#xff1a; <!DOCTYPE html> <html> <head><title>注册页面</title> </head> <body> <!-- 表单&#xff0c;用于提交按钮&#xff0c;隐式提交 --> <form action"…

后台管理系统 - 页面布局设计

前端的中后台管理系统相比于其他普通项目&#xff0c;从开发设计的角度来说有几点比较特殊&#xff1a; 一个是权限设计&#xff0c;具体实现可参考&#xff1a;传送门。一个是页面布局的设计&#xff0c;也是本文要说的。一个好的页面布局设计&#xff0c;无论是对于页面结构…

Java Web实现登录注册(超详细附代码)

Java Web实现登录注册&#xff08;超详细附代码&#xff09; 文章目录Java Web实现登录注册&#xff08;超详细附代码&#xff09;1.前言2.登录注册设计流程3.注册的数据流程4.登录的数据流程5.部分代码的展示5.1注册5.2登录6.总结1.前言 相信刚学Javaweb的小伙伴第一个接触的…

30个极致实用的谷歌浏览器插件,让你开发事半功倍

浏览器是开发人员最强大的工具。99% 的人不会 100% 地利用他们的浏览器。这里有 30 个浏览器扩展&#xff0c;如果你能合理充分利用将大大提升你的开发效率。1. WhatFont"WhatFont"&#xff0c;是一款帮助用户快速识别网页中字体信息的工具。当你在浏览网页时&#x…

vue|axios发送post请求详解

axios发送Post请求 首先我们要知道发送一个请求体的时候我们要明确发送的类型是什么&#xff0c;常见的类型有三种 form-dataapplication/jsonapplication/x-www-form-urlencoded 以上三种类型是进行数据传输的数据类型&#xff0c;我们知道在js代码中的对象都不是以上的三种…

react实现路由跳转

react通过路由实现页面跳转&#xff1a; ​ 函数式路由(withRouter)使用原生js方法实现路由功能。 ​ eg&#xff1a;export default withRouter(Home) Home是组件名称。 示例&#xff1a;class Home extends Component{<button onClick{this.goForward}>下一级</bu…

猿创征文|【C++游戏引擎Easy2D】炫酷动画来这学,位移动画构造函数让节点执行动画

&#x1f9db;‍♂️iecne个人主页&#xff1a;&#xff1a;iecne的学习日志 &#x1f4a1;每天关注iecne的作品&#xff0c;一起进步 &#x1f4aa;学C必看iecne 本文专栏&#xff1a;【C游戏引擎】. &#x1f433;希望大家多多支持&#x1f970;一起进步呀&#xff01; ✨前…

from origin ‘null‘ has been blocked by CORS policy: Cross origin requests are only supported for ...

跨源资源请求问题解决方案 问题描述&#xff1a;当我们在vsCode中使用 open in brower插件打开html文件文件时&#xff0c;就会报错 xxx已被CORS策略阻止&#xff0c;引入的资源还会失效。 解决办法1 :Live Server插件 在vsCode的插件市场中搜索并安装Live Server插件&#x…

Axios

Axios是Ajax的一个框架&#xff0c;简化Ajax操作 一、基本操作 Axios执行Ajax的操作&#xff1a; 1. 添加axios的js文件 <script language"JavaScript" src"script/axios.min.js"></script> 2.1 客户端向服务端异步发送普通参数值 格式&am…

vue-router报错: uncaught error during route navigation

bug场景&#xff1a; H5项目中,浏览器流程走的通,ios流程走得通,安卓机有的可以有的不行 报错信息&#xff1a; 提示&#xff1a;这里描述项目中遇到的问题&#xff1a; 例如&#xff1a;数据传输过程中数据不时出现丢失的情况&#xff0c;偶尔会丢失一部分数据 APP 中接收数…

尚融宝06-ECMAScript基本介绍和使用

目录 一、ECMAScript 1、ECMA 2、ECMAScript 3、什么是 ECMA-262 4、ECMA-262 历史 5、ECMAScript 和 JavaScript 的关系 二、基本语法 1、let声明变量 2、const声明常量 3、解构赋值 4、模板字符串 5、声明对象简写 6、定义方法简写 7、参数的默认值 8、对象拓…

less变量

Less变量一、Less简介二、Less中的变量三、less外部引入一、Less简介 1.Less是一门css的预处理语言&#xff0c;less是一个css的增强版&#xff0c;通过less可以编写更少的代码实现更强大的样式。 变量名以两条短横线命名 例如&#xff1a; --color&#xff1a;red 2.Less特…

vue的created函数中方法执行的顺序设置方法

1.vue的created钩子函数中&#xff0c;方法的执行顺序 1.1情景&#xff1a;vue框架中通常在created钩子函数里执行访问数据库的方法&#xff0c;然后返回数据给前端&#xff0c;前端data中定义全局变量接收数据 1.2误区&#xff1a;我们可能会思考按照自己设定好的逻辑走&…

使用uni-app的uni.chooseImage获取的图片路径,存储到数据库中,无法在前端展示该路径的图片

html,js,uni-app, 首先我在uni-app中使用如下方法添加图片 uni.chooseImage({count: 1, //count: 6, //默认9sizeType: [original, compressed], //可以指定是原图还是压缩图&#xff0c;默认二者都有sourceType: [album], //从相册选择success: function(res) {console.log(…

【vue2】vue2中的性能优化(持续更新中)

⭐ v-for 遍历避免同时使用 v-if ⭐ v-for 中的key绑定唯一的值 ⭐ v-show与v-if对性能的影响 ⭐ 妙用计算属性 ⭐ 使用防抖与节流控制发送频率 ⭐ 路由守卫处理请求避免重复发送请求 ⭐ 使用第三方UI库的引入方式 【前言】 该系列是博主在使用vue2开发项目中常用上的一…

JavaScript ,18种常用数组方法,快来看看你会吗?

前言 众所周知&#xff0c;向后端请求数据&#xff0c;处理数据是前端工程师必备的技能&#xff0c;从后端请求回来的数据往往是数组的形式返回到前端&#xff0c;因此数组处理方法的重要性可想而知&#xff1b;数组的处理方法在MDN文档上很多&#xff0c;很多朋友在学习时往往…