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

자바스크립트


[실전] 슬라이드쇼 만들기 (2)

이번에는 요즘 유행하는 슬라이드쇼를 만들어 볼거야.
웹 초기에는 지난 번에 만든 슬라이드쇼를 내 홈피의 대문에 보여 주어도 "와~" 했는데, 사람들 눈이 점점 높아져서 새로운 효과가 나타나기 시작했어.
그리고 display=none/block 을 이용한 쇼는 아무래도 약간씩은 끊어지는 느낌이 있었거든.

그래서 그림 하나를 보여주고는 옆으로 스스륵 밀리는 효과가 새로 유행하기 시작했어.
커로셀(carousel) 효과라고 부르는데 carousel은 '회전목마' 라는 뜻이야.
놀이공원에 가면 꼭 있는 회전목마 있지?
회전목마를 타면 계속 빙글빙글 돌잖아. 한 바퀴 돌면 다시 제자리로 오고...
바로 그런 장면과 비슷하다고 해서 이런 방식의 효과를 carousel 이라고 불러.

커로셀(carousel)효과를 구현하는 방법도 참 여러가지가 있는데, 검색하면서 그나마 제일 쉬워 보이는 코드를 선택했어.
우선 이 방식의 구현 로직은 다음과 같아.
  1. ul의 넓이는 그림1장*그림갯수로 정한다. (ul.style.width = 3000px)
  2. float:left로 정렬하면 그림3장은 가로로 나란히 붙게 된다. → [그림1 그림2 그림3]
  3. transition 시간(2초)에 transform 방향으로 그림 1장 크기 만큼 이동한다.
  4. transition 시간이 지나면 setTimeout 으로 아래 작동이 실행된다
  5. 첫째 그림을 마지막에 복사한다. → [그림1 그림2 그림3 그림1] 이 된다
  6. 첫째 그림을 삭제 한다. → [ null 그림2 그림3 그림1] 이 된다
  7. 다음 이동을 위해 좌측 위치값 0 으로 초기화 → [그림2 그림3 그림1]
  8. 함수가 시작되고 4초가 지나면 다시 carousel 이 실행되고 1번 부터 실행된다.
주요 소스를 볼까?


....
<style>
	.banner {margin:0 auto; padding:0; overflow:hidden;}
	.banner ul {position:relative; margin:0px; padding:0; list-style:none; }
	.banner ul li {float:left} 
</style>
....
<div class="banner" style="width:1000px; height:350px">
	<ul>
		<li><img src="roll1.jpg" style="width:1000px"></li>
		<li><img src="roll2.jpg" style="width:1000px"></li>
		<li><img src="roll3.jpg" style="width:1000px"></li>
	</ul>
</div>
....
<script>
	setInterval(function() { carousel(); }, 4000); // 4초 마다 그림이동
	
	function carousel() {
		let ul = document.querySelector('.banner ul');
		ul.style.width = "3000px"; // 전체 배너창 크기 (1개그림넓이*그림갯수)
		ul.style.transition = "transform 2000ms ease-in-out"; // 2초(2000ms)에 걸쳐 천천-보통-천천 이동한다
		ul.style.transform = "translateX(-1000px)"

		setTimeout(function() { //- 위 이동속도 2초(2000ms)가 지나면 그림 순서를 변경
			ul.style.transition = "none"; // 초기화
			ul.style.transform = "none";
			//첫번째 이미지를 마지막에 복사(이동이 아니라 복사)해서 추가
			ul.innerHTML += ("<li>" + ul.querySelectorAll("li")[0].innerHTML + "</li>"); 
			//뒤로 복사된 첫번째 이미지는 필요 없으니 삭제
			ul.querySelectorAll("li")[0].remove();
			//다음 움직임을 위해서 배너 좌측의 위치값을 초기화
			ul.style.left = "0px";
		}, 2000);
	};
</script>
​

transform 이라는 새로운 css 속성이 나타났네?
이것은 변화하는 요소의 크기, 위치, 기울기, 회전등을 조절하는 속성이야.
지난 번에 배운 transition 과 함께 애니메이션 효과를 줄 때 많이 사용하는 속성이야.
우리 코드에서는 transform = "translateX(-1000px) 로 사용했는데, 뜻은..
"X축 방향으로 -1000px을 이동해라" 라는 뜻이야.
마이너스 기호면 왼쪽으로 이동하고 마이너스가 없으면 오른쪽 이동을 뜻해.
이 속성 역시 구글에서 검색하면 무수하게 많은 설명과 예제를 쉽게 찾을 수 있으니 여기서 설명은 생략할께.

나머지 라인들의 코드들은 모두 소스에 주석으로 설명해 두었으니 그것을 참조해 보도록 해.
요약하면 맨 앞에 있던 그림을 맨 뒤로 옮기고 차례차례 그림 1개 만큼씩 왼쪽으로 이동시키는 방식이야.
그러면 그림들이 계속 회전목마 처럼 순차적으로 무한으로 도는 것 처럼 작동하게 되는 거지.

