codestates / codestates/art-ground

[Error Handling Log] overflow 되는 부분을 마우스 드래그로 좌우 스크롤하기 / 박지영

Open
#311 0 comments 0 reactions 1 assignee Claimed by @devLuenna View on GitHub
Error Handling Log
Dominant language
JavaScript
Stars
7
Forks
9
PR merge metrics
No merged PRs in 30d

Description

- 스크롤 이벤트가 일어나는 태그의 속성:

```css
.categories {
display: flex;
align-items: center;
margin: 1rem 0 1.2rem 0;
padding: 0 0.5rem;
width: 100%;
overflow-x: scroll;
}
```

- `overflow-x: scroll;` 일 때 돔의 속성값(scrollWidth, clientWidth, scrollLeft)이 나타내는 것을 이해하기 쉽게 패드로 그려보았다
![image](https://user-images.githubusercontent.com/83934037/135721011-ce558e5a-04ad-4115-90ce-1a6a8562bb2d.png)

1. `DOM.scrollWidth`스크롤 할 수 있는 총 길이
2. `DOM.clientWidth`설정한 max width ( 화면에 보이는 스크롤의 길이 )
3. `DOM.scrollLeft`스크롤 가장 왼쪽 (`DOM.scrollLeft = 0` ) 부터 이동한 스크롤 길이. 즉 `DOM.scrollLeft` 길이만큼 스크롤 이동
4. `mouseEvent.pageXonMouseDown`시 x 좌표.

- 마우스가 클릭되고 드래그를 시작하면 `isDrag` 상태값을 true로 전환
- 좌우 슬라이드 스크롤의 움직임은 해당 DOM의 scrollLeft로 움직인다. 해당 DOM의 scrollLeft를 얻기 위해 useRef를 사용하여 DOM에 접근. (마우스가 드래그 되는 동안 돔의 `scrollLeft` 속성값을 조절하여 화면에 드래그가 적용되어 보여지게 함)

```jsx
const scrollRef = useRef(null);
const [isDrag, setIsDrag] = useState(false);
const [startX, setStartX] = useState(0);

const onDragStart = (e) => {
e.preventDefault();
setIsDrag(true);
setStartX(e.pageX + scrollRef.current.scrollLeft);
};

const onDragEnd = () => {
setIsDrag(false);
};

const onDragMove = (e) => {
if (isDrag) {
scrollRef.current.scrollLeft = startX - e.pageX;
//scrollLeft 값을 바꿔주어 돔에 컴포넌트를 실시간으로 보여줌

}
};

///////////////////////////////////////////////////////////

return(


//...


{tags.map(el =>
handleTagFilter(el)}>{el})}


//...


)
```

- 추가로 발생한 문제들
- startX 위치 재조정: 마우스를 움직였을 때 더 이상 스크롤을 할 수 없는 상태에서, 반대쪽으로 스크롤을 움직이고 싶을 때, 처음 마우스를 **클릭한 지점을 지나쳐야** 스크롤이 움직인다. (`startX`의 `scrollLeft` 값이 변하지 않기 때문에)이를 해결하기 위해 `DOM`의 속성들을 이용해 해결했다.
- 가장 왼쪽일 때, 움직이고 있는 마우스의 `x`좌표가 곧 `startX`로 설정.
- 가장 오른쪽일 때, 움직이고 있는 마우스의 `x`좌표에 현재 스크롤된 길이 `scrollLeft`의 합으로 설정

```jsx
const onDragMove = (e) => {
if (isDrag) {
scrollRef.current.scrollLeft = startX - e.pageX;
//scrollLeft 값을 바꿔주어 돔에 컴포넌트를 실시간으로 보여줌

let { scrollWidth, clientWidth, scrollLeft } = scrollRef.current;

if (scrollLeft === 0) { //왼끝이 보이는데 계속 오른쪽으로 드래그할 때
//console.log('1', e.pageX)//계속 증가
setStartX(e.pageX);
} else if (scrollWidth <= clientWidth + scrollLeft) { //오른쪽끝이 보이는데 계속 왼쪽으로 드래그할 때
//console.log('2', e.pageX + scrollLeft)//계속 감소
setStartX(e.pageX + scrollLeft);
}

}
};
```


- 너무 많은 이벤트 발생: `onScroll` 이벤트와 같이 `onMouseMove`도 수많은 이벤트가 발생. `Debounce` 대신 이벤트를 delay 시켜 끊어주는 `Throttle`을 사용하여 해결. delay를 일반적인 250ms를 설정하면 너무 불편해 100ms로 설정.

```jsx
const throttle = (func, ms) => {//너무 많은 이벤트가 발생하니 250ms마다 이벤트 감지.
let throttled = false;
return (...args) => {
if (!throttled) {
throttled = true;
setTimeout(() => {
func(...args);
throttled = false;
}, ms);
}
};
};
const delay = 100;
const onThrottleDragMove = throttle(onDragMove, delay);
```


- 평상 시 이벤트 제거하기: `onMouseMove` 이벤트는 클릭 여부와 상관없이 해당 DOM에 위치하면 발생한다.이를 막기 위해 `isDrag`가 `false` 일 때 작동하지 않도록 설정.

```jsx


{tags.map(el =>
handleTagFilter(el)}>{el})}

```

### **에러 핸들링을 위해 참고한 레퍼런스 링크**
https://velog.io/@tunakim/마우스-드래그로-좌우-스크롤-구현-ft.-React

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.