개발 도구 (Development Tools)/Sample Code

클릭과 드래그 구분하기

BiCute 2022. 12. 15. 08:00
반응형

 

 

클릭이 가능한 카드형 박스지만, 내부 내용을 드래그해서 복사도 가능하게 하고 싶은 경우.

즉, 같은 박스이지만 내부에서 드래그와 클릭을 구분해서 실행해야 할 경우 사용하는 방법.

(아무리 생각해도 사용자 친화적 UI는 아닌 거 같지만 하라면 해야지 뭘 어쩌겠는가...)

 

 

 

방법 1. 클릭 시간을 기준으로

  정확하게는 드래그를 구분하는것이 아니라, 클릭 지속시간을 이용하여 판단하는 방법. 

  마우스를 누르고 있는 시간이 길다면 클릭이 아닌 것으로 판단.

<template>
	<div class="workBox" v-for="(work, i) in works" :key="i" 
		@mousedown="dragCheckStart" 
		@mouseup="dragCheckEnd" 
		@click="moveToWork(work)">
		<WorkSummaryTop :project="project" :work="work" @delete="onChange" @edit="onChange" />
		<WorkSummary :project="project" :work="work"/>
	</div>
</tempalte>

<script>
export default defineStoreComponent({
	data(){
		return {
			checkDragTime: false,
			checkTimer: null,
		}
	},
	methods: {
		dragCheckStart() {
			this.checkTimer = setTimeout(() => (this.checkDragTime = true), 100);
		},
		dragCheckEnd() {
			clearTimeout(this.checkTimer);
			setTimeout(() => (this.checkDragTime = false));
		},
		moveToWork(work) {
			if (!this.checkDragTime) {
				클릭일때 실행할 함수
				ex) this.$router.push(`/project/${this.projectNo}/work/${work.no}`)
			}
		},
	}
})
</script>

 

 

 

방법 2. 드래그 거리를 기준으로

  클릭을 시작한 지점으로부터, 클릭을 해제한 지점까지의 거리를 측정하여 클릭과 드래그를 구분.

<template>
	<div class="workBox" v-for="(work, i) in works" :key="i" 
		@mousedown="dragCheckStart($event)" 
		@mouseup="dragCheckEnd($event)" 
		@click=“moveToWork(work)">
		<WorkSummaryTop :project="project" :work="work" @delete="onChange" @edit="onChange" />
		<WorkSummary :project="project" :work="work"/>
	</div>
</template>

<script>
export default defineStoreComponent({
	data(){
		return {
			checkDrag: false,
			positionX: 0,
			positionY: 0
		}
	},
	methods: {
		dragCheckStart(event) {
			this.positionX = event.clientX;
			this.positionY = event.clientY;
		},
		dragCheckEnd() {
			if(Math.abs(this.positionX - event.clientX) > 50 || Math.abs(this.positionY - event.clientY) > 50 ) {
				this.checkDrag = true
			}
			setTimeout(()=>{this.checkDrag = false})
		},
		moveToWork(work) {
			if (!this.checkDrag) {
				클릭일때 실행할 함수
				ex) this.$router.push(`/project/${this.projectNo}/work/${work.no}`)
			}
		},
	}
})
</script>

 

 

 

결론은 둘 다 사용

<template>
	<div class="workBox" v-for="(work, i) in works" :key="i" 
		@mousedown="dragCheckStart($event)" 
		@mouseup="dragCheckEnd($event)" 
		@click=“moveToWork(work)">
		<WorkSummaryTop :project="project" :work="work" @delete="onChange" @edit="onChange" />
		<WorkSummary :project="project" :work="work"/>
	</div>
</template>

<script>
export default defineStoreComponent({
	data(){
		return {
			checkDrag: false,
			positionX: 0,
			positionY: 0,
            
            checkDragTime: false,
            checkTimer: null
		}
	},
	methods: {
		dragCheckStart(event) {
			this.positionX = event.clientX;
			this.positionY = event.clientY;
			this.checkTimer = setTimeout(() => (this.checkDragTime = true), 100);
            // 이미지를 클릭해서 드래그 할경우 DOM 요소를 벗어나기 때문에 mouseup 이벤트가 실행하지 않음.
            // 내부 드래그가 필요 없을경우 e.preventdefault()로도 대체 가능.
			if(event.target.tagName.toLowerCase() == 'img') {
			setTimeout(() => (this.checkDragTime = false),100);
			}
        },
		dragCheckEnd(event) {
			if(Math.abs(this.positionX - event.clientX) > 50 || Math.abs(this.positionY - event.clientY) > 50 ) {
			this.checkDrag = true
			clearTimeout(this.checkTimer);
			}
		setTimeout(()=>{this.checkDrag = false},100)
		setTimeout(() => (this.checkDragTime = false),100);
		},
		moveWorkDetail(work) {
			if (!this.checkDrag && !this.checkDragTime) {
			this.$router.push(`/project/${work.project_no}/work/${work.no}`)
			}
		},
	}
})
</script>

 

 

 

 

반응형