프로그래머스 고양이 사진 검색 사이트 - 개발 (랜덤 고양이 배너 섹션)

Z6su3·2022년 4월 21일
0

main.js ← App.js ← api/api.js
← components(floder) ← SearchInput.js
← SearchError.js
← SearchKeyword.js
← SearchResult.js
← ImageInfo.js
← ImageBanner.js
← Loading.js
← lib ← LocalStorage.js
← LazyLoading.js

검색 결과 목록 위 배너 형태의 랜덤 고양이 섹션을 추가해야합니다. 조건은 다음과 같습니다.

  • 앱이 구동될 시 /api/cats/random50 api요청 이후 결과를 별도 섹션에 노출
  • 검색결과가 많아도 5개까지만 화면에 노출
  • 각 이미지는 좌, 우 슬라이드 기능이 포함
  • 좌, 우 버튼을 클릭하면 현재 노출된 이미지는 사라지고, 이전 또는 다음 이미지를 보여준다. 트랜지션은 선택이다.

🐇 배너 데이터

앱이 구동되면 데이터를 요청하여 섹션에 넣어야한다. 해당 값을 관리하는 banner 변수를 생성하고, App.js에서 init시 데이터를 할당해준다.

App.js

...

export default function App($app) {
  this.state = {
    ...
    banner: [],
  };

	...

  const init = async () => {
    const initData = await request("random");

    this.setState({
      ...this.state,
      banner: initData,
      data,
    });

    const storage = getLocalStorage();

    if (!storage || !storage.data || !storage.data.length) {
      return;
    }

    this.setState({
      ...this.state,
      loading: false,
      data: storage.data,
    });
  };
  init();
}

🐇 슬라이드 만들기

슬라이드를 만드는 방법은 다양합니다.

🥕 CSS Margin

사용자에게 보이는 화면만을 고려하여 보여지는 요소와 가려진 요소의 크기를 고려하여 요소 전체를 좌우로 미는 형태로 구현되는 모습입니다.

🥕 요소 추가 삭제

구현방식은 슬라이드 리스트 내 요소를 삭제하고 추가하는 방식입니다. 마지막 조건에 따라서 전체를 삭제하고 추가하는 형태로 구현하셔도 좋습니다.

본 개발은, 마지막 조건에서 좌, 우 버튼 클릭 시 1개의 이미지가 사라지고 추가되는 형태로 구현되었습니다.

ImageBanner.js

export default function ImageBanner({ $app, initialState }) {
  this.state = initialState;
  this.$target = document.createElement("div");
  this.$target.className = "SlideShow";

  this.$prev = document.createElement("span");
  this.$prev.className = "prev";
  this.$prev.innerHTML = `⟨`;

  this.$slide = document.createElement("ul");
  this.$slide.className = "Slides";

  this.$next = document.createElement("span");
  this.$next.className = "next";
  this.$next.innerHTML = `⟩`;

  this.$target.appendChild(this.$prev);
  this.$target.appendChild(this.$slide);
  this.$target.appendChild(this.$next);

  $app.appendChild(this.$target);

  this.setState = (nextState) => {
    this.state = nextState;
    this.render();
  };

  this.render = () => {
    this.$slide.innerHTML = this.state
      .slice(0, 5)
      .map((cat, index) => {
        return `
					<li>
						<img src="${cat.url}" title="${cat.name}" data-index="${index}"/>
					</li>`;
      })
      .join("");
  };

  const changeSlides = (type) => {
		//좌, 우 버튼 선택에 따라 세부 조건을 변경
    type = type === "prev" ? true : false;

    const $slide = document.querySelector("ul");
		//좌 버튼을 누르는 경우 마지막요소를 선택
		//우 버튼을 누르는 겨웅 첫번째요소를 선택
    const $slideChild = $slide.querySelector(
      type ? "li:last-child" : "li:first-child"
    );
    const $slideImg = $slideChild.querySelector("img");
    const { index } = $slideImg.dataset;

		//새로운 요소의 데이터 인덱스 조정
    const idx = parseInt(index, 10) + (type ? -5 : +5);
    if (idx >= 0 && idx < this.state.length) {
			//선택한 요소 삭제
      $slideChild.remove();

			//삭제된 요소의 위치에 맞게 새 요소를 추가
      const $slideItem = document.createElement("li");
      $slideItem.innerHTML = `
	      <img src="${this.state[idx].url}" title="${this.state[idx].name}" data-index="${idx}"/>
	    `;
      type ? $slide.prepend($slideItem) : $slide.appendChild($slideItem);
    }
  };

  this.$prev.addEventListener("click", () => {
    changeSlides("prev");
  });
  this.$next.addEventListener("click", () => {
    changeSlides("next");
  });

  this.render();
}

App.js

...
import ImageBanner from "./components/ImageBanner.js";

...

export default function App($app) {
  ...

  const imageBanner = new ImageBanner({
    $app,
    initialState: [],
  });
	
	...

  this.setState = (nextState) => {
    this.state = nextState;
    ...
    imageBanner.setState(this.state.banner);
  };

  ...
}

추후 트랜지션을 적용하면, setInterval()를 이용하여 prev, lang버튼을 클릭하여 조절합니다.

profile
기억은 기록을 이길수 없다

0개의 댓글