만들 수 있다! 이미지 슬라이더!

단점: 아직 자동재생이 안됨


기본편

참고 사이트: https://penguingoon.tistory.com/255

하단에 있는 이전/다음버튼을 누르면 그림이 움직인다.

HTML

<!DOCTYPE html>
<html>

<head>
    <link href="style.css" rel="stylesheet">
    <title>저세상 이미지 슬라이더</title>
</head>

<body>
    <div class="container">
        <h1>Dotted wallpaper 둘러보기</h1>
        <div class="slider">
            <div class="image">
                <img src="https://i.imgur.com/ExRqDrt.png">
                <img src="https://i.imgur.com/XOLeZVs.png">
                <img src="https://i.imgur.com/7eHRY2s.png">
                <img src="https://i.imgur.com/WoZAGSa.png">
                <img src="https://i.imgur.com/ADHH2MR.png">
            </div>
        </div>
        <button class="prev">이전</button>
        <button class="next">다음</button>
    </div>
    <script src="script.js">
    </script>
    <div class="text">
        <p>본 이미지 슬라이더에 사용된 이미지는 전부 수제입니다. 도트찍느라 고생했습니다... </p>
    </div>
</body>

</html>

사실 얘는 뼈대라 특별히 설명할 건 없다. 응용편의 경우 밑에 뭐가 하나 더 들어간다는 것 빼곤 진짜 특별할 게 없다. 

CSS

@import url('https://fonts.googleapis.com/css2?family=Gaegu&display=swap');

* {
    font-family: 'Gaegu', cursive;
}

.container {
    width:972px;
    margin:0 auto;
}

.text{
    text-align:center;
    font-size:13pt;
}

h1 {
    text-align:center;
}

.slider {
    height:600px;
    width:972px;
    overflow:hidden; /*한 장만 보여주기 위해 필요*/
}

.image {
    position:relative;
    display:flex;
    height:600px;
}

img {
    width:972px;
    height:600px;
}

button, button:active, button:focus {
    width:100px;
    height:45px;
    font-size:16pt;
    border:1px dotted #00498c;
    color:#00498c;
    background-color:white;
    outline:none;
}

button:hover {
    background-color:#00498c;
    color:white
}

button:disabled {
    border:1px dotted gray;
    color:gray;
}

button:disabled:hover {
    background-color:gray;
    color:white;
}

.prev {
    float:left;
}

.next {
    float:right;
}

얘 응용편 코드는 네이버에서 짤리게 생겼어… ㄷㄷ

JS

let curPos = 0;
let position = 0; 
const IMAGE_WIDTH = 972;
const prevBtn = document.querySelector(".prev")
const nextBtn = document.querySelector(".next")
const images = document.querySelector(".image")
//const는 뭐지? 

function prev() {
    if (curPos > 0) {
        nextBtn.removeAttribute("disabled");
        position += IMAGE_WIDTH;
        images.style.transform = `translateX(${position}px)`;
        curPos = curPos - 1;
    }
    if(curPos == 0){
        nextBtn.removeAttribute("disabled");
        position -= (IMAGE_WIDTH * 5);
        images.style.transform = `translateX(0)px)`;
        curPos = 5;
    }
}
//이전 버튼

function next() {
    if (curPos < 5) {
        prevBtn.removeAttribute("disabled");
        position -= IMAGE_WIDTH;
        images.style.transform = `translateX(${position}px)`;
        curPos = curPos + 1;
    }
    if(curPos == 5){
        prevBtn.removeAttribute("disabled");
        position += (IMAGE_WIDTH * curPos);
        images.style.transform = `translateX(${position}px)`;
        curPos = 0;
    }
}
//다음 버튼

function init(){
    prevBtn.addEventListener("click", prev)
    nextBtn.addEventListener("click", next)
    }
init();

사실상 얘가 코어다. 그니까 대충 HTML은 뼈대, CSS는 살, JS는 작동을 담당한다고 보면 된다. 