위 소소를 적용한 데모 페이지는 아래 링크에서 확인해 볼 수 있어.
http://yogibbs.kr/jsDemo/carousel1-vanilla.html

어때? 예전 show,hide 방식을 이용한 것 보다 훨씬 더 세련되게 그림들이 바뀌는 것 같지?

■ 어디서나 쓸 수 있는 함수로 만들기
위에서 배운 커로셀(carousel) 함수는 잘 작동하지만 몇가지 제한사항이 있어.
첫째 그림의 가로(width)를 1000px 로 고정했고, 또 세로(height)는 350px 로 고정한 div 안에서 작동하도록 되어 있어.
그런데 홈페이지의 대분에 적용할 때는 가로폭이 일정하지 않아.
메일페이지 브라우저의 가로에 꽉 차게 보이고 싶은데, 사용자 마다 브라우저를 다르게 보잖아. 또 pc에서 보는 사람도 있고, 태블릿, 모바일도 다 가로 크기가 달라.
또 세로도 문제야. 세로 크기를 고정시키면서 가로만 늘리고, 줄이면 그림이 옆으로 찌그러 지거나 퍼져 보이게 돼.

이렇게 화면의 크기가 달라도 항상 꽉차게 보이게 하려면 어떻게 할까?
또 그림 원래의 가로.세로 비율에 따라 세로도 늘어나거나 줄어들게 하고 싶다면?
바로 자바스크립트로 가로폭을 계산하도록 하면 되지 않을까?
그리고 기왕 함수로 만드는 김에 이동시킬 div 요소와 그림 슬라이딩 시간도 인자로 주어서 어디서나 함수명만 호출해서 사용할 수 있으면 더 좋을것 같아.
그럼 한 페이지 안에서 여러개의 회전목마를 표현할 수도 있잖아.
해 보자구. 여기 소스가 있어.

....
<style>
	.banner {margin:0 auto; padding:0; overflow:hidden;}
	.banner ul {position:relative; margin:0px; padding:0; list-style:none; width:10000px}
	.banner ul li {float:left;} 
</style>
....
<div class="banner">
	<ul>
		<li><img src="roll1.jpg"></li>
		<li><img src="roll2.jpg"></li>
		<li><img src="roll3.jpg"></li>
	</ul>
</div>
....
<script>
carousel('.banner');
let mySlide = setInterval(function() { carousel('.banner',2000); }, 4000);// 다음 이미지로 롤링 할 시간차

function carousel(target, rollTime) {
	var banner = document.querySelector(target);
	var ul = document.querySelector(target +' ul');
	var img	= document.querySelectorAll(target +' img');
	var imgWidth  = banner.offsetWidth; // 그림 1개 넓이 (div 가로에 꽉차게)
	ul.style.width = imgWidth * img.length + "px"; // 전체 배너창 크기 (그림넓이*그림갯수)
	for ( var i = 0; i < img.length; i++ ) {img[i].style.width = imgWidth + "px";} // 모든 그림의 width 값 동일하게
	if (!rollTime) {return;} // rollTime 이 없으면 첫째 그림만 보여주고 나간다
	ul.style.transition = "transform " + rollTime + "ms ease-in-out"; // rollTime 초(ms)에 걸쳐 천천-보통-천천 이동한다
	ul.style.transform = "translateX(" + (-imgWidth) + "px)"

	setTimeout(function() { //- 위 이동속도가 rollTime 초(ms)가 지나면 그림 순서를 변경
		ul.style.transition = "none"; // 초기화
		ul.style.transform = "none";
		ul.innerHTML += ("<li>" + ul.querySelectorAll("li")[0].innerHTML + "</li>"); //첫번째 이미지를 마지막에 복사
		ul.querySelectorAll("li")[0].remove();//뒤로 복사된 첫번째 이미지는 필요 없으니 삭제
		ul.style.left = "0px"; //다음 움직임을 위해서 배너 좌측의 위치값을 초기화
	}, rollTime);
};
</script>
​

함수에 슬라이드쇼를 보여줄 div 요소와 이동시간을 파라미터(parameter)로 준 것 외에 이전 소스와 크게 다르지는 않아.
눈여겨 봐야 할 부분들 만 설명할께.

첫째, 우선 style 선언문의 .ul 에 width:10000px 로 정했어.
이 길이는 브라우저 창 가로크기 * 그림갯수가 충분히 들어갈 만한 크기로 대충 지정해 둔거야.
웹페이지가 로딩되고 자바스크립이 작동하기 전에 그림들이 여러장일 경우 세로 크기를 정하지 않으면 float:left 로 가로로 붙여도 다음 그림이 아래로 밀려나 순간적으로 여러 장이 다 보이는 것과 스크롤바가 생겨서 가로 크기 계산이 틀리는 것을 막기 위해서야.
ul 의 크기를 아루리 크게 해도 이것을 감싸는 div 의 속성이 overflow:hidde 이기 때문에 가로로 넘치는 부분이 보이지 않아.

