TIL 2023.06.08(sort_정렬, dorpdown)

김지혜·2023년 6월 8일
0

✔️어떤 문제가 있었는지

"버튼 클릭 시 영화 카드 리스트의 제목을 기준으로 오름차순, 내림차순으로 정렬"되도록 기능을 구현하던 중

  • 영화 카드 리스트의 제목 값을 어떻게 따로 추출해야 하는가?
  • 홈페이지 내에서 카드가 정렬되는 기능을 어떤 함수코드로 작성해야 하는가?
    라는 문제에 봉착했다.

✔️내가 시도해본 것들

다른 팀원분의 코드에서 발전한 팀 프로젝트이기에 사진과 자세한 자료는 첨부가 어려움
-> 최대한 글로 설명해보자면 이렇다.

먼저 제목 값만 따로 추출하기 위해 다른 팀원분들께 도움을 요청했고,

팀원분들께서 친절하게 설명해주신 덕분에
-> 제목 값을 출력되게 하는 코드를 짜는 것에 성공했다.

// <html>
// dropdown 버튼
// 하위메뉴를 누르면 카드가 정렬되는 방식으로 구현할 예정
<div class="dropdown">
                <button class="dropdown-toggle" type="button" id="dropdownMenuButton1" data-bs-toggle="dropdown" aria-expanded="false">영화 제목 정렬</button>
                <ul class="dropdown-menu" aria-labelledby="dropdownMenuButton1">
                    <li><a class="dropdown-item1" id="dropdown-item1" href="#" onclick="sort1">오름차순</a></li>
                    <li><a class="dropdown-item2" id="dropdown-item2" href="#" onclick="sort2">내림차순</a></li>
                </ul>
            </div>
// <script>
// '검사' => 'console'에서 console.log();로 제목 값만 출력되도록
// 팀원분들께서 도와주셨다.
$sort.addEventListener('click', () => {
    const $movie_title = document.querySelectorAll('.movie-title');
    const sortedTitles = Array.from($movie_title);
 	
    sortedTitles.forEach(title => {
        console.log(title);
    });
});

=> 개발자 도구 -> 검사 -> console에서 먼저 영화의 제목 값만 출력되게끔 코드를 짰다.

출력결과

=> 이 추출된 제목 값으로 어떻게 카드를 정렬 시키는 기능을 구현하냐는 것이 다음 문제였다.

->

제목값을 추출한 코드를 기반으로 시도한 코드는 대략 이렇다.

// 시행 착오 _ console.log();
// 오름차순 정렬
 $sort1.addEventListener('click', () => {
     const $movie_title = document.querySelectorAll('.movie-title');
     const sortedTitles = Array.from($movie_title)
         .map(item => item.textContent)
         .sort((a, b) => a.localeCompare(b));
     sortedTitles.forEach(title => {
        console.log(title);
         card - list;
     });
 });

// 내림차순 정렬
$sort2.addEventListener('click', () => {
    const $movie_title = document.querySelectorAll('.movie-title');
    const sortedTitles = Array.from($movie_title)
        .map(item => item.textContent)
        .sort((a, b) => b.localeCompare(a)); // 내림차순 정렬

    sortedTitles.forEach(title => {
        console.log(title);
    });
});

=> 1번째 시도

&&

//  영화 제목
//  오름차순(2)
$sort1.addEventListener('click', () => {
    const $movieContainer = document.querySelector('.movie-container');
    const $movieCards = Array.from($movieContainer.querySelectorAll('.movie-card'));
    $movieCards.sort((cardA, cardB) => {
        const titleA = cardA.querySelector('.movie-title').textContent;
        const titleB = cardB.querySelector('.movie-title').textContent;
        return titleA.localeCompare(titleB);
    });

    $movieCards.forEach(card => {
        $movieContainer.appendChild(card);
    });
});

