[JS] Level3 15-19강

ByeolGyu·2024년 6월 25일

JavaScript

목록 보기
10/17

✔ position : sticky (15강)

  • Edge 이상에서 사용가능
  • 스크롤이 되었을 때 화면에 고정되는 요소를 만들고 싶을 때 사용할 수 있는 CSS 속성
  • position : fixed 와의 차이
    : position : sticky 는 스크롤이 되어서 이 요소가 화면에 나오면 고정시킨다는 특성

사용 시 주의점

  1. 스크롤을 할 만한 부모 박스가 있어야하고
  2. top 등 좌표속성과 함께 써야 제대로 보임

사용 예시

getBoundingClientRect()

: HTML 요소의 크기와 화면에 상대적인 위치를 반환하는 메서드

  • 요소의 경계 상자에 대한 정보를 포함하는 DOMRect 객체를 반환
  • 뷰포트를 기준으로 한 좌표 반환, 스크롤 위치와 관계없이 요소의 위치 측정
  • 요소가 화면에 렌더링되지 않은 경우(예: display: none인 경우) getBoundingClientRect()는 모두 0인 값을 반환

경계 확인

if (firstRect.bottom < 0 && secondRect.top <= windowHeight) {}

  • firstRect.bottom
    : firstText 요소의 하단 경계가 화면의 상단 경계로부터 얼마나 떨어져 있는지 나타냄
  • firstRect.bottom < 0
    : firstText의 하단이 뷰포트의 상단을 지나갔는지 확인
  • secondRect.top
    : secondText 요소의 상단 경계가 화면의 상단 경계로부터 얼마나 떨어져 있는지를 나타냄
  • windowHeight
    : 브라우저 창의 높이(뷰포트의 높이)
  • secondRect.top <= windowHeight
    : secondText의 상단이 뷰포트의 하단보다 위에 있는지 확인

clear

  • 요소가 플로트된 요소들의 영향을 받지 않도록 하여, 플로트 요소들 아래에 위치하도록함
  • 레이아웃을 정리하고 깨진 레이아웃을 방지하는 데 유용

clear 속성의 값

none : 기본값으로, 플로트된 요소의 영향을 받지 않음
left : 요소가 왼쪽으로 플로트된 요소의 오른쪽에 위치
right: 요소가 오른쪽으로 플로트된 요소의 왼쪽에 위치
both: 요소가 왼쪽 또는 오른쪽으로 플로트된 모든 요소 아래에 위치

clear: both

  • 요소가 이전의 모든 플로트된 요소들(왼쪽과 오른쪽 모두)의 영향을 받지 않도록 함

<body style="background-color: grey; height:3000px">  

    <div class="grey">
        <div class="image">
            <image src="laptop (2).jpeg" width="100%" id="mainImage">
        </div>
        <div style="clear:both"></div>
        <div class="text" id="firstText">
            어
			쩌
            고
        </div>
        <div style="clear:both"></div>
        <div class="text" style="margin-top: 300px;" id="secondText">
           	저
			쩌
			고
        </div>
    </div>

    <script>
        window.addEventListener('scroll', function() {
            var firstText = document.getElementById('firstText');
            var secondText = document.getElementById('secondText');
            var mainImage = document.getElementById('mainImage');
            
            var firstRect = firstText.getBoundingClientRect();
            var secondRect = secondText.getBoundingClientRect();
            var windowHeight = window.innerHeight;

            if (firstRect.bottom < 0 && secondRect.top <= windowHeight) {
                // firstText가 화면에서 벗어나고 secondText가 화면에 나타나면 이미지 변경
                mainImage.src = 'laptop (3).jpeg';
            } else {
                mainImage.src = 'laptop (2).jpeg';
            }
        });
    </script>
</body>
.grey {
    background : lightgrey;
    height : 2000px;
    margin-top : 500px;
}

.image {
    float : right;
    width : 40vw;
    position : sticky; /*div박스의 스크롤이 끝나면 해제됨*/ /*(fixed와 유사)*/
    top : 100px; /*상단 어디에 고정되는지*/
}

.text {
    float : left;
    width : 50vw;
}