둘째, 함수 안에서 그림 1장의 크기는 지정한 요소(target)의 크기로 했어.(var imgWidth=banner.offsetWidth)
그림에 높이를 지정하지 않으면 가로 크기만 정하면 세로는 자동으로 비율에 따라 정해져.
그리고 ul의 크기도 그림1장*그림갯수로 다시 정확하게 설정했어.
위 style에서 정한 ul 의 크기가 충분히 크면 다시 계산할 필요는 없겠지만 혹시라도 부족하면 여기서 다시 계산해 정확한 크기가 될거야.

세째, if (!rollTime) {return;}// rollTime 이 없으면 첫째 그림만 보여주고 나간다
이것은 이 함수를 처음 시작할 때 첫번째 그림을 보여주기 위한 코드야.
지금 script 코드의 첫 두 줄은 다음과 같아.

carousel('.banner');
let mySlide = setInterval(function() { carousel('.banner',2000); }, 4000);
​

알다시피 setInterval() 은 몇 초 간격으로 함수를 실행할 때 사용하잖아.
그러니 첫 줄이 없으면 첫 4초 동안은 carousel()함수가 실행이 안돼.
그림은 보여 주겠지만 그림의 width를 계산하는 것은 carousel()에서 하기 때문에 div에 딱 맞지 않는 그림을 보여 주면서 4초 후에야 계산을 해서 다음 그림을 보여 줄거야.
그래서 setInterval() 전에 이 함수를 실행해서 첫번째 그림을 요소 안에 딱 맞는 크기로 보여주는 역할만 하도록 했어.
그리고 두 번째 줄에 setInterval() 로 차례로 그림을 보여 주면 자연스럽게 전체 그림들이 이동하게 돼.
이해가 돼?
여러분의 소스에서 첫 줄을 주석 처리하고 실행해 보면 확실하게 이해할 수 있을거야.
(사실 나도 첫 번째 그림을 어떻게 해결하나 고민고민하다 생각한 방법이야. 더 좋은 방법은 여러분들이 만들어 봐..)

아~ 눈치있는 학생이면 두 번째 setInterval()을 왜 변수에 대입했을까? 궁금할거야.
그냥 이전 처럼 setInterval(function() {carousel('.banner',2000); }, 4000); 로 해도 돼.
그런데 이렇게 변수(객체)에 대입해 두면 이 변수명 만으로 추가 작업을 할 수도 있거든..
예를들어 그림에 마우스를 올리면 슬라이딩이 멈춘다던지...(이것이 필요하면 아래 참고 링크들의 소스를 보면 돼)

자, 어쨌든 이렇게 해서 함수로 정리를 끝낸 회전목마의 데모 사이트는 아래와 같아.
확인해 보고 브라우저 창을 가로로 늘렸다 줄였다 하면서 어떻게 변하는지 살펴 봐. 그리고 Ctrl-U 로 소스도 꼭 확인해 보고...
http://yogibbs.kr/jsDemo/carousel-function.html

■ 그밖의 방법들
지금까지 회전목마 슬라이드쇼를 학습해 보았어.
재미있었지?

그런데 아직도 부족한게 많아.
다른 멋진 홈페이지를 보면 슬라이드쇼 좌우에 좌로, 우로 버튼도 있고 또 하단에 페이지까지 표시되기도 하는 것도 많아.
처음에는 그런 멋진 슬라이드를 모델로 강좌를 하려고 했는데 내가 봐도 너무 어려워.
기능이 많아 질수록 코드는 어쩔 수 없이 복잡해 지거든...
그래서 코드를 최대한 줄이고 핵심만 설명하도록 하다 보니 이렇게 뭔가 좀 빠진 결과가 되었네?..ㅎ

좌우 이동 버튼이라던지, 또 슬라이드쇼 화면 아래에 페이지까지 넣는 기능을 직접 만들고 싶다면 아래 내가 검토했던 블로그들을 참조해 보도록 해.
이제 여러분의 실력이면 아래 내용들도 충분히 이해할 수 있을거야.
아래 각각의 링크를 클릭해서 구현된 페이지를 확인해 보고, Ctrl-U 로 소스를 직접 확인해 보도록 해.

http://yogibbs.kr/jsDemo/carousel4-vanilla.html

http://yogibbs.kr/jsDemo/carousel2-vanilla.html

http://yogibbs.kr/jsDemo/carousel3-vanilla.html

위 데모 페이지들 분석해 보고 "너무 어려워~ 난 개발자 체질이 아닌가 벼.." 하고 고뇌하는 학생이 있다면 아직 좌절하지 마~
다른 방법이 또 있어..
다음 강의로 가 봐..
목차제 목조회
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 63
16 43
17 45
18 49
19 46
20 55
21 61
22 55
23 102