개발 관련/Vue

[vue.js] 커스텀 scroll을 만들어보자.

Hago하고 2022. 3. 30. 00:02
반응형

프로젝트를 진행하던 중, 우리가 알고 있는 식상한 기본 스크롤이 아닌,

마음대로 스타일링이 가능한 스크롤을 제작하게될 일이 생겼다.

 

스크롤에는 대표적인 라이브러리에는 perfect-scrollbar, vuescroll 정도가 있을 것 같고,

뷰 전용 라이브러리가 아닌 자바스크립트 라이브러리로는 iscroll 도 모멘텀스크롤을 위해 자주 사용하는 것 같았다.

 

여러 라이브러리들을 갖다 붙여봤지만 우리가 사용하는 vue는 vue 3였고...

대부분 뷰 전용 라이브러리들이 vue 2에 모여있는데... 우리는 vue 3를 사용하고 있었기에 마땅한 스크롤바를 찾을만한게 없었다. (제발 vue2 꾸준히 업데이트해줘요...)

 

아무튼 결국 스크롤을 내가 따로 만들게 되었다.

 

거두절미하고 대략적인 모습은 이렇게 생겼다.

 

 

스크롤바를 단순히 다시 만드는 것은 의외로 간단하다 우리가 알아야할 것은 scrollHeight , scrollTop 이다.

let scrollHeight = document.documentElement.scrollHeight;
// 이는 자신이 어떤 엘리멘트를 스크롤 하느냐에 따라 조금씩 달라진다.
// 예를들어 body 스크롤에서 스크롤 height를 알아내려면 위처럼 하는 것이 맞고,
// 특정 div의 스크롤 높이를 알고싶다면 해당 div의 id값을 받아와 알아내는 것이 맞다.

그 다음으로 필요한 부분인 scrollTop. 이는 현재 스크롤이 탑(제일 위)으로부터 얼마나 떨어져있는지를 나타낸다.

let scrollTop = document.documentElement.scrollTop;
//이것도 마찬가지로 특정 div 스크롤의 위치를 알고 싶다면 해당 div를 가져와야한다.
//let element = document.getElementById('div');
//let scrollTop = element.scrollTop;

 이 두개만 안다면 스크롤을 만들 수 있다.

 

우선 나같은 경우에는 해당 기본 스크롤을 input[type=range]로 가져왔다.

 

<input type="range" v-model="scrollPosition" step="0.1" min="0" max="100" :style="{width: `${scrollbarHeight}px`}"/>
/*
    v-model은 scroll의 위치를 나타내는 scrollPosition에 담기로 하였고,
    step은 조금 더 부드럽게 보이기 위해 0.1로 설정을 했다. 1로 설정할 경우 스크롤이 뚝뚝 끊겨보인다.
    최소값과 최대값은 0부터 100까지로 설정했다.
    style에서 width에 scrollHeight를 주었는데, 이는 후에 서술하도록 하겠다.
*/

 

style 설정에서 width에 scrollHeight를 넣은 이유는 우선 기본적으로 input은 가로형으로 나오게 된다.

이걸 세로로 돌려 스크롤로 사용할 수 있도록 바꿔주는 것이다.

css의 아주 편리한 기능중에 -webkit-appearance : slider-vertical; 가 있긴하지만, 이를 적용할 경우에는 아래와 같이 0이 맨 아래로 가게된다.

 

하지만 우리가 생각하는 스크롤은 위에서부터 아래로 내려가는 것이다보니 0이 상단으로 올라가야 한다.

불행히도 0을 상단으로 올려주는 코드같은건 세상에 존재하지 않았다.

vertical도 역방향이 있다면 얼마나 좋았을까.

 

그래서 나는 한가지 꾀를 부렸다.

바로 transform을 이용하여 input 자체를 시계방향으로 90도 돌려버리는 것이었다.

body::-webkit-scrollbar {
  display: none;
  /* 기존 스크롤바를 가리는 방법 */
}



input[type=range] {
   position:absolute;
   -webkit-appearance: none;
   -webkit-transform:rotate(90deg);
   -moz-transform:rotate(90deg);
   -o-transform:rotate(90deg);
   -ms-transform:rotate(90deg);
   transform:rotate(90deg);
   max-width: 90vh;
   height: 5px;
   background: grey;
}

대신 이렇게 하게 되면 불편한 점이. 가로로 놓여져야할 input이 세로로 돌아가게 되면서 우리가 아는 width와 height가 바뀌어버린다는 점이다. 세로로 돌렸을때 우리가 알 던 width는 height값이 되고, height값은 width값이 된다.

 

잘 모르겠다면 직접 테스트해보는 것이 가장 좋다.

-webkit-appearance: none은 기존의 스타일을 모두 없애는 것이기 때문에 input[type=range]의 rail을 투명하게 만든다.

 

아무튼 이렇게 만들어서 오른쪽편에 붙였다면 이제 이 슬라이더와 스크롤을 기능적으로 붙여줄 차례이다.

 


동작하는 단계는 (1) 스크롤 이벤트 발생 -> (2) scrollTop, scrollHeight를 이벤트로 넘김 -> (3)계산 후 스크롤바에 적용 순서이다.

 

스크롤을 감지하여 scrollTop이 변경되면 scrollTop과 현재 scrollHeight를 받게되고, 이 때 계산식은 아래와 같다.

 

this.scrollPosition = (scrollTop * 100) / scrollHeight;

 

우리는 0부터 100까지를 퍼센트라고 생각하고 스크롤을 할 것이기 때문에 위와 같은 식이 적용이 된다.

이렇게하여 scrollPosition과 연결하게 되면

 

 

 

 

위와 같이 직접 드래그를 하거나, 마우스 휠이 이동함에 따라 스크롤의 위치가 바뀌게 사용할 수 있다.

핵심적인 부분은 모두 다뤘으니 css를 조금 더 살펴보자면, 

 

우선 input range의 스타일은 크게 세 가지 부분으로 나뉜다.

input[type=range] {
	/* input range의 전체적인설정. 위치, 길이 등을 결정 */
}

input[type=range]::-webkit-slider-thumb {
	/* 스크롤의 버튼을 나타내는 부분. 색상 및 크기 조절 가능*/
}

input[type=range]::-webkit-slider-runnable-track {
	/* 
    	슬라이더 트랙과 관련된 버튼. 
        슬라이더 트랙의 색을 설정하거나 할 수 있으나
        Input[type=range]와 겹치는 부분이 많아 필자는 쓰지 않음.
	*/
}

 

위 세 가지를 요리조리 섞어서 만들면 이제 위와 같이 직접 제작한 스크롤이 완성된다.

 

 


 

도움이 되셨다면 광고나 공감 부탁드리고 자주는 아니지만 그래도 한 번 쓸 때 열심히, 자세하게 쓸 수 있도록 노력하겠습니다 :D

댓글은 언제나 열려있으니 궁금하신 점은 댓글로 남겨주시면 열심히 공부해서 답변달도록 하겠습니다.

반응형