요기보드3   필수기초 선택과목 요기보드 그누보드 로그인

자바스크립트


[실전] slideUp , slideDown , slideToggle

이번에는 이전 학습인 [슬라이딩 효과]에서 완성하지 못한 슬라이딩을 마쳐 볼거야.

css 의 transition 과 height 를 이용한 슬라이딩이 완벽하지 않은 이유는 div 의 높이 초기값이 css에서 height:0px 로 이기 때문에 이것을 보여 줄 때의 높이를 미리 알 수 없기 때문이었어.
반면 display 와 몇가지 다른 속성을 보여졌을 때의 높이를 알 수가 있어.
그럼 이 두가지 속성을 잘 짬뽕하면 되지 않을까?
예를들어 다음과 같이 하는 거야.

■ slideDown()
우선 토글할 div 는 초기에는 display:none 로 감춰 두고, slideDown 함수가 실행하면 아래와 같이 작동하도록 하는거야.
  1. 감춰진 div 요소의 display를 block 으로 보이게 한다
  2. 해당 div 요소의 높이(height)를 알아내 변수에 저장한다.
  3. height 를 0px로 바꾼다. -> 다시 감춰지겠지?
  4. transition 속성으로 변화할 시간을 지정한다
  5. 변수에 저장했던 height 값으로 다시 높이를 바꾼다.
이렇게 하면 div의 높이가 있으므로 크기가 가변적인 div도 자연스럽게 정확한 위치까지 스스륵 보이게 되겠지?


function slideDown() {
	let el = document.querySelector("subMenu");
    let savPosition = el.style.position; 	// (1)현재 position 기억
	let savVisibility = el.style.visibility;// (2)현재 visibility 기억
	el.style.position   = 'absolute';
    el.style.visibility = 'hidden';
    el.style.display = 'block';
    let height= el.offsetHeight;	// height 값 계산 
	el.style.position   = savPosition;	// (1)에서 기억한 원래 position 으로 되돌리기
    el.style.visibility = savVisibility;// (2)에서 기억한 원래 visibility 으로 되돌리기
    el.style.overflow = 'hidden';
    el.style.height = 0;
    el.offsetHeight;
	el.style.transition = "height 1000ms";
	el.style.height = height + 'px';
}
​
대략 위 순서 요약에서 설명한 순서대로 처리되었는데 display 속성 외에 몇 개가 더 있네?
position 과 visibility 가 그것이야.
현재 상태의 position 과 visibility 상태값을 임시변수에 기억하고, position=absolute 와 visibility=hidden 으로 변경한 뒤에 display 를 block 로 바꾸고 let height=el.offsetHeight 로 요소의 높이를 계산했어.
그리고 높이를 계산한 뒤에는 position, visibility 값을 임시변수에 저장된 값으로 원래대로 되돌려 놓았어.

왜 이렇게 복잡하게 높이를 구했을까?
한 번 위 소스를 복사한 여러분의 소스에서 position 과 visibility 들이 있는 라인들을 지우고 직접 테스트해 봐.
어떤 때는 제대로 되고, 또 어떤 상황에서는 제대로 높이를 계산하지 못해.
이렇게 한 이유는 현재 요소의 상태에 따라 display 속성 만 block 으로 바꿔서는 정확한 높이를 찾지 못하는 경우가 있기 때문이야.

나도 "어? 왜 그럴까?" 싶어서 한참을 헤메다 찾았어.
그런데 그때 이유를 찾았던 웹페이지를 다시 찾지 못해서 지금 이유를 설명못해..ㅎ
그렇지만 당시 읽었던 웹페이지에서는 visibility 도 영향을 끼친다고 해서 그 라인들도 포함해 두었어.
어쨌든 위와 같은 소스를 통해 별도 css 지정 없이도 자바스크립트 만으로 transition 효과를 구현해 냈어.

■ slideUp()
이번에는 펼쳐진 요소를 스스륵 닫는 방법이야.
slideDown()과 반대로 하면 될 것 같지만 조금 달라.
왜냐하면 여기서는 이미 다 보이는 상태이기 때문에 높이를 따로 계산할 필요가 없어.
소스를 먼저 확인해 보자구.


function slideUp() {
	let el = document.querySelector("subMenu");
	el.style.transition = "height 1000ms";
	el.style.height = el.offsetHeight + 'px';
	el.offsetHeight; // 높이 초기화
	el.style.overflow = 'hidden';
	el.style.height = 0;
	setTimeout( () => {
		el.style.removeProperty('height');
		el.style.display = 'none';
	}, 1000);
}
​
현재 보이는 선택한 div 높이(el.offsetHeight)에서 0 으로 바꾸는데 transition 속성을 height 1000ms 로 지정했으니 1초동안 스스를 닫히게 되겠지?
그리고 setTimeout()을 이용해서 1초가 지나면 display를 none로 바꿔서 완전히 보이지 않도록 했어.
사실 1초 후에는 height가 0px 이 되니 보이지 않겠지만 이렇게 확실하게 display:none 로 해두지 않으면 다음에 다시 보이기를 하거나 토글로 사용할 때 문제가 될 수도 있어.
그래서 확실하게 감춰 버리는 코드를 추가했어.

■ slideToggle()
토글은 이전에 학습했던 토글과 거의 동일해.
현재 요소가 감춰진 상태면 slideDown() 함수를 호출하고, 반대로 보이는 상태이면 slideUp()을 호출해서 감추는 함수야.


