개인공부

[기본기다지기] 클릭수에 따른 인기차트 업데이트_HTML/CSS/JS

chsua 2023. 2. 3. 14:26

목표

1. 내가 생각한 웹 기능을 구현할 수 있는지 실험목적(어디까지 프론트엔드로 되는지 몰라서 그냥 머리속에서 웹기능을 하나씩 만들어보는중.. )

2. 이전에는 각 element 하나하나가 기능했다면 이번엔 동일한 류의 element(여기선 책)을 만들어 이걸 어떻게 다루어볼 수 있는지 확인

 

 

 

구상

1. 각 책은 아래로 임의 처리함

<a href="#" class="book 서울에서강릉으로"><img src="./book.png" />서울에서 강릉으로</a>

 > 왜 id로 안넣었느냐? 테마별 또는 best에 중복되는 경우 동일한 책이라고 처리하기 위해

 > id로 하면 같은 책인 다른 요소가 다른 id를 가져야한다고 생각했음 (예. NEW BOOk의 "코딩의.."와 best의 "코딩의.."가 같길바람)

 > 일단 이런 생각으로 id가 아닌 class로 처리했고, id로 같은 방식이 되는지 다시 해볼 생각.

 

2. JS에서 클릭을 받으면 class를 확인해서 클릭수를 ++해주고 이를 기반으로 best를 프린팅해주는 방식

 

3. 검색은 따로 기능처리 안함

 

백이 없어서 새로고침하면 다 날아감..

 

 

 

문제점

1. 처음에 class를 여러개 설정할 때  class="A" class="B"이렇게 하면 되는줄 알았음

2. 하지만 class="A B"이렇게 하는 것었음

3. 그래서 class를 book과 책제목(완전히 띄어쓰기까지 동일하게)으로 하려고 했는데 띄어쓰기를 포함하면 각 다른 class가 됨

        (ex. 책 제목 "나한테 맞는 운동 찾기"을 class="나한테 맞는 운동 찾기"로 하면 class가 4개가 됨...)

4. 결국 일단 임의로 다 붙여서 class를 작성했고 이를 기반으로 클릭수를 모으는 것(객체로 처리)까지 가능해짐

5. 이걸 가지고 프린팅하려고 보니까 class에 제목을 적어놨던건 띄어쓰기가 모두 사라진 상태.. 그래도 작동은 함

 

6. 이건 지금은 문제가 아닌데 만약 책의 갯수가 커진다면 해당 시스템은 굉장히 비효율적일 것이라고 생각됨

7. 지금은 map(this.book)에 "책의 class:click수"로 넣어서 하고, 이걸 array로 변환해서 sort해서 index로 top10을 추출함

8. 결국 실시간으로 top을 구하려면 클릭이 발생할때마다 해당 작업을 반복해야하고 책의 수가 많아지면 감당할 수 없을 것으로 추측

9. 하지만 이걸 어떻게 해결할 수 있을지 모르겠음. 현실에서는 백엔드가 하는일이려나.. 아니라면 어떻게 처리하면 좋을지 모르겠음 


코드

1. THLM

<!DOCTYPE html>
<html lang="ko">
    <head>
        <meta charset="utf-8">
        <link rel="stylesheet" href="./practice.css"/>
        <meta name="viewport" content="width=device-width">
        <title>practice</title>
    </head>

    <body>
        <header>
            <h1 class="title">BOOk LOOK BOOK LOOK</h1>
        </header>
        
        <main>
            <nav>
                <div class="categoryBox">
                <p class="category">카테고리</p>
                <a href="#">인문/사회</a>
                <a href="#">에세이</a>
                <a href="#">과학</a>
                <a href="#">정치</a>
                <a href="#">기타</a>
                </div>
                <div class="input"> 
                    <input class="submit">
                    <button type="submit">제출</button>
                </div>
            </nav>
        
            <div class="main">
                <div class="a">
                    <div class="bookList" class="newBook">
                        <p> NEW BOOK</p>
                        <a href="#" class="book 서울에서강릉으로"><img src="./book.png" />서울에서 강릉으로</a>
                        <a href="#" class="book 제주도에서카페열기"><img src="./book.png" />제주도에서 카페열기</a>
                        <a href="#" class="book 2050년강아지는세상을정복한다"><img src="./book.png" />2050년 강아지는 세상을 정복한다</a>
                        <a href="#" class="book 고양이,그귀여움에대하여"><img src="./book.png" />고양이, 그 귀여움에 대하여</a>
                        <a href="#" class="book 코딩으로인생역전"><img src="./book.png" />코딩으로 인생역전</a>
                        <a href="#" class="book 하루한잔,득과실"><img src="./book.png" />하루 한 잔, 득과 실</a>
                    </div>
                    <div class="bookList" class="weekTheme">
                        <p class="theme"> WEEK THEME_건강한 돼지가 되어보자!</p>
                        <a href="#" class="book 홈트!이렇게시작하자!"><img src="./book.png" />홈트! 이렇게 시작하자!</a>
                        <a href="#" class="book 저탄고지의진실"><img src="./book.png" />저탄고지의 진실</a>
                        <a href="#" class="book 건강하게다이어트하는방법"><img src="./book.png" />건강하게 다이어트하는 방법</a>
                        <a href="#" class="book 3개월,10kg감량성공비법"><img src="./book.png" />3개월, 10kg 감량 성공비법</a>
                        <a href="#" class="book 나한테맞는운동찾기"><img src="./book.png" />나한테 맞는 운동 찾기</a>
                        <a href="#" class="book 당에중독된다는말"><img src="./book.png" />당에 중독된다는 말</a>
                    </div>
                </div>
                <div class="best">
                    <p class="bestUpdate">BEST BOOK</p>
                    <!-- <div class="rank" id="1">  예시
                        <p class="rankNum"> 1. </p>
                        <a href="#"  class="book 서울에서강릉으로">서울에서 강릉으로</a>
                    </div> -->
                    <!-- <div class="rank" id="2"> 
                        <p class="rankNum"> 2. </p>
                        <a href="#"  class="book 저탄고지의진실">저탄고지의 진실</a>
                    </div> -->
                </div>
            </div>
        <main>
        <script src="practice.js"></script>
    </body>
