vue组件实现图片的拖拽和缩放
vue实现一个组件其实很简单但是要写出一个好的可复用的组件那就需要多学习和钻研一下,一个好的组件必须有其必不可少的有优点:一是能提高应用开发效率、测试性、复用性等;二是组件应该是高内聚、低耦合的;三是组件应遵循单向数据流的原则。
在实现我的图片的拖拽组件我们的搞清其原理,在这里我使用的是mousedown,mousemove和mouseup来实现拖拽。如图所示:

1.新建ElementDrag.vue文件内容如下:
<template>
<div class="drag-outer"
ref="dragWrap"
@mousemove="dragMousemove">
<div class="drag-inner"
ref="dragElement"
@mousedown="dragMousedown"
@mouseup.stop="isMousedown = false">
<slot></slot>
</div>
</div>
</template>
2. 定义moveStart用于记录拖拽元素初始位置。定义isMousedown变量来判断鼠标是否按下, 如果isMousedown === true鼠标移动就改变darg-inner位置。
<script>
export default {
name: 'ElementDrag',
data() {
return {
isMousedown: false, //鼠标是否按下
moveStart: {x: 0, y: 0}, //拖拽元素初始位置
translate: {x: 0, y: 0}, //计算拖拽元素在下下x,y方向各移动了多少
scale: 1, //拖拽元素缩放值
}
},
methods: {
dragMousedown() {
this.moveStart.x = event.clientX
this.moveStart.y = event.clientY
this.isMousedown = true
},
dragMousemove() {
if(this.isMousedown) {
this.translate.x += (event.clientX - this.moveStart.x) / this.scale
this.translate.y += (event.clientY - this.moveStart.y) / this.scale
this.$refs.dragElement.style.transform = `scale(${this.scale}) translate(${this.translate.x}px, ${this.translate.y}px)`
this.moveStart.x = event.clientX
this.moveStart.y = event.clientY
}
}
}
}
</script>
3.样式部分我们设置外层drag-outer用flex布局让里面元素快速居中, user-drag: none;禁用图片等元素的可拖拽属性。
<style lang="scss" scoped>
.drag-outer {
width: 100%;
height: 100%;
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
.drag-inner {
transform-origin: center center;
display: flex;
justify-content: center;
align-items: center;
cursor: move;
user-select: none;
>* {
-webkit-user-drag: none;
user-drag: none;
}
}
}
</style>
4.添加鼠标滚轮事件缩放drag-inner元素, e.wheelDelta为正表示放大,为负缩小,值越大表示滚动越快。通过scale控制拖拽元素缩放。同过对组件传值scaleZoom来控制其缩放最大最小程度值。
...
methods: {
props: {
type: Object,
default(){
return {
min: 0.5,
max: 5
}
}
},
...
handleScroll(e) {
let speed = e.wheelDelta/120
if(e.wheelDelta > 0 && this.scale < this.scaleZoom.max) {
this.scale+=0.04*speed
this.$refs.dragElement.style.transform = `scale(${this.scale}) translate(${this.translate.x}px, ${this.translate.y}px)`
}else if(e.wheelDelta < 0 && this.scale > this.scaleZoom.min){
this.scale+=0.04*speed
this.$refs.dragElement.style.transform = `scale(${this.scale}) translate(${this.translate.x}px, ${this.translate.y}px)`
}
}
},
mounted() {
window.addEventListener('mousewheel',this.handleScroll,false)
}
5.以上代码已经实现了功能我们预期的功能,但是为了更好的体验,需要进一步优化组件。添加isHover来控制鼠标是否移动到了drag-outer以外,如果isHover为false这时鼠标滚轮滚动不会缩放元素,并且将isMousedown设置为false。再使用插槽slot预览位置。
<template>
<div class="drag-outer"
ref="dragWrap"
@mouseenter="isHover = true"
@mouseleave="isHover = isMousedown = false"
@mousemove="dragMousemove">
<div class="drag-inner"
ref="dragElement"
@mousedown="dragMousedown"
@mouseup.stop="isMousedown = false">
<slot></slot>
</div>
</div>
</template>
....
data() {
return {
...,
isHover: false,
}
},
methods: {
...
handleScroll(e) {
if(this.isHover) {
let speed = e.wheelDelta/120
if(e.wheelDelta > 0 && this.scale < this.scaleZoom.max) {
this.scale+=0.04*speed
this.$refs.dragElement.style.transform = `scale(${this.scale}) translate(${this.translate.x}px, ${this.translate.y}px)`
}else if(e.wheelDelta < 0 && this.scale > this.scaleZoom.min){
this.scale+=0.04*speed
this.$refs.dragElement.style.transform = `scale(${this.scale}) translate(${this.translate.x}px, ${this.translate.y}px)`
}
}
}
}
贴上组件的最终代码:
<template>
<div class="drag-outer"
ref="dragWrap"
:style="outerOptions"
@mouseenter="isHover = true"
@mouseleave="isHover = isMousedown = false"
@mousemove="dragMousemove">
<div class="drag-inner"
ref="dragElement"
:style="innerOptions"
@mousedown="dragMousedown"
@mouseup.stop="isMousedown = false">
<slot></slot>
</div>
</div>
</template>
<script>
export default {
name: 'ElementDrag',
props: {
outerOptions: {
type: Object,
default () {
return {
background: 'rgba(0,0,0,0.9)'
}
}
},
innerOptions: {
type: Object,
default () {
return {
background: 'rgba(0,0,0,0.1)',
}
}
},
scaleZoom: {
type: Object,
default () {
return {
max: 5,
min: 0.2
}
}
}
},
data() {
return {
isMousedown: false,
isHover: false,
moveStart: {},
translate: {x: 0, y: 0},
scale: 1
}
},
methods: {
handleScroll(e) {
if(this.isHover) {
let speed = e.wheelDelta/120
if(e.wheelDelta > 0 && this.scale < this.scaleZoom.max) {
this.scale+=0.04*speed
this.$refs.dragElement.style.transform = `scale(${this.scale}) translate(${this.translate.x}px, ${this.translate.y}px)`
}else if(e.wheelDelta < 0 && this.scale > this.scaleZoom.min){
this.scale+=0.04*speed
this.$refs.dragElement.style.transform = `scale(${this.scale}) translate(${this.translate.x}px, ${this.translate.y}px)`
}
}
},
dragMousedown() {
this.moveStart.x = event.clientX
this.moveStart.y = event.clientY
this.isMousedown = true
},
dragMousemove() {
if(this.isMousedown) {
this.translate.x += (event.clientX - this.moveStart.x) / this.scale
this.translate.y += (event.clientY - this.moveStart.y) / this.scale
this.$refs.dragElement.style.transform = `scale(${this.scale}) translate(${this.translate.x}px, ${this.translate.y}px)`
this.moveStart.x = event.clientX
this.moveStart.y = event.clientY
}
}
},
mounted() {
window.addEventListener('mousewheel',this.handleScroll,false)
}
}
</script>
<style lang="scss" scoped>
.drag-outer {
width: 100%;
height: 100%;
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
.drag-inner {
transform-origin: center center;
display: flex;
justify-content: center;
align-items: center;
cursor: move;
user-select: none;
>* {
-webkit-user-drag: none;
user-drag: none;
}
}
}
</style>
在home.vue文件使用:点击体验
<template>
<div class="home">
<ElementDrag>
<img src="https://img0.baidu.com/it/u=937276518,3474029246&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=750">
</ElementDrag>
</div>
</template>
<script>
import ElementDrag from '@/components/ElementDrag'
export default {
name: 'Home',
components: {
ElementDrag
}
}
</script>
<style scoped>
.home {
width: 100vw;
height: 100vh;
}
</style>
vue组件实现图片的拖拽和缩放的更多相关文章
- Winform图片拖拽与缩放
最近做项目的时候遇到上传施工平面布置图,查看,因为图片比较大,一般的显示器分辨率无法显示全,然后还需要放大看清楚图片里面的文字内容,所以需要用到图片的拖拽与缩放功能.这里整理下具体操作. 首先新建一个 ...
- 在 Element-UI 的 Table 组件上添加列拖拽效果
Element-UI 的 Table组件很强大,但是我们的需求更强大... 简单粗暴的来一发效果图: 一.数据驱动 传统的拖动效果,都是基于通过 mousedown.mousemove.mouseup ...
- vue-drag-resize 可拖拽可缩放的标签,如何管理多个拖拽元素之间的zIndex?操作上需要保持当前激活的组件是最上层,但是在总体上,又要确保其图层管理的顺序。
麻烦总是不断出现,还好办法总比困难多, 1.公司开发一款可视化编辑html网页的多媒体编辑平台,牵扯到标签元素的拖拽,缩放,我找了找方法发现原生技术实现起来代码太多,麻烦,还好找到了一个vue组件,可 ...
- Qt之股票组件-自选股--列表可以拖拽、右键常用菜单
目录 一.开头嘴一嘴 二.效果展示 三.自选股列表 1.列表初始化 2.添加Item 3.右键菜单 4.拖拽Item 5.刷新数据 四.相关文章 原文链接:Qt之股票组件-自选股--列表可以拖拽.右键 ...
- Ant Design -- 图片可拖拽效果,图片跟随鼠标移动
Ant Design 图片可拖拽效果,图片跟随鼠标移动,需计算鼠标在图片中与图片左上角的X轴的距离和鼠标在图片中与图片左上角的Y轴的距离. constructor(props) { super(pro ...
- H5拖拽 构造拖拽及缩放 pdf展示
前言: 协助项目需要实现一个签名的功能. 功能说明:1.有文本签名和头像签名.2.头像签名需要实现可拖拽功能.3.需要展示的是pdf的文件并需要获取签名位于pdf文件的相对位置. 功能一:实现拖拽 思 ...
- H5拖拽 构造拖拽及缩放 pdf文件转换为html预览
前言: 协助项目需要实现一个签名的功能. 功能说明:1.有文本签名和头像签名.2.头像签名需要实现可拖拽功能.3.需要展示的是pdf的文件并需要获取签名位于pdf文件的相对位置. 功能一:实现拖拽 思 ...
- svg拖拽和缩放
需求:做机房平面图,用svg实现拖拽和缩放,刚开始一头雾水,不知所措,好在皇天不负有心人........ 本文重点介绍拖拽,单纯实现很简单,但是由于vue项目,机房图有很多事件,拖拽就成了难点 简单介 ...
- JS利用 Sea.js 实现模块化:拖拽、缩放及范围限制
知识点总结: Sea.js的使用:define.export.seajs.use.require等方法: 参考:http://seajs.org/docs/ Sea.js与require.js的区 ...
随机推荐
- LuoguP7398 [COCI2020-2021#5] Šifra 题解
Content 给定一个长度 \(n\) 的只包含小写字母和 \(0\sim9\) 的字符串(字符串中的字母可视为分隔符).求字符串中包含多少个不同的数字. 数据范围:\(1\leqslant n\l ...
- java 编程基础 类加载器
什么是类加载器 类加载器负责将class文件(可能在磁盘上,也可能在网络上)加载到内存中,并为之生成对应的java.lang.Class对象.Java开发中无须过分关心类加载机制,但所有的编程人员都应 ...
- tomcat Address already in use: JVM_Bind
运行多个tomcat时,出现tomcat Address already in use: JVM_Bind这个错误,可以按照如下方式解决: 修改F:\tomcat20111101\apache-tom ...
- SpringBoot整合Apache Shiro
Subject 用户主体 (把操作交给SecurityManager)SecurityManager 安全管理器 (关联Realm)Realm Shiro连接数据的桥梁 引入maven依赖 < ...
- 【LeetCode】1419. 数青蛙 Minimum Number of Frogs Croaking (Python)
作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 字典 日期 题目地址:https://leetcode ...
- 【LeetCode】383. Ransom Note 解题报告(Java & Python)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 Java解法 Python解法 日期 [LeetCo ...
- 【LeetCode】538. Convert BST to Greater Tree 解题报告(Python)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 递归 日期 题目地址:https://leetcod ...
- v75.01 鸿蒙内核源码分析(远程登录篇) | 内核如何接待远方的客人 | 百篇博客分析OpenHarmony源码
子曰:"不学礼,无以立 ; 不学诗,无以言 " <论语>:季氏篇 百篇博客分析.本篇为: (远程登录篇) | 内核如何接待远方的客人 设备驱动相关篇为: v67.03 ...
- uniapp 兼容H5复制文本功能,亲测可用
封装copyText函数,具体如下: copyText(val){ let result // #ifndef H5 uni.setClipboardData({ data: val, success ...
- vue 把字符串的所有=替换成&&&的方法
//把字符串中所有=换成&&& let reg=new RegExp('=','g')//g代表全部 let newMsg=JSON.stringify(msg).replac ...