✔ 스크롤 위치에 따라 변하는 애니메이션 (16강)

스크롤 위치에 따라 opacity가 변하는 애니메이션

  • $(window).scroll(function() : 스크롤 시
  • (window).scrollTop() : 내부코드, 현재 창의 스크롤바 높이를 알려줌
  • 800~ 1150까지 스크롤바를 내리면 첫째 카드의 opacity를 1- 0으로 서서히 변경
  1. 스크롤바 위치 확인
  2. 스크롤바높이가 800~1150이 될 때 1~0이 되는 가변적인 값"인 미지의 변수 y
    → 1 차 함수 사용
    → 계산해서
    y = a * 높이 + b
            1 = a * 800 + b ;
            0 = a * 1150 + b ;
            800a = b-1
            1150a = b
            - 350a = -1 
            a = -1 / 350
            b = 23/7
    → 대입 var y = (-1/350) * scrollHeight + (23/7);
    → $('.card-box').eq(0).css('opacity', y);
<body>
    <div class="card-background">
        <div class="card-box">
            <img src="laptop (2).jpeg">
        </div>
        <div class="card-box">
            <img src="laptop (3).jpeg">
        </div>
        <div class="card-box">
            <img src="laptop (4).jpeg">
        </div>
    </div>

    <script>
        $(window).scroll(function(){ // 스크롤 될때마다 실행, window는 뷰포트 의미
            var scrollHeight = $(window).scrollTop(); // 현재 스크롤 바 높이
            console.log(scrollHeight);

            var y = (-1/350) * scrollHeight  + (23/7);
            /*
            var y = a * 높이 + b
            1 = a * 800 + b ;
            0 = a * 1150 + b ;
            800a = b-1
            1150a = b
            - 350a = -1 
            a = -1 / 350
            b = 23/7
            */

            var z = (- 1/3500) * scrollHeight  + (43/35);
            /*
            1 = a * 800 + b;
            (9 / 10) = a * 1150 + b
            1 / 10 = - 350a
            a = - 1/3500
            b = 43/35
            */
            
            // 800~ 1150까지 스크롤바를 내리면
            // 첫째 카드의 opacity를 1- 0으로 서서히 변경
            $('.card-box').eq(0).css('opacity', y); // 미지의 변수 y를 넣어 사용 가능


            // 800~ 1150까지 스크롤바를 내리면
            // 카드의 크기가 1에서 0.9로 작아지도록        
            $('.card-box').eq(0).css('transform', `scale( ${z} )`); // transform : scale(z)
            $('.card-box').eq(0).css(' transition', 'all 0.2s'); 
        }); 
    </script>
</body>
.card-background{
    height:3000px;
    margin-top:800px;
    margin-bottom:1600px;
}

.card-box img {
    display : block;
    margin : auto;
    max-width : 50%;
    border-radius: 3%;
}

.card-box {
    position : sticky; // 위치 고정
    top : 200px;
    margin-top : 200px;
}

✔ 캐러셀 스와이프 기능 & 터치 이벤트(17-18강)

mouse 이벤트

  • 마우스로 html 요소를 조작할 때 발동하는 이벤트
    1. mousedown : 어떤 요소에 마우스버튼 눌렀을 때
  1. mouseup : 어떤 요소에 마우스버튼 뗐을 때
  2. mousemove : 어떤 요소위에서 마우스 이동할 때
<script>
  $('.slide-box').eq(0).on('mousemove', function(e){
    console.log(e.clientX) // 마우스의 현재 X좌표
  })
</script>

스와이프 해 사진 움직이기

  • 일정 px 만큼 드래그 하면 다음 이미지로, 일정 px보다 적게 움직이면 기존 이미지
  • draggable = false : 슬라이드 전환 기능이 드래그 이벤트로 인해 방해받지 않도록함
    <style>
    .slide-container{
        width : 300vw;
        /*margin-left:-100vw; 왼쪽으로 박스 이동*/
        overflow: hidden;
    }
    .slide-box{
        width:100vw;
        float : left; /*왼쪽으로 박스 배치*/
    }
    .slide-box img{
        width:100%;
    }
    </style>

    <div style="overflow: hidden">
        <div class="slide-container">
            <div class="slide-box">
                <img src="laptop (2).jpeg" draggable="false"> <!--드래그, 이동 할 수 없음-->
            </div>
            <div class="slide-box">
                <img src="laptop (3).jpeg">
            </div>
            <div class="slide-box">
                <img src="laptop (4).jpeg">
            </div>
        </div>
    </div>

 <script>
         let startX = 0 ; // 전역변수로 시작좌표  
         let down = false; // 마우스가 눌려있는지

        $('.slide-box').eq(0).on('mousedown', function(e){ // 마우스를 눌렀을 때
            console.log(e.clientX) // 현재 마우스 위치의 X좌표
            startX = e.clientX;
            down = true;
        })

        $('.slide-box').eq(0).on('mousemove', function(e){ // 마우스를 움직일 때
            //console.log(e.clientX)
            if(down == true){ // 마우스를 누른 상태라면
                console.log(e.clientX -startX) // 이동거리
                $('.slide-container').css('transform', `translateX(${e.clientX -startX}px`) // 우측으로 드래그한 거리만큼  이동
            }
        })


		// 마우스를 땠을 때 이동거리가 300 이상이면 2번사진 보여주기
        $('.slide-box').eq(0).on('mouseup', function(e){ // 마우스를 땠을 때
           down = false;
           if (e.clientX -startX < -300){
                $('.slide-container').css('transition', 'all 0.5s').css('transform', 'translateX(-100vw)');
           }else {
                $('.slide-container').css('transition', 'all 0.5s').css('transform', 'translateX(0vw)');
           }
           setTimeout(()=>{ // 이동이 끝났을 때 트랜지션 제거
                $('.slide-container').css('transition', 'none')
           }, 500); // 마우스를 떼면 0.5초정도 transition을 붙였다가 제거
        });
    </script>

모바일 터치 이벤트 리스너

  • 터치 스와이프 가능한 리스너
  1. touchstart : 터치시작시 발동
  2. touchmove : 터치중일 때 계속 발동
  3. touchend : 터치종료시 발동
  • e.clientX를 e.touches[0].clientX로 바꿔서 사용
    cuz. 터치는 여러 손가락으로 할 수 있어서, 몇번째 손가락인지 지정해주어야 함
  • touchend 리스너에는 e.clientX말고 e.changedTouches[0].clientX 사용
        // 모바일 기기 touchstart, touchmove, touchend
        $('.slide-box').eq(0).on('touchstart', function(e){ // 터치 했을 때
            startX = e.touches[0].clientX; // 터치이벤트 시 X좌표
            down = true;
        })

        $('.slide-box').eq(0).on('touchmove', function(e){ // 스와이프할 때
            //console.log(e.clientX)
            if(down == true){
                $('.slide-container').css('transform', `translateX(${e.touches[0].clientX -startX}px`) // 우측으로 드래그한 거리만큼  이동
            }
        })

        $('.slide-box').eq(0).on('touchend', function(e){ // 터치 종료
           down = false;
           if (e.changedTouches[0].clientX -startX < -300){ // changedTouches[0].clientX
                $('.slide-container').css('transition', 'all 0.5s').css('transform', 'translateX(-100vw)');
           }else {
                $('.slide-container').css('transition', 'all 0.5s').css('transform', 'translateX(0vw)');
           }
           setTimeout(()=>{ // 이동이 끝났을 때 트랜지션 제거
                $('.slide-container').css('transition', 'none')
           }, 500);
        });

Hammer.js

  • 외부 자바스크립트인 Hammer.js를 사용하면
  • 브라우저 호환성도 알아서 잡아줌
  • 이벤트리스너 6개대신 1개만 써도 됨
  • 스와이프, pinch, rotate 등 여러 제스쳐를 감지하는 이벤트리스너 제공해서 편리

응용

하얀 배경 보이지 않게

  • 첫 번째 이미지에서 스와이프 시 사진이 없을때 나오는 하얀 배경 나오지 않도록
$('.slide-box').eq(0).on('mousemove', function(e){ // 마우스를 움직일 때
            //console.log(e.clientX)
            if(down == true){
                console.log(e.clientX -startX) // 이동거리
                if(e.clientX - startX < 0){ // 이동거리가 음수일때만
                    $('.slide-container').css('transform', `translateX(${e.clientX -startX}px`) // 우측으로 드래그한 거리만큼  이동
                } 
            }
        })

나머지 사진에도 적용

  • $(document).ready(function(){}
    : DOM이 완전히 로드되었을 때 함수 내의 코드가 실행되도록 보장
  • moveX = e.clientX - startX;
    : 현재 마우스 위치의 X 좌표와 이전 startX 값의 차이를 계산하여 마우스 이동 거리를 구함
  • let newTranslateX = (currentSlide * -100) + (moveX / totalSlides);
    -currentSlide 현재 활성화된 슬라이드의 인덱스, 슬라이드가 왼쪽으로 이동할 때마다 값 변경
    -currentSlide*-100 현재 활성화된 슬라이드 인덱스에 슬라이드의 너비(100)을 음수로 곱해 X 슬라이드가 오른쪽으로 이동할 때마다 좌표 설정
    -(moveX / totalSlides) 마우스 이동 거리인 moveX를 슬라이드 개수로 나눈 값, 마우스 드래그에 대한 반응을 조절
  • let newTranslateX = currentSlide * -100;
    <script>
        $(document).ready(function() {
            let startX = 0;
            let down = false;
            let currentSlide = 0;

            $('.slide-box').on('mousedown',function(e){
                startX = e.clientX;
                down = true;
            });

            $(document).on('mousemove', function(e){
                if(!down) return;
                
                let moveX = e.clientX - startX;
                let newTranslateX = (currentSlide * -100) + (moveX / totalSlides); 
            
                // 현재 슬라이드가 첫 번째 슬라이드이고, 왼쪽으로 이동하려는 경우
                if (currentSlide === 0 && moveX > 0) {
                    newTranslateX = 0; // 왼쪽으로 추가 이동을 하지 않음
                }
                // 현재 슬라이드가 마지막 슬라이드이고, 오른쪽으로 이동하려는 경우
                else if (currentSlide === totalSlides - 1 && moveX < 0) {
                    newTranslateX = -(currentSlide * 100); // 오른쪽으로 추가 이동을 하지 않음
                }
                else {
                    $('.slide-container').css('transform', `translateX(${newTranslateX}vw)`);
                }
            });

            $(document).on('mouseup', function(e){
                if (!down) return;
                down = false;

                let moveX = e.clientX - startX;
                if (Math.abs(moveX) > 200){
                    if(moveX < 0 && currentSlide < totalSlides-1){
                        currentSlide++; // 오른쪽 이미지
                    } else if (moveX > 0 && currentSlide > 0){
                        currentSlide--; // 왼쪽 이미지
                    }
                }
                let newTranslateX = currentSlide * -100; // 이미지 크기만큼 이동한 새 좌표
       
                $('.slide-container').css('transition', 'all 0.5s');
                $('.slide-container').css('transform', `translateX(${newTranslateX}vw)`);
                
                setTimeout(function(){
                    $('.slide-container').css('transition', 'none')
                }, 500);
            });

        });
    </script>

✔ switch (19강)

  • if else보다 괄호가 적어 변수값에 따른 조건분기를 만들고 싶을 때 조금 더 간편하게 적을 수 있음
<body>
    <div id="quiz">
        <h4>1 + 1?</h4>
        <button>2</button>
        <button>누가 1 + 12 라고 결론 내림? 누구부터 시작된거야</button>
        <button>귀요미</button>
    </div>

    <script>
        let answer = document.querySelector('#quiz').addEventListener('click', 
            function(e){
                switch (e.target.innerHTML){
                    case '2' : alert("정답입니다."); break;
                    case '누가 1 + 1은 2 라고 결론 내림? 누구부터 시작된거야' : alert("세상에 불만을 덜어냅시다."); break;
                    case '귀요미' : alert("유행 지남"); break;
                    default : alert("아무것도 실행 안됨");
                }
        })
    </script>
</body>
profile
ByeolGyu

0개의 댓글