반응형
클릭이 가능한 카드형 박스지만, 내부 내용을 드래그해서 복사도 가능하게 하고 싶은 경우.
즉, 같은 박스이지만 내부에서 드래그와 클릭을 구분해서 실행해야 할 경우 사용하는 방법.
(아무리 생각해도 사용자 친화적 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>
반응형