// 내림차순(2)
$sort2.addEventListener('click', () => {
    const $movieContainer = document.querySelector('.movie-container');
    const $movieCards = Array.from($movieContainer.querySelectorAll('.movie-card'));
    $movieCards.sort((cardA, cardB) => {
        const titleA = cardA.querySelector('.movie-title').textContent;
        const titleB = cardB.querySelector('.movie-title').textContent;
        return titleB.localeCompare(titleA);
    });

    $movieCards.forEach(card => {
        $movieContainer.appendChild(card);
    });
});

=> 2번째 시도

현재는 코드가 수정된 시점(버튼을 누르면 출력하는 코드 -> 완성된 코드로 수정됨)에서 쓰는 거라
자세한 출력 결과 사진 첨부가 어렵지만.

대략 제목 값과 똑같이 console.log();

오름차순 (a - b)

숫자(number) > 한글(kr => 가나다) > 영어(en => ABC)

내림차순 (b - a)

영어(en => ABC) > 한글(kr => 가나다) > 숫자(number)

=> 값이 출력되었다.

-> 하지만 어디까지나 console.log();일 뿐,

&&

페이지에서 카드가 정렬되는 기능을 구현하는 것은 막막했다.

= 구글링을 해본 결과
-> 다양한 함수와 다른 개발자들이 공유한 코드의 도움으로 해결할 수 있었다.

✔️어떻게 해결 했는지

1차 작업($cardList 배열 정렬)

= console.log();에서만 지속적으로 console 에서 값을 출력하는 것이 아닌
forEach$cardList배열을 순회할 수 있다는 사실을 알아냈다.

= $cardList를 중점적으로 코드를 짜는 것에만 집중했었는데,
-> $cardList는 그저 카드의 모음일 뿐.

카드를 각각 정렬되도록 수행하는 것은 "$cardList - $cardList.children"(부모 - 자식) 관계로 코드를 짜는 것이 더 효율적이었다.

// 실제 실현 코드
const $sort = document.querySelector('#dropdownMenuButton1');
const $sort1 = document.querySelector('#dropdown-item1');
const $sort2 = document.querySelector('#dropdown-item2');

console.log($sort1);

// consol.log(<p class = "movie-title"> "제목")
$sort.addEventListener('click', () => {
    const $movie_title = document.querySelectorAll('.movie-title');
    const sortedTitles = Array.from($movie_title);

    sortedTitles.forEach(title => {
        console.log(title);
    });
});

// 카드 오름차순 정렬
// html id="dropdown-item" href="#" 드롭다운 하위버튼과 연결
$sort1.addEventListener('click', () => {
    const $cardList = document.getElementById('card-list');
    const $cards = Array.from($cardList.children);

    $cards.sort((a, b) => {
        const titleA = a.querySelector('.movie-title').textContent;
        const titleB = b.querySelector('.movie-title').textContent;
        return titleA.localeCompare(titleB);
    });

    $cards.forEach(card => {
        $cardList.appendChild(card);
    });
});

// 카드 내림차순 정렬
// html id="dropdown-item2" href="#" 드롭다운 하위버튼과 연결
$sort2.addEventListener('click', () => {
    const $cardList = document.getElementById('card-list');
    const $cards = Array.from($cardList.children);

    $cards.sort((a, b) => {
        const titleA = a.querySelector('.movie-title').textContent;
        const titleB = b.querySelector('.movie-title').textContent;
        return titleB.localeCompare(titleA);
    });

    $cards.forEach(card => {
        $cardList.appendChild(card);
    });
});

=> 다른 팀원분의 코드로 진행하는 프로젝트 (+영화포스터, 제목 노출)이기에
-> 출력 결과 사진 첨부는 어렵지만 카드가 정렬되는 기능을 구현하는 것에 성공

2차 작업(dropdown 기능)

카드 배열에 성공
->
dropdown 버튼의 기능이 수행되도록 다시 2차 작업 시작

