팀 프로젝트 영화 정렬 구현하기
TIL 23. 10. 26
오늘 한 일
- 영화 목록 정렬 기능 구현
- 팀 프로젝트 3일차 진행사항
영화 목록 정렬 구현
영화를 제목과 평점을 기준으로 정렬하는 기능을 구현했다. main.js는 실행만 담당한다. form 요소에 sumbit 이벤트가 발생하면 정렬을 하도록 이벤트 핸들러를 등록했다.
// main.js
import { generateMovieCards } from './movie.js';
import { performSearch } from './search.js';
import { filterAndSortMovieCards } from './sort.js';
generateMovieCards();
const $form = document.querySelector('#search');
const $searchInput = document.getElementById('search-input');
const $sortForm = document.querySelector('#sort-form');
$form.addEventListener('submit', (event) => {
event.preventDefault();
performSearch($searchInput.value);
});
$sortForm.addEventListener('submit', (event) => {
event.preventDefault();
filterAndSortMovieCards();
});
처음에는 $sortForm
이벤트 리스너에서 이미 브라우저에 그려진 영화 카드를 모두 지우고 다시 그렸었다. 그런데 generateMovieCards 함수는 fetch 즉, API 호출을 하는 함수인데 그럴 때마다 서버에 요청을 보내는 것이 비효율적이라고 생각했다. 그래서 DOM 요소에 그려진 요소를 정렬하는 방향으로 개발을 진행했다. 추후에 스크롤하며 영화를 추가 요청하는 확장성도 고려헸다.
<!-- index.html -->
<form id="sort-form">
<div id="sort" class="sort">
<div class="sort-container">
<label for="genre">GENRE</label>
<select name="genre" id="genre">
<option value="default">default</option>
<option value="action">Action</option>
<option value="adventure">Adventure</option>
<option value="animation">Animation</option>
<option value="aomedy">Comedy</option>
</select>
</div>
<div class="sort-container">
<label for="rating">RATING</label>
<select name="rating" id="rating">
<option value="default">default</option>
<option value="5+">5+</option>
<option value="6+">6+</option>
<option value="7+">7+</option>
<option value="8+">8+</option>
<option value="9+">9+</option>
</select>
</div>
<div class="sort-container">
<label for="orderby">ORDER BY</label>
<select name="order" id="orderby">
<option value="default">default</option>
<option value="title">title</option>
<option value="rating">rating</option>
</select>
</div>
<button id="sort-btn">SORT</button>
</div>
</form>
간단히 스타일을 적용해서 구현했다. 추후에 버튼과 select css를 적용하고 장르도 옵션을 확장할 예정이다. form 태그를 정보 제출이라는 의미로 필터링이나 정렬 기준 정보를 보내 수행한다는 맥락에서 사용했다.
HTML
<form>
요소는 정보를 제출하기 위한 대화형 컨트롤을 포함하는 문서 구획을 나타냅니다. - MDN
// sort.js
import { SORTBY } from './constants.js';
const $sortContainer = document.querySelectorAll('#sort>div>select');
const $movieList = document.querySelector('#movie-list');
export const filterAndSortMovieCards = () => {
const obj = {};
const sortObj = { 0: 'genre', 1: 'rating', 2: 'order' };
for (let [idx, node] of $sortContainer.entries()) {
if (node.value === 'default') {
obj[sortObj[idx]] = undefined;
continue;
}
obj[sortObj[idx]] = node.value;
}
const { genre, rating, order } = obj;
if (!genre && !rating && !order) return;
const $movieCards = document.querySelectorAll('.movie-card');
[...$movieCards]
.sort((cardLi1, cardLi2) => {
switch (order) {
case SORTBY.TITLE:
const cardTitle1 = cardLi1
.querySelector('h2')
.innerHTML.toUpperCase();
const cardTitle2 = cardLi2
.querySelector('h2')
.innerHTML.toUpperCase();
if (cardTitle1 < cardTitle2) return -1;
if (cardTitle1 > cardTitle2) return 1;
return 0;
case SORTBY.RATING:
const cardRating1 = +cardLi1
.querySelector('h5')
.innerHTML.split(' ')[2];
const cardRating2 = +cardLi2
.querySelector('h5')
.innerHTML.split(' ')[2];
return cardRating1 - cardRating2;
// case SORTBY.YEAR:
// return;
default:
return;
}
})
.forEach((element) => $movieList.append(element));
};
아직 장르와 평점 순으로 필터링하는 것은 구현하지 못했다. 폼 요소의 submit 이벤트 콜백함수인 filterAndSortMovieCards 함수가 호출되면 먼저 select의 값을 가져오고자 했다. 예상하지 못했던 것은 querySelectAll의 반환값이 NodeList
이었다. sort, filter, map 메서드를 적용할 수 없었다.
참고:
NodeList
가Array
는 아니지만,forEach()
를 사용하여 반복할 수 있습니다. 또한Array.from()
을 사용하여Array
로 변환 할 수도 있습니다. - NodeList
MDN 문서를 보고 NodeList에 사용 가능한 메서드 NodeList.entries()
를 사용했다.
NodeList.entries()
메서드는 이 객체에 포함된 모든 key/value 쌍을 통과하는iterator
를 반환합니다. 이 값(value)은Node
(en-US) 객체입니다. NodeList.entires()
entries 메서드는 인덱스와 노드를 반환했다. 이를 변수에 저장해 순회하며 객체로 만들었다. 지금 보니 정렬과 필터링 기준으로 객체를 만드는 것은 외부 함수로 작성하면 가독성이 좋을 것 같다.
스프레드 연산자를 이용해 NodeList를 일반 배열로 변환할 수 있었다. sort 메서드로 siwtch 문을 사용해 정렬을 구현했다.
팀 프로젝트 3일차 협업 진행사항
느낀점
역시나 팀 분할 작업은 쉽지 않다. 이제 github 사용은 익숙해졌다. git add, commit
push 전 git pull origin develop
. commit을 하지 않고 최신화하려면 git stash, pull, stash pop
. 염려했던 것보다 git 전략이 잘 사용되고 있다. 팀원들도 전체 개발 프로세스를 이해하고 잘 사용하고 있다. 그리고 다들 열심히 해서 많은 동기부여가 된다.
협업하는 과정에서 팅뭔이 아직 기능 개발이나 UI 구현이 완료되지 않은 상태에서 개발을 할 때 dummy 데이터와 temp 파일을 만들어서 활용하는 방법을 터득했다. html과 css 혹은 로직을 테스트할 때 팀원이 작업하는 파일의 변경점을 만들지 않고 새로운 파일을 생성해서 테스트한다. 해당 파일은 로컬에서만 사용하고 develop 브랜치에 push하지 않는다.
개발 프로세스에 따라 협업이 익숙해지고 있다. 이제 기능 개발과 UI 개선, 리팩토링에 좀 더 힘 써야겠다.
댓글남기기