function slideToggle() {
	let el = document.querySelector("subMenu");
	if (window.getComputedStyle(el).display == 'none') {
	   slideDown();
	} else {
	   slideUp();
	}
}
​
약간 특이한 점은 현재 상태 요소의 상태를 알기 위한 if 절에서 el.style.display 대신 window.getComputedStyle(el).display 라는 속성을 사용했는데 왜 굳이 생소한 속성을 사용했는지 나도 모르겠어.
그냥 구글에서 검색한 많은 소스에 이걸 사용하길래 나도 그냥 베꼇어.
아마 지금까지의 학습처럼 if (el.style.display == 'none') 로 해도 문제 없을거야.

토글까지 구현한 소스는 아래 링크에서 직접 확인해 볼 수 있어.
http://yogibbs.kr/jsDemo/slideUpDown.html

■ 조금 더 생각해 보기
지금까지 자바스크립트로 슬라이딩 효과를 구현하는 방법을 공부해 보았어.
그런데 지금까지 설명은 모두 <div id="subMenu">~</div> 인 요소에 대해서만 작동하도록 되어 있어.
또 슬라이딩 시간도 모두 1초(1000ms)로 작동해.
그러므로 위 소스를 여러분의 홈페이지에 그대로 적용하려면 슬라이딩을 할 요소에 항상 id="subMenu"를 적용시켜야 만 작동할거야.
여기저기 다른 요소에도 작동하도록 할 수 없을까?
또 슬라이딩 시간도 내가 직접 정하게 할 수 없을까?

당연히 되지.
그래서 함수를 사용하는 거잖아.
원래 함수를 사용하는 큰 목적 중 하나가 한 번 만들어 둔 소스를 여러 곳에서 쓸 수 있게 하는 것이야.
그리고 함수를 호출할 때에 다른 값을 전달하는 것이 바로 인자(argument)야.
앞서 함수 설명에서도 잠깐 배웠지?

그럼 이번에 배운 slideDown(), slideUp(), slideToggle() 함수에도 웹페이지의 (1)어떤 요소를 감출 것인가와 (2)슬라이딩 시간을 인자(argument) 주면 될거야.
예를들어 slideDown() 함수는 아래와 같이 변경해 주면 돼.


function slideDown(target, time=500) {
	let el = document.querySelector(target);
	....
	el.style.transition = "height " + time + "ms";
	....
}
​
위 코드에서 target 은 파라미터(parameter)라고 불러.
응? 인자(argument) 라며?
주는 쪽에서는 인자(argunet)라고 부르고, 받은 쪽에서는 파라미터(parameter)라고 불러.
줄 때는 '값'으로 주고, 받는 쪽에서는 이것을 '변수'로 받아서 이름이 좀 다르지만 사실 같은 거 라고 생각해도 큰 문제는 없어.
그래서 받는 쪽에서는 일반 변수와 구분하기 위해 '매개변수'라고 부르기도 하는데 그게 영어로 파라미터야.

우리의 예제에서는 위와 같이 함수를 변경하면 함수를 호출할 때는 슬라이딩할 요소를 '#subMenu' 같이 값(인자)으로 주면서 함수를 호출하면 함수는 이 값을 target 라는 파라미터에 담겨 함수 내에서 변수처럼 사용할 수 있어.
두번째 인자인 time 은 슬라이딩 시간이야.
그런데 위 예제에서는 time=500 로 쓴 이유는 만일 사용자가 함수를 호출하면서 두번째 인자인 time 값(인자)를 주지 않으면 500 (0.5초)을 기본값으로 사용하겠다는 뜻이야.
만일 사용자가 slideDown('#subMenu', 1000) 으로 함수를 호출했다면 슬라이딩 시간이 인수로 보냈으니 함수에서는 time 값이 1000 이 되고 내부에서 time 파라미터 매개변수의 값은 1000이 될테니 transition 의 속성은 "height 1000ms" 가 되겠지?

slideDown(), slideToggle() 도 마찬가지야.
자 이제 내 홈페이지에서 다른 클래서 요소(예: myDiv)를 슬라이딩 2초에 걸쳐 슬라이딩 토글 시키고 싶으면 버튼에 아래와 같은 코드를 적어 주면 되겠지?


	...
	<button onclick="slideToggle('.myDiv',2000)">토글</button>
	...
​

아래 데모 페이지에서 테스트를 해보고 Ctrl-U 로 소스를 보면 이미 파라미터를 사용한 함수로 만든 것임을 알 수 있어.

http://yogibbs.kr/jsDemo/slideUpDown.html
(꼭 다시 들어 가서 Ctrl-U 로 전체 소스를 직접 확인해 보도록 해.)

자바스크립트를 이용한 슬라이딩 효과에 대해서는 여기까지야.
나중에 [내 라이브러리 만들기]편에서 다시 간단히 설명할거야.

다음은 내가 이 슬라이딩 효과를 공부하면서 검색한 웹페이지 중에서 나름 도움을 받았던 곳들을 소개해 볼께.

css transition 작동 이해하기

바닐라js로 슬라이드 다운 업 구현하기

codepen 에서 슬라이딩 소스

목차제 목조회
1 119
2 120
3 124
4 106
5 101
6 116
7 102
8 115
9 99
10 99
11 107
12 98
13 93
14 111
15 64
16 44
17 46
18 49
19 47
20 55
21 62
22 55
23 102