// 드롭다운 버튼
<html>
   <div class="dropdown">
                <button class="dropdown-toggle" type="button" id="dropdownMenuButton1" data-bs-toggle="dropdown" aria-expanded="false">영화 제목 정렬</button>
                <ul class="dropdown-menu" aria-labelledby="dropdownMenuButton1">
                    <li><a class="dropdown-item1" id="dropdown-item1" href="#" onclick="sort1">오름차순</a></li>
                    <li><a class="dropdown-item2" id="dropdown-item2" href="#" onclick="sort2">내림차순</a></li>
                </ul>
            </div>
</html>
<script>
// 드롭다운 버튼 클릭 시 이벤트 핸들러
const dropdownMenu = document.querySelector('.dropdown-menu');
const dropdownButton = document.getElementById('dropdownMenuButton1');

dropdownButton.addEventListener('click', function () {
    if (dropdownMenu.style.display === 'none') {
        dropdownMenu.style.display = 'block';
    } else {
        dropdownMenu.style.display = 'none';
    }
});

// 드롭다운 항목 클릭 시 이벤트 핸들러 
// console.log 오류 방지 + 버튼 작동 확인
const dropdownItems = document.querySelectorAll('.dropdown-item1, .dropdown-item2');

dropdownItems.forEach(item => {
    item.addEventListener('click', function (event) {
        event.stopPropagation(); // 이벤트 전파 중지
        const text = this.textContent;
        console.log(`Item ${text} clicked`);
    });
});

// 클릭 이벤트가 발생한 곳 이외의 영역을 클릭하면 메뉴를 닫음
document.addEventListener('click', function (event) {
    const dropdownMenu = document.querySelector('.dropdown-menu');
    const dropdownToggle = document.querySelector('.dropdown-toggle');

    if (!dropdownToggle.contains(event.target) && !dropdownMenu.contains(event.target)) {
        dropdownMenu.style.display = 'none';
    }
});

// 페이지 로드 시 메뉴 상태를 복원
// 원래는 구상 예정X, 하지만 페이지 새로 고침시
// ->
// 메뉴 버튼을 누르지 않아도 하위 메뉴가 생성되는 오류가 있기에 추가
window.addEventListener('load', function () {
    const menuState = localStorage.getItem('menuState');
    if (menuState === 'on') {
        dropdownMenu.style.display = 'block';
    } else {
        dropdownMenu.style.display = 'none';
    }
});
</script>
  • dropdown 버튼 실행 확인 완료된 코드
  • js로 기능을 구현하느라 시간을 지체하여
    -> css는 다음 기회에 개인적으로 구현해보기로 결심했다.

✔️새롭게 알게된 것

js & 함수

<html>

<a/> :

  • 객체 정의 - 주소 이동( = 링크)
  • 태그(요소)의 의미
  • 하이퍼링크를 만들 때도 사용

<li/> :

  • list의 약자, 목록을 만드는 태그
  • 단독 사용 X
  • 메뉴 등을 만들 때도 사용

href :

  • 같은 페이지 내에서 명시된 id를 가지고 있는 요소를 연결함.

href = "#" :

  • 일반적으로 클릭 시 아무 동작도 수행하지 않고
    -> 페이지의 위치를 변경하지 않는 링크

  • 주로 클릭 이벤트를 처리하기 위한 뼈대
    -> js 코드로 동작 구현 가능

= 일반적:

  • js 이벤트 핸들러와 함꺠 사용
    -> 클릭 이벤트 처리
const link = document.querySelector('a');
link.addEventListener('click', function(event) {
  event.preventDefault(); // 기본 동작 방지
  // 클릭 이벤트 처리 코드 작성
});

sort(메서드):

  • js의 배열의 내용을 정렬

  • 호출 시 배열의 요소들이 문자열로 취급되어 정렬
    => 정렬은 원본 배열을 변경 -> 변경된 배열로 전환

  • 오름차순 (a - b)

  • 내림차순 (b - a)

array.sort(compareFuntion);

array:

  • 정렬할 배열