어? 근데 HTML코드에 onclick이 없네요? 그것은 init()이라는 함수에서 addEventListener로 prev와 next 버튼을 클릭하면 해당 함수를 불러라~ 라고 설정했기 때문이다. 원래는 이전버튼 비활성화도 같이 했었는데 뺑뺑이 돌리면서 그건 빼버렸다. 그럼 로직이 어떻게 되느냐…

function next() {
    if (curPos < 5) {
        prevBtn.removeAttribute("disabled");
        position -= IMAGE_WIDTH;
        images.style.transform = `translateX(${position}px)`;
        curPos = curPos + 1;
    }
    if(curPos == 5){
        prevBtn.removeAttribute("disabled");
        position += (IMAGE_WIDTH * curPos);
        images.style.transform = `translateX(${0}px)`;
        curPos = 0;
    }
}

이건 Next버튼의 코드이다. transform은 CSS에서 어떤 요소를 변형하는것. 즉, Next 버튼을 누르면 position에서 이미지의 가로 길이(고정값)만큼 X좌표를 옮겨간다. 그럼 curPos가 5인 건? HTML 소스에 이미지 다섯 장 있었음. 

즉, 이미지가 맨 마지막이 아닐 때는 다음 장으로 넘어가고, 이미지가 맨 마지막이면 다시 처음 이미지로 돌아간다. Prev 버튼은 반대로 맨 처음 이미지일 때 마지막으로 가고, 아니면 한장 뒤로 돌아가는 것. 

Prev와 next 버튼이 각각 맨 처음, 맨 끝일 때 처리는 참고문헌에 없었다. 그냥 내가 버튼 연타로 누르기 귀찮아서 추가했지… 

응용편

근데 이제 그 어디서 많이 본 그런…

HTML

<html>

<head>
    <link href="style.css" rel="stylesheet">
    <script src="https://kit.fontawesome.com/dc58858c96.js" crossorigin="anonymous"></script>
    <title>저세상 이미지 슬라이더 시즌 2</title>
</head>

<body>
    <div class="wrap">
        <h1>돌아온 이미지 슬라이더 feat. 폰트어썸</h1>
        <h2>만드느라 정말 고생했습니다... 특히 밑에 저 점 움직이는거... </h2>
        <div class="container">
            <button class="prev">
                <i class="fa-solid fa-angle-left" id="prev"></i>
            </button>
            <div class="slider">
                <div class="image">
                    <img src="https://i.imgur.com/girxIea.jpg">
                    <img src="https://i.imgur.com/vSDcWOZ.jpg">
                    <img src="https://i.imgur.com/PutJ2re.jpg">
                    <img src="https://i.imgur.com/sexakO0.jpg">
                    <img src="https://i.imgur.com/oLXNhqu.jpg">
                    <img src="https://i.imgur.com/3l9IcG3.jpg">
                    <img src="https://i.imgur.com/yAacpMb.jpg">
                    <img src="https://i.imgur.com/kPCC0eD.jpg">
                    <img src="https://i.imgur.com/oS0TfYm.jpg">
                    <img src="https://i.imgur.com/gxr9C6X.jpg">
                </div>
            </div>
            <button class="next">
                <i class="fa-solid fa-angle-right" id="next"></i>
            </button>
            <div class="bar">
                <div class="activate"></div>
                <div></div>
                <div></div>
                <div></div>
                <div></div>
                <div></div>
                <div></div>
                <div></div>
                <div></div>
                <div></div>
            </div>
        </div>
        <script src="script.js"></script>
    </div>
</body>

</html>

잘 보면 slider 밑에 bar라는 div가 하나 더 추가됐는데, 이게

이거다. 왜 사이트에서 이벤트 공지나 배너같은 거 슬라이더에 올려두고 빙빙 돌릴 때 이미지가 쇽쇽 돌아갈때마다 저 점도 같이 움직이잖음?