</html>

 

2. CSS

/* body*/

body {
  width: 70%;
  margin: 0% auto;
  padding: 5%;
}

header {
  border-bottom: 3px solid black ;
  border-bottom-style: double;
  text-align: center;
  height: 80px;
}

.main{
  display: grid;
  grid-template-columns: 3fr 1fr;
}

a{
  text-decoration:none;
}

.input{
  display:inline;
}

main a {
  color:rgb(27, 27, 27) ;
}

/* nav */
nav {
  border-bottom: 0.3px solid rgba(53, 53, 53, 0.3);;
  padding: 1% 1% 1% 3%;
  display: grid;
  grid-template-columns: 3fr 1fr;
  gap: 3%;
  text-align: center;
}

.categoryBox {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr;
  gap: 3%;
}

.categoryBox > a, .category {
  border: 1px solid tan;
  color: teal;
  border-radius: 10px;
  font-size: smaller;
  line-height: 2;
}

.category{
  display: block;
  background-color: teal;
  border: 1px solid teal;
  color:white ;
  margin:0px ;

}

.categoryBox > a:hover{
  background-color: tan;
  color:black;
}

.input{
  align-self : right;
}


/* bookList */
.bookList {  
  padding:3%;
  display: grid;
  grid-template-columns: 1fr 1fr 1fr 1fr;
  grid-template-rows: 12% 44% 44%;
}

.bookList > a{
  padding-bottom: 10px;
  margin: 3%;
  margin-bottom: 8%; 
  border: 0.3px solid rgba(53, 53, 53, 0.3);
  text-align: center;
  font-size: small;
  overflow:hidden;
}

img{
  width: 70%;
  display: block;
  margin: 9% auto;
}

.bookList > p{
  grid-column: 1/5;
  font-size: larger;
  font-weight: bold;
  position: relative;
  bottom: 4%;
}

/* best */
.best {
  border-left: 1px solid rgba(53, 53, 53, 0.3) ;
  margin: 5%;
  padding: 5% 0 -5% 5%;
}

.rank {
  font-size: small;
  margin: 3%;
  padding: 3%;
  border-bottom: 1px solid rgba(53, 53, 53, 0.3) ;
  text-align: center;
}

.rank > p {
  display: inline;
  margin-right: 3%;

}

.bestUpdate {
  text-align: center;
  font-weight: bold;
}

 

3. JS

const bookElem = document.querySelectorAll(".book");
const body = document.querySelector("body");
const bestElem = document.querySelector(".best");

class Best {

    constructor() {
        this.books = new Map();
        this.best = [];
    }

    init() {
        bookElem.forEach(book => {
            book.addEventListener("click", this.bookClick.bind(this));
            book.addEventListener("click", this.bestUpdate.bind(this));
            this.books.set(book.className, 0);
        });


    }

    bookClick(event) {
        let eventElemClass = event.target.className;
        if (!this.books.has(event.target.className)) {
            eventElemClass = event.target.parentElement.className;
        }

        console.log(eventElemClass);
        this.books.set(eventElemClass, this.books.get(eventElemClass) + 1);
    }

    bestUpdate() {
        this.best = [...this.books];
        this.best.sort((a, b) => b[1] - a[1]);

        bestElem.innerHTML = "";

        const pElem = document.createElement("p");
        pElem.classList.add("bestUpdate");
        pElem.textContent = "BEST BOOK";
        bestElem.appendChild(pElem);

        for (let i = 0; i < 10; i++) {
            if (this.best[i][1] !== 0) {
                this.makeRank(i + 1, this.best[i][0]);
            }
        }

    }

    makeRank(rankNum, name) {
        const divElem = document.createElement("div");
        divElem.classList.add("rank")
        divElem.setAttribute("id", rankNum);
        bestElem.appendChild(divElem);
        divElem.addEventListener("click", this.bookClick.bind(this));
        divElem.addEventListener("click", this.bestUpdate.bind(this));

        const pChildElem = document.createElement("p");
        pChildElem.classList.add("rankNum")
        pChildElem.textContent = `${rankNum}.`;
        divElem.appendChild(pChildElem);

        const aChildElem = document.createElement("a");
        aChildElem.setAttribute("href", "#");
        const onlyName = name.split(" ");
        aChildElem.classList.add(onlyName[0]);
        aChildElem.classList.add(onlyName[1]);
        aChildElem.textContent = onlyName[1];
        divElem.appendChild(aChildElem);

    }

}

const best = new Best();
best.init();