compareFunction (선택 사항):

  • 정렬 순서를 정의 함수
  • 2개의 요소를 비교하고 정렬 순서에 따라 값 반환해야 함
  • 비교 함수를 제공하지 않으면 요소 -> 문자열로 변환되어 사전식으로 정렬
const numbers = [5, 1, 3, 2, 4];
numbers.sort(); // 기본적으로 문자열로 변환하여 사전식으로 정렬
console.log(numbers); // [1, 2, 3, 4, 5]

const words = ['banana', 'apple', 'cherry'];
words.sort(); // 문자열로 변환하여 사전식으로 정렬
console.log(words); // ['apple', 'banana', 'cherry']

const points = [40, 100, 1, 5, 25];
points.sort((a, b) => a - b); // 숫자 오름차순 정렬
console.log(points); // [1, 5, 25, 40, 100]
  • 반환 값 < 0
    => 첫 번째 요소가 두 번째 요소보다 앞에 정렬

  • 반환 값 = 0
    => 요소 정렬X

  • 반환 값 > 0
    => 첫 번째 요소는 두 번째 요소보다 뒤에 정렬


const $movie_title = document.querySelectorAll('.movie-title');:
= 문서 내에서 모든 클래스의 이름이 'movie-title'인 요소들을 선택
-> '$movie_title' 변수에 할당하는 역할

$movie_title(변수 이름):

  • 선택된 요소들을 나타내는 NodeList

'.movie-title':

  • js에서 사용되는 문자열
  • CSS 선택자
  • 클래스 이름이 "movie-title"인 모든 요소를 선택

forEach(메서드):

  • 배열 / NodeList와 같은 반복 가능한 매체에서 사용 가능
  • 각 요소에 대해 주어진 콜백 함수 실행

EX. dropdownItems에 대해 forEach 메서드를 사용하여 각 항목에 이벤트 리스너 추가

dropdownItems.forEach(item => {
    item.addEventListener('click', function (event) {
        event.stopPropagation(); // 이벤트 전파 중지
        const text = this.textContent;
        console.log(`Item ${text} clicked`);
    });
});

addEventListener(메서드):

  • 요소이벤트 리스너 추가
  • 첫번째 인자 -> 이름 지정,
    두번째 인자 -> 해당 이벤트 발생 시 실행할 함수(이벤트 핸들러 전달)

EX. dropdownButton 요소에 클릭 이벤트 리스너추가하고, 클릭 이벤트가 발생할 때마다 함수가 실행

dropdownButton.addEventListener('click', function () {
    if (dropdownMenu.style.display === 'none') {
        dropdownMenu.style.display = 'block';
    } else {
        dropdownMenu.style.display = 'none';
    }
});

querySelectorAll:

  • CSS 선택자일치하는 모든 요소 NodeList로 반환

EX.

const dropdownItems = document.querySelectorAll('.dropdown-item1, .dropdown-item2');

querySelector:

  • 문서 내에 지정CSS 선택자에 일치하는 첫 번째 요소 반환

EX.

const dropdownMenu = document.querySelector('.dropdown-menu');

getElementById(메서드):

  • 주어진 id 속성값해당하는 요소반환
  • 문서 내에서 고유한 id를 가진 요소를 선택할 때 사용

style.display:

  • 요소의 display 속성을 설정하거나 가져올 수 있는 속성.

EX. 드롭다운 메뉴 설정

dropdownMenu.style.display === 'none'
dropdownMenu.style.display = 'block'

none

text 박스가 보여지지 않음

block

text 박스가 아래로 보여짐


menuState(변수):

  • 로컬 스트로리지에서 메뉴 상태 저장

EX. localStorage.getItem('menuState')을 사용하여 menuState 키에 저장된 값을 가져옵니다.

window.addEventListener('load', function () {
const menuState = localStorage.getItem('menuState');

localStorage.getItem(메서드):

  • 로컬 스토리지에서 주어진 키에 해당하는 값을 가져옴

EX. menuState 키에 저장된 값을 가져옴

 const menuState = localStorage.getItem('menuState');

0개의 댓글