인프런 커뮤니티 질문&답변

좋은 백조님의 프로필 이미지
좋은 백조

작성한 질문수

애플 웹사이트 인터랙션 클론!

main.js 적용 내용

선생님 질문이 있습니다.

작성

·

127

0

/**
 *ECMA6 SCRIPT STUDY
 */

//const arr=[1,2,3];
//바람직한 패턴이 아닙니다.

(()=>{
	//const arr=[1,2,3]; //지역변수로 선언하고 코딩하는 것을 제안.
	const sceneInfo=[
		{	
			type:'sticky',
			//0
			heightNum:5,	//브라우저 높이의 5배로 scrollheight 세팅.
			scrollHeight:0, //문서길이에 대해서 섹션의 애니메이션 구간을 미리 설정합니다.
							//일단 0이라고 설정한 부부은 기기마다 값이 달라질 수 있기 때문에
							//스크롤 높이의 몇배수 만큼 설정을 해주려고 합니다.
			objs:{
				container: document.querySelector('#scroll-section-0'),
				messageA: document.querySelector('#scroll-section-0 .main-message.a'),
				messageB: document.querySelector('#scroll-section-0 .main-message.b'),
				messageC: document.querySelector('#scroll-section-0 .main-message.c'),
				messageD: document.querySelector('#scroll-section-0 .main-message.d'),
			},
			values:{
				messageA_opacity_in: [0, 1, { start: 0.1, end: 0.2 }],
				messageB_opacity_in: [0, 1, { start: 0.3, end: 0.4 }],
				messageC_opacity_in: [0, 1, { start: 0.5, end: 0.6 }],
				messageD_opacity_in: [0, 1, { start: 0.7, end: 0.8 }],
				messageA_translateY_in: [20, 0, { start: 0.1, end: 0.2 }],
				messageB_translateY_in: [20, 0, { start: 0.3, end: 0.4 }],
				messageC_translateY_in: [20, 0, { start: 0.5, end: 0.6 }],
				messageD_translateY_in: [20, 0, { start: 0.7, end: 0.8 }],
				messageA_opacity_out: [1, 0, { start: 0.25, end: 0.3 }],
				messageB_opacity_out: [1, 0, { start: 0.45, end: 0.5 }],
				messageC_opacity_out: [1, 0, { start: 0.65, end: 0.7 }],
				messageD_opacity_out: [1, 0, { start: 0.85, end: 0.9 }],
				messageA_translateY_out: [0, -20, { start: 0.25, end: 0.3 }],
				messageB_translateY_out: [0, -20, { start: 0.45, end: 0.5 }],
				messageC_translateY_out: [0, -20, { start: 0.65, end: 0.7 }],
				messageD_translateY_out: [0, -20, { start: 0.85, end: 0.9 }]			
			}
		},
		//각구간을 4개로 나눴습니다.
		{	
			//1
			type:'normal',
			heightNum:5,
			scrollHeight:0,
			objs:{
				container: document.querySelector('#scroll-section-1')
			} 
		},
		{	
			type:'sticky',
			//2
			scrollHeight:0,
			objs:{
				container: document.querySelector('#scroll-section-2'),
				messageA: document.querySelector('#scroll-section-2 .a'),
				messageB: document.querySelector('#scroll-section-2 .b'),
				messageC: document.querySelector('#scroll-section-2 .c'),
				pinB: document.querySelector('#scroll-section-2 .b .pin'),
				pinC: document.querySelector('#scroll-section-2 .c .pin')
			},
			values: {
				messageA_translateY_in: [20, 0, { start: 0.15, end: 0.2 }],
				messageB_translateY_in: [30, 0, { start: 0.6, end: 0.65 }],
				messageC_translateY_in: [30, 0, { start: 0.87, end: 0.92 }],
				messageA_opacity_in: [0, 1, { start: 0.25, end: 0.3 }],
				messageB_opacity_in: [0, 1, { start: 0.6, end: 0.65 }],
				messageC_opacity_in: [0, 1, { start: 0.87, end: 0.92 }],
				messageA_translateY_out: [0, -20, { start: 0.4, end: 0.45 }],
				messageB_translateY_out: [0, -20, { start: 0.68, end: 0.73 }],
				messageC_translateY_out: [0, -20, { start: 0.95, end: 1 }],
				messageA_opacity_out: [1, 0, { start: 0.4, end: 0.45 }],
				messageB_opacity_out: [1, 0, { start: 0.68, end: 0.73 }],
				messageC_opacity_out: [1, 0, { start: 0.95, end: 1 }],
				pinB_scaleY: [0.5, 1, { start: 0.6, end: 0.65 }],
				pinC_scaleY: [0.5, 1, { start: 0.87, end: 0.92 }],
			}	
		},	
		
		
		
		
		{
			//3
			type:'sticky',
			scrollHeight:0,
			heightNum:5,
			objs:{
				container: document.querySelector('#scroll-section-3'),
				canvasCaption: document.querySelector('.canvas-caption')
			},
			values:{
				
			}
		}	
	];

	
	let yOffset=0;
	let prevScrollHeight=0;
		//현재 스크롤위치보다 이전에 위치한 스크롤 섹션들의 스크롤 높이값의 합.
	let currentScene=0;
		//활성화된 씬
	let enterNewScene=false; //새로운 scene이 시작되는 순간.
	
	
	
	
	
	function setLayout(){
		for(let i=0; i<sceneInfo.length; i++){
			if (sceneInfo[i].type==='sticky'){
				sceneInfo[i].scrollHeight = sceneInfo[i].heightNum * window.innerHeight;
				sceneInfo[i].objs.container.style.height=`${sceneInfo[i].scrollHeight}px`;
				//기본적으로 문자열을 설정해야하나 ${--- } << ---이부분에 변수이름을 적용 가능
			}else if(sceneInfo[i].type==='normal'){
				sceneInfo[i].scrollHeight = sceneInfo[i].objs.container.style.offsetHeight;
			}
			sceneInfo[i].objs.container.style.height=`${sceneInfo[i].scrollHeight}px`;
		}

		//정확하게 한번더 선언. 재선언 가능의 LET
		yOffset=window.pageYOffset;
		//load이벤트와 연관지어야하는 이유.
		let totalScrollHeight=0;
		for(let i=0; i<sceneInfo.length; i++){
			totalScrollHeight+=sceneInfo[i].scrollHeight;
			if(totalScrollHeight >= yOffset){
				currentScene=i;
				break;
				/*
					*총 전체스크롤 높이가 현재 커서하고있는 페이지 스크롤 위치보다 크면,
					*break를 사용하여 for 문을 탈출합니다.
					*그리고 i값을 currentscene으로 세팅해줍니다.
				 */
			}
		}
		document.body.setAttribute('id',`show-scene-${currentScene}`);
	}
	
	
	
	
	
	
	
	function calcValues(values, currentYOffset){//스크롤 비율 계산
		let rv;
		let scrollRatio=currentYOffset/sceneInfo[currentScene].scrollHeight;
		
		let scrollHeight=sceneInfo[currentScene].scrollHeight;
		//currentYOffset은 playanimation에서 한개의 씬을 넘길때마다 초기화되는 스크롤의 값.
		//scrollheight는 그 씬의 높이.
		//그러므로 비율계산은 씬의 오프셋/씬의 높이
		
		if (values.length===3){
			//start~end 사이에 애니메이션 발생
			
			const partScrollStart=values[2].start*scrollHeight;
			const partScrollEnd=values[2].end*scrollHeight;
			const partScrollHeight=partScrollEnd-partScrollStart;
			
			if (currentYOffset>=partScrollStart && currentYOffset <= partScrollEnd){
				rv=(currentYOffset-partScrollStart)/partScrollHeight*(values[1]-values[0])+values[0];	
			}
			else if (currentYOffset<partScrollStart){
				rv=values[0];
			}
			else if (currentYOffset>partScrollEnd){
				rv=values[1];
			}
		}else{
			rv=scrollRatio*(values[1]-values[0])+values[0];	
		}
		
		return rv;
	}
	
	
	
	function playAnimation(){
		
		const objs=sceneInfo[currentScene].objs;
		const values=sceneInfo[currentScene].values;
		const currentYOffset=yOffset-prevScrollHeight;
		const scrollHeight=sceneInfo[currentScene].scrollHeight;
		const scrollRatio=(yOffset-prevScrollHeight) / scrollHeight;
		switch (currentScene){
			case 0:
				//let messageA_opacity_0=values.messageA_opacity[0];
				//let messageA_opacity_1=values.messageA_opacity[1];
				
				if(scrollRatio<=0.22){
					objs.messageA.style.opacity=calcValues(values.messageA_opacity_in,currentYOffset);
					objs.messageA.style.transform=`translateY(${calcValues(values.messageA_translateY_in,currentYOffset)}%)`;
				}
				else{
					objs.messageA.style.opacity=calcValues(values.messageA_opacity_out,currentYOffset);
					objs.messageA.style.transform=`translateY(${calcValues(values.messageA_translateY_out,currentYOffset)}%)`;
				}
				 if (scrollRatio <= 0.42) {
                // in
	                objs.messageB.style.opacity = calcValues(values.messageB_opacity_in, currentYOffset);
	                objs.messageB.style.transform = `translate3d(0, ${calcValues(values.messageB_translateY_in, currentYOffset)}%, 0)`;
	            } else {
	                // out
	                objs.messageB.style.opacity = calcValues(values.messageB_opacity_out, currentYOffset);
	                objs.messageB.style.transform = `translate3d(0, ${calcValues(values.messageB_translateY_out, currentYOffset)}%, 0)`;
	            }
	
	            if (scrollRatio <= 0.62) {
	                // in
	                objs.messageC.style.opacity = calcValues(values.messageC_opacity_in, currentYOffset);
	                objs.messageC.style.transform = `translate3d(0, ${calcValues(values.messageC_translateY_in, currentYOffset)}%, 0)`;
	            } else {
	                // out
	                objs.messageC.style.opacity = calcValues(values.messageC_opacity_out, currentYOffset);
	                objs.messageC.style.transform = `translate3d(0, ${calcValues(values.messageC_translateY_out, currentYOffset)}%, 0)`;
	            }
	
	            if (scrollRatio <= 0.82) {
	                // in
	                objs.messageD.style.opacity = calcValues(values.messageD_opacity_in, currentYOffset);
	                objs.messageD.style.transform = `translate3d(0, ${calcValues(values.messageD_translateY_in, currentYOffset)}%, 0)`;
	            } else {
	                // out
	                objs.messageD.style.opacity = calcValues(values.messageD_opacity_out, currentYOffset);
	                objs.messageD.style.transform = `translate3d(0, ${calcValues(values.messageD_translateY_out, currentYOffset)}%, 0)`;
	            }
				break;
				
			case 2:
				 // console.log('2 play');
	            if (scrollRatio <= 0.32) {
	                // in
	                objs.messageA.style.opacity = calcValues(values.messageA_opacity_in, currentYOffset);
	                objs.messageA.style.transform = `translate3d(0, ${calcValues(values.messageA_translateY_in, currentYOffset)}%, 0)`;
	            } else {
	                // out
	                objs.messageA.style.opacity = calcValues(values.messageA_opacity_out, currentYOffset);
	                objs.messageA.style.transform = `translate3d(0, ${calcValues(values.messageA_translateY_out, currentYOffset)}%, 0)`;
	            }
	
	            if (scrollRatio <= 0.67) {
	                // in
	                objs.messageB.style.transform = `translate3d(0, ${calcValues(values.messageB_translateY_in, currentYOffset)}%, 0)`;
	                objs.messageB.style.opacity = calcValues(values.messageB_opacity_in, currentYOffset);
	                objs.pinB.style.transform = `scaleY(${calcValues(values.pinB_scaleY, currentYOffset)})`;
	            } else {
	                // out
	                objs.messageB.style.transform = `translate3d(0, ${calcValues(values.messageB_translateY_out, currentYOffset)}%, 0)`;
	                objs.messageB.style.opacity = calcValues(values.messageB_opacity_out, currentYOffset);
	                objs.pinB.style.transform = `scaleY(${calcValues(values.pinB_scaleY, currentYOffset)})`;
	            }
	
	            if (scrollRatio <= 0.93) {
	                // in
	                objs.messageC.style.transform = `translate3d(0, ${calcValues(values.messageC_translateY_in, currentYOffset)}%, 0)`;
	                objs.messageC.style.opacity = calcValues(values.messageC_opacity_in, currentYOffset);
	                objs.pinC.style.transform = `scaleY(${calcValues(values.pinC_scaleY, currentYOffset)})`;
	            } else {
	                // out
	                objs.messageC.style.transform = `translate3d(0, ${calcValues(values.messageC_translateY_out, currentYOffset)}%, 0)`;
	                objs.messageC.style.opacity = calcValues(values.messageC_opacity_out, currentYOffset);
	                objs.pinC.style.transform = `scaleY(${calcValues(values.pinC_scaleY, currentYOffset)})`;
	            }

				break;
				
			case 3:
				break;
		}
	}

	function scrollLoop(){
		prevScrollHeight=0;
		enterNewScene=false;
		for(let i = 0; i<currentScene; i++){
			prevScrollHeight+=sceneInfo[i].scrollHeight;
		}
		if (yOffset>prevScrollHeight+sceneInfo[currentScene].scrollHeight){
			enterNewScene=true;
			currentScene++;
		}
		if (yOffset<prevScrollHeight){
			enterNewScene=true;
			if(currentScene===0) return;//모바일기기의 위로 올릴경우 -가 될 때를 방지
			currentScene--;
		}
		document.body.setAttribute('id',`show-scene-${currentScene}`);
		//"setAttribute 속성은 id 값을 두번재 인자값으로 줄 수 있다. 라는 의미"
		console.log(currentScene);
		if (enterNewScene) return ;
		playAnimation();
	}
	

	window.addEventListener('resize',setLayout);
	window.addEventListener('load',setLayout);
	//각 스크롤 높이를 로드, 리사이즈 될 때 스크롤의 높이를 잡아줍니다.
	window.addEventListener('scroll',()=>{
		yOffset=window.pageYOffset;
		scrollLoop();
		
	});
	setLayout();
})();