CSS

@font-face {
    font-family: 'Goyang';
    src: url('https://cdn.jsdelivr.net/gh/projectnoonnu/noonfonts_one@1.0/Goyang.woff') format('woff');
    font-weight: normal;
    font-style: normal;
}

* {
    margin: 0;
    padding: 0;
    font-family: 'Goyang';
    color:#2C3333;
    background-color:#E7F6F2;
}

h1, h2 {
    text-align:center;
    margin-bottom:20px;
}

.prev, .next {
    text-align: center;
    font-size:60pt;
}

button {
    border:none;
}

button:disabled > i {
    color:#A5C9CA;
}

.wrap {
    width: 1280px;
    margin:0 auto;
}

.container {
    width:1280px;
    display: grid;
    grid-template-columns: auto 960px auto;
    align-items: center;
}

.slider {
    width:960px;
    overflow:hidden;
}

img {
    width:960px;
}

.image {
    display:flex;
    position:relative;
    transition: all 1s;
}

.bar {
    grid-column: 2 / span 1;
    text-align:center;
    margin: 20px auto 0 auto;
    display:flex;
}

.bar div {
    width:20px;
    height:20px;
    background-color:#A5C9CA;
    margin: 0 10px 0 15px;
    border-radius:15px;
    transition: all 0.5s;
}

.bar .activate {
    background-color:#2C3333;
}

워… 안 짤린 게 기적이다… 아래쪽 bar에 대해서 CSS가 추가된 부분은 모양과 grid 위치 관련(상위 요소가 grid이다). activate 클래스는 현재 화면에 보이는 그림 위치이다. transition은 스무th하게 움직일 수 있게 설정해주는 거라고 보면 된다. 

JS

let curPos = 0;
let position = 0;
const IMAGE_WIDTH = 960;
const prevBtn = document.querySelector(".prev");
const nextBtn = document.querySelector(".next");
const images = document.querySelector(".image");
const dot = document.querySelectorAll('.bar > div');

function prev() {
    if (curPos > 0) {
        nextBtn.removeAttribute("disabled");
        position += IMAGE_WIDTH;
        images.style.transform = `translateX(${position}px)`
        dot[curPos].classList.remove("activate")
        curPos = curPos - 1; 
        dot[curPos].classList.add("activate")
    }
    else if (curPos == 0) {
        nextBtn.removeAttribute("disabled");
        position -= (IMAGE_WIDTH * 6);
        images.style.transform = `translateX(0)px)`
        dot[curPos].classList.remove("activate")
        curPos = 6;
        dot[curPos].classList.add("activate")
    }
}

function next() {
    if (curPos < 9) {
        prevBtn.removeAttribute("disabled");
        position -= IMAGE_WIDTH;
        images.style.transform = `translateX(${position}px)`
        dot[curPos].classList.remove("activate")
        curPos = curPos + 1
        dot[curPos].classList.add("activate")

    }
    else if (curPos == 9) {
        prevBtn.removeAttribute("disabled");
        position += (IMAGE_WIDTH * curPos);
        images.style.transform = `translateX(${position}px)`
        dot[curPos].classList.remove("activate")
        curPos = 0;
        dot[curPos].classList.add("activate")
    }
}

function init() {
    prevBtn.addEventListener("click", prev)
    nextBtn.addEventListener("click", next)
    dot[curPos].classList.add("activate")
}

init();

위에 그 점같은 게 그림이 움직일 때 같이 움직여야 한다고 했잖음? 그래서 이전-다음버튼을 누를 때 이 점같은 게 색깔이 바뀌어야 하는데, 그걸 클래스 추가/제거를 통해서 하게 된다. 그래서 init 함수에서 0번 도트에 클래스를 추가하게 된다. (저게 배열로 가져오더라고…)

아무튼 그래서 이미지가 스무th하게 움직이는 어디서 많이 본 슬라이더가 탄생했다.