利用vue組件實(shí)現(xiàn)圖片的拖拽和縮放功能
前言
vue實(shí)現(xiàn)一個(gè)組件其實(shí)很簡(jiǎn)單但是要寫出一個(gè)好的可復(fù)用的組件那就需要多學(xué)習(xí)和鉆研一下,一個(gè)好的組件必須有其必不可少的有優(yōu)點(diǎn):一是能提高應(yīng)用開發(fā)效率、測(cè)試性、復(fù)用性等;二是組件應(yīng)該是高內(nèi)聚、低耦合的;三是組件應(yīng)遵循單向數(shù)據(jù)流的原則。
在實(shí)現(xiàn)我的圖片的拖拽組件我們的搞清其原理,在這里我使用的是mousedown,mousemove和mouseup來(lái)實(shí)現(xiàn)拖拽。
如圖所示:

方法如下:
1.新建ElementDrag.vue文件內(nèi)容如下:
<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變量來(lái)判斷鼠標(biāo)是否按下, 如果isMousedown === true鼠標(biāo)移動(dòng)就改變darg-inner位置。
<script>
export default {
name: 'ElementDrag',
data() {
return {
isMousedown: false, //鼠標(biāo)是否按下
moveStart: {x: 0, y: 0}, //拖拽元素初始位置
translate: {x: 0, y: 0}, //計(jì)算拖拽元素在下下x,y方向各移動(dòng)了多少
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.樣式部分我們?cè)O(shè)置外層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.添加鼠標(biāo)滾輪事件縮放drag-inner元素, e.wheelDelta為正表示放大,為負(fù)縮小,值越大表示滾動(dòng)越快。通過scale控制拖拽元素縮放。同過對(duì)組件傳值scaleZoom來(lái)控制其縮放最大最小程度值。
...
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.以上代碼已經(jīng)實(shí)現(xiàn)了功能我們預(yù)期的功能,但是為了更好的體驗(yàn),需要進(jìn)一步優(yōu)化組件。添加isHover來(lái)控制鼠標(biāo)是否移動(dòng)到了drag-outer以外,如果isHover為false這時(shí)鼠標(biāo)滾輪滾動(dòng)不會(huì)縮放元素,并且將isMousedown設(shè)置為false。再使用插槽slot預(yù)覽位置。
<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文件使用:點(diǎn)擊體驗(yàn)
<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>總結(jié)
到此這篇關(guān)于利用vue組件實(shí)現(xiàn)圖片的拖拽和縮放功能的文章就介紹到這了,更多相關(guān)vue組件實(shí)現(xiàn)圖片拖拽縮放內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
VUEJS 2.0 子組件訪問/調(diào)用父組件的實(shí)例
下面小編就為大家分享一篇VUEJS 2.0 子組件訪問/調(diào)用父組件的實(shí)例。具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來(lái)看看吧2018-02-02
Vue手動(dòng)控制點(diǎn)擊事件Click觸發(fā)方式
這篇文章主要介紹了Vue手動(dòng)控制點(diǎn)擊事件Click觸發(fā)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-01-01
vue.js動(dòng)態(tài)數(shù)據(jù)綁定學(xué)習(xí)筆記
這篇文章主要為大家詳細(xì)介紹了vue.js動(dòng)態(tài)數(shù)據(jù)綁定學(xué)習(xí)筆記,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-05-05
利用Vue3實(shí)現(xiàn)一個(gè)可以用js調(diào)用的組件
最近遇到個(gè)功能要求,想要在全局中調(diào)用組件,而且要在某些js文件內(nèi)調(diào)用,所以這篇文章主要給大家介紹了關(guān)于如何利用Vue3實(shí)現(xiàn)一個(gè)可以用js調(diào)用的組件的相關(guān)資料,需要的朋友可以參考下2021-08-08
vue中使用 pinia 全局狀態(tài)管理的實(shí)現(xiàn)
本文主要介紹了vue中使用 pinia 全局狀態(tài)管理的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07
vue3中如何使用ref和reactive定義和修改響應(yīng)式數(shù)據(jù)(最新推薦)
這篇文章主要介紹了vue3中如何使用ref和reactive定義和修改響應(yīng)式數(shù)據(jù),這里就是vue3中setup組合式api中如何定義響應(yīng)式數(shù)據(jù)并且修改賦值全部?jī)?nèi)容,需要的朋友可以參考下2022-12-12
vue中子組件向父組件傳遞數(shù)據(jù)的實(shí)例代碼(實(shí)現(xiàn)加減功能)
這篇文章主要介紹了vue中子組件向父組件傳遞數(shù)據(jù)的實(shí)例代碼(實(shí)現(xiàn)加減功能) ,需要的朋友可以參考下2018-04-04