지금까지 따라 작성한 내용들인데 body요소의 id가 0 , 1,2,3 이런식으로 바뀌어야하는데 0, 1 까지만 바뀌고 2-3으로는 바뀌지가 않아서 2씬에서 핀위의 글씨가 보이지 않습니다  어딘지 잘모르겠습니다...

답변 1

0

1분코딩님의 프로필 이미지
1분코딩
지식공유자

두가지를 고치셔야 하는데요,

1. sceneInfo의 2번(3번째 씬)에 heightNum: 5 설정이 빠져있어서 #scroll-section-2의 높이가 제대로 설정되지 않고 있습니다.

2. setLayout 함수에서 'normal' 섹션의 높이 설정하는 부분에 속성값이 잘못 들어가 있습니다. offsetHeight는 style 객체의 속성이 아니라 DOM 객체의 속성이기 때문에 container.style.offsetHeight가 아닌 container.offsetHeight로 써주셔야 합니다.

sceneInfo[i].scrollHeight = sceneInfo[i].objs.container.style.offsetHeight;

이 부분을

sceneInfo[i].scrollHeight = sceneInfo[i].objs.container.offsetHeight;

이렇게 고쳐주세요^^

좋은 백조님의 프로필 이미지
좋은 백조

작성한 질문수

질문하기