드래그 앤 드롭과 마우스 이벤트 (step 25)
Position:absolute
HTML의 태그를 절대 위치에 배치할 수 있다.
절대 위치는 left, top, bottom, right 프로퍼티 값으로 정하며, 이 값들은 부모 태그 안에서의 상대 좌표이다.
1. 기본적인 공 태그 구현
ball.onmousedown = function(event) {
// (1) absolute 속성과 zIndex 프로퍼티를 수정해 공이 제일 위에서 움직이기 위한 준비를 합니다.
ball.style.position = 'absolute';
ball.style.zIndex = 1000; //필수적이지는 않음
// 현재 위치한 부모에서 body로 직접 이동하여
// body를 기준으로 위치를 지정합니다.
document.body.append(ball);
// 공을 pageX, pageY 좌표 중앙에 위치하게 합니다.
function moveAt(pageX, pageY) {
ball.style.left = pageX - ball.offsetWidth / 2 + 'px';
ball.style.top = pageY - ball.offsetHeight / 2 + 'px';
}
// 포인터 아래로 공을 이동시킵니다.
moveAt(event.pageX, event.pageY);
function onMouseMove(event) {
moveAt(event.pageX, event.pageY);
}
// (2) mousemove로 공을 움직입니다.
document.addEventListener('mousemove', onMouseMove);
// (3) 공을 드롭하고, 불필요한 핸들러를 제거합니다.
ball.onmouseup = function() {
document.removeEventListener('mousemove', onMouseMove);
ball.onmouseup = null;
};
};
ball.style.position = 'absolute';
로 객체인 ball을 자유롭게 이동시킬수 있게 만든다.
ball.style.left = event.pageX
ball.style.top = event.pageY
의 경우 마우스가 위치하는 곳에 해당 그림의 왼쪽 위 부분이 나타난다.
이를 중앙으로 맞추기 위해서는 실제left
와top
을 위치보다 위로 그리고 오른쪽으로 (-하게) 만들어야 중앙으로 온다.
따라서ball.style.left = event.pageX - ball.offsetWidth / 2 + 'px';
ball.style.top = event.pageY - ball.offsetHeight / 2 + 'px';
로 위치를 위로 올려 마우스 위치가 해당 공의 중앙이 되도록 한다.
추가할 부분
브라우저 자체적으로 이미지나 요소에 대한 드래그 앤 드롭을 지원하기 때문입니다. 브라우저에서 제공하는 기능이 자동 실행되어 작성한 코드와 충돌되기 때문
(우리가 실행하려는 mousemove mouseup에 겹쳐서 dragstart가 실행되는것을 막기 위해서 dragstart를return false
처리한다.
ball.ondragstart = function() {
return false;
};
1.1 공을 눌렀을때 바로 마우스의 중앙으로 공이 오는것을 막아보기
$ball.style.left = pageX - $ball.offsetWidth / 2 + 'px';
$ball.style.top = pageY - $ball.offsetHeight / 2 + 'px';
위의 내용을 수정해본다.
Element.getBoundingClientRect()
요소의 크기와 viewport를 기준으로 한 요소의 상대적인 위치 정보를 담은 DOMRect 객체를 반환하는 메서드
이를통해 새로운 코드로 바꾸면
// onMouseDown()
let shiftX = event.clientX - $ball.getBoundingClientRect().left; //마우스를 대상으로
let shiftY = event.clientY - $ball.getBoundingClientRect().top;
그림으로는 이와같다.
따라서 실제 마우스를 클릭하였을때 left,top의 위치가 맨끝점을 기준으로 각각 shiftX shiftY만큼을 빼야하므로
$ball.style.left = event.pageX - shiftX + 'px';
$ball.style.top = event.pageY - shiftY + 'px';
이렇게 수정된다. (기존값보다 shiftX,shiftY만큼 더 뺌으로써 마우스를 기준으로 오른쪽 아래에 그림이 있어야하나 더 위로올라가 마우스가 누르는 위치를 처음 클릭한 위치와 같게 만들어서 클릭시에도 갑자기 공이 움직이는 것을 막아준다.
2. ondrag 사용하는 예시
<!DOCTYPE html>
<html lang="ko">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<style>
div {
width: 180px;
height: 280px;
margin: 10px;
padding: 10px;
border: solid 15px #8B4513;
float: left;
}
</style>
</head>
<body>
<div ondrop="drop(event)" ondragover="dragEnter(event)">
<img id="monalisa" width="180" height="280" src="https://www.ilbe.com/file/download/11181795373" draggable="true" ondragstart="drag(event)">
</div>
<div ondrop="drop(event)" ondragover="dragEnter(event)"></div>
</body>
<script>
function drag(event){
event.dataTransfer.setData("text", event.target.id);
}
//기본동작을 막은 후
function dragEnter(event){
event.preventDefault();
}
// 해당 처리
function drop(event){
var data = event.dataTransfer.getData("text");
event.target.appendChild(document.getElementById(data));
}
</script>
</html>
위의 예시는
ondrag
를 써서 해당 그림을 다른 그림으로 옮기는 작업을 수행하는 역할을 한다.
1.기본적인 공 태그 구현 VS 2. ondrag 사용하는 예시
1번의 경우 공을 드래그시 해당 그림이 유지된 채로 움직임을 진행한다. (보기에 공을 그상태로 움직인다는 느낌이 든다.)
그리고 충돌의 방지를 위해 기본적으로 작동되는 ondrag를event.preventDefault()
를 썼다.
2번의 경우 그림을 드래그시 기존형태가 아닌 작아진 형태로 드래그를 진행하게 된다. 기본적인 ondrag는 써야하기때문에 따로
event.preventDefault()
를 쓰지는 않았다.
과제
실행코드 결과
<!DOCTYPE html>
<html lang="ko">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<style>
div{
position:absolute;
}
#bar {
width: 1000px;
height: 50px;
border-radius: 50px;
background-color: gray;
margin-top :10px;
}
#drag{
width:20px;
height:80px;
border-radius:50px;
background-color: blue
}
</style>
</head>
<body>
<div id='bar'></div>
<div id='drag'></div>
</body>
<script>
let drag = document.getElementById('drag');
drag.onmousedown = function(event) {
// (1) absolute 속성과 zIndex 프로퍼티를 수정해 공이 제일 위에서 움직이기 위한 준비를 합니다.
event.preventDefault();
drag.style.position = 'absolute';
drag.style.zIndex = 1000;
// 현재 위치한 부모에서 body로 직접 이동하여
// body를 기준으로 위치를 지정합니다.
document.body.append(drag);
// 공을 pageX, pageY 좌표 중앙에 위치하게 합니다.
function moveAt(pageX, pageY) {
if(pageX - drag.offsetWidth / 2 > 990 )
drag.style.left = "990px";
else if(pageX - drag.offsetWidth / 2 < 9 )
drag.style.left = "9px"
else
drag.style.left = pageX - drag.offsetWidth / 2 + 'px';
drag.style.top = pageY
}
// 포인터 아래로 공을 이동시킵니다.
moveAt(event.pageX, event.pageY);
function onMouseMove(event) {
moveAt(event.pageX, "6px");
}
// (2) mousemove로 공을 움직입니다.
document.addEventListener('mousemove', onMouseMove);
// (3) 공을 드롭하고, 불필요한 핸들러를 제거합니다.
drag.onmouseup = function() {
document.removeEventListener('mousemove', onMouseMove);
document.removeEventListener('mouseup', onMouseMove);
};
drag.ondragstart = function() {
return false;
};
drag.ondragend = function(){
return false;
}
};
</script>
</html>
해당 바 안에서의 움직임은 문제가 없으나 다른 문제가 발생
문제점
해당 마우스로 바를 클릭한상태로 흰색창부분에서 마우스를 띄면 진행이 계속된다. (바를 멈출수가 없다.)
해결법
<!DOCTYPE html>
<html lang="ko">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<style>
div{
position:absolute;
}
#bar {
width: 1000px;
height: 50px;
border-radius: 50px;
background-color: gray;
margin-top :10px;
}
#drag{
width:20px;
height:80px;
border-radius:50px;
background-color: blue
}
</style>
</head>
<body>
<div id='bar'></div>
<div id='drag'></div>
</body>
<script>
let drag = document.getElementById('drag');
drag.onmousedown = function(event) {
// (1) absolute 속성과 zIndex 프로퍼티를 수정해 공이 제일 위에서 움직이기 위한 준비를 합니다.
event.preventDefault();
drag.style.position = 'absolute';
drag.style.zIndex = 1000;
// 현재 위치한 부모에서 body로 직접 이동하여
// body를 기준으로 위치를 지정합니다.
document.body.append(drag);
// 공을 pageX, pageY 좌표 중앙에 위치하게 합니다.
function moveAt(pageX, pageY) {
if(pageX - drag.offsetWidth / 2 > 990 )
drag.style.left = "990px";
else if(pageX - drag.offsetWidth / 2 < 9 )
drag.style.left = "9px"
else
drag.style.left = pageX - drag.offsetWidth / 2 + 'px';
drag.style.top = pageY
}
// 포인터 아래로 공을 이동시킵니다.
moveAt(event.pageX, event.pageY);
function onMouseMove(event) {
moveAt(event.pageX, "6px");
}
// (2) mousemove로 공을 움직입니다.
document.addEventListener('mousemove', onMouseMove);
document.addEventListener('mouseup', onMouseUp);
// (3) 공을 드롭하고, 불필요한 핸들러를 제거합니다.
function onMouseUp() {
document.removeEventListener('mousemove', onMouseMove);
document.removeEventListener('mouseup', onMouseMove);
};
drag.ondragstart = function() {
return false;
};
drag.ondragend = function(){
return false;
}
};
</script>
</html>
이렇게 하니 정상적으로 문제가 없었다.
두 코드의 차이
- onmouseup사용
document.addEventListener('mousemove', onMouseMove);
// (3) 공을 드롭하고, 불필요한 핸들러를 제거합니다.
drag.onmouseup = function() {
document.removeEventListener('mousemove', onMouseMove);
document.removeEventListener('mouseup', onMouseMove);
};
- addEventListener사용
// (2) mousemove로 공을 움직입니다.
document.addEventListener('mousemove', onMouseMove);
document.addEventListener('mouseup', onMouseUp);
// (3) 공을 드롭하고, 불필요한 핸들러를 제거합니다.
function onMouseUp() {
document.removeEventListener('mousemove', onMouseMove);
document.removeEventListener('mouseup', onMouseMove);
};
느낀점
addEventListener를 많이사용하자??
혹시 한번 실험을 해주실 분들은 저 아래 두 코드를 실험해주시고 의견 남겨주시면 감사하겠습니다.
shiftX,shiftY를 잘 사용할수있게 만들기
// onMouseDown()
let shiftX = event.clientX - $ball.getBoundingClientRect().left; //마우스를 대상으로
let shiftY = event.clientY - $ball.getBoundingClientRect().top;
출처
Author And Source
이 문제에 관하여(드래그 앤 드롭과 마우스 이벤트 (step 25)), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@khw970421/드래그-앤-드롭과-마우스-이벤트-step-25저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)