미디어 페이지 (유투브 api 예제)

works.html

<!DOCTYPE html>
<html lang="ko">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>실습 예제: 취업용 프로필 페이지 제작</title>
    <link rel="stylesheet" href="css/style.css" />
    <script
      src="https://kit.fontawesome.com/ccbe8c103f.js"
      crossorigin="anonymous"
    ></script>
    <link rel="preconnect" href="https://fonts.googleapis.com" />
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
    <link
      href="https://fonts.googleapis.com/css2?family=Gowun+Batang&family=Noto+Sans+KR:wght@100..900&family=Orbitron:wght@400..900&display=swap"
      rel="stylesheet"
    />
    <script type="module" src="js/common.js"></script>
    <script type="module" src="js/youtube.js"></script>
  </head>

  <body>
    <div class="wrap">
      <header>
        <h1><a href="index.html" title="인트로 페이지 이동">SANG-DO NAM</a></h1>

        <nav>
          <a href="profile.html">About me</a>
          <a href="works.html">My works</a>
          <a href="blog.html">Diary</a>
          <a href="join.html">Join</a>
          <a href="login.html">Login</a>
        </nav>

        <div class="btnToggle">
          <p></p>
          <p></p>
          <p></p>
        </div>
      </header>

      <main class="work">
        <h1>My Works</h1>
        <section class="frame"></section>
      </main>

      <footer>
        <ul>
          <li>
            <a href="#" target="_blank"><i class="fa-brands fa-youtube"></i></a>
          </li>
          <li>
            <a href="https://sd-ux.blogspot.com/" target="_blank"
              ><i class="fa-brands fa-google"></i
            ></a>
          </li>
          <li>
            <a href="#" target="_blank"
              ><i class="fa-brands fa-square-facebook"></i
            ></a>
          </li>
        </ul>
        <p>2025 nam sang do &copy; All right reserved.</p>
      </footer>
    </div>

    <aside class="mobileMenu"></aside>

    <aside class="popup">
      <span class="closePop">close</span>
      <div class="con"></div>
    </aside>
  </body>
</html>


youtube.js

const api_key = 'AIzaSyAA1--4yowu_MLnUqDB7a200vEhqphM84Q';
const pid = 'PLXVj76JGLotR4xaw0HyL9VwOa5y6efr_j';
const num = 3;

const base_url = 'https://www.googleapis.com/youtube/v3/playlistItems';
const req_url = `${base_url}?part=snippet&playlistId=${pid}&key=${api_key}&maxResults=${num}`;

const frame = document.querySelector('.frame');

// 유튜브 데이터 호출 및 동적 UI 생성
fetch(req_url)
  .then(data => {
    return data.json();
  })
  .then(json => {
    const youtubeData = json.items;

    let tags = '';

    youtubeData.forEach((data, index) => {
      console.log(data);

      let tit = '';
      let desc = '';

      if (data.snippet.title.length > 35) {
        tit = data.snippet.title.substring(0, 35) + '...';
      } else {
        tit = data.snippet.title;
      }

      data.snippet.description.length > 120
        ? (desc = data.snippet.description.substring(0, 120) + '...')
        : (desc = data.snippet.description);

      // 동적으로 생성될 유튜브 제목, 썸네일, 본문 정보
      tags += `
        <article>
          <h2>${tit}</h2>
          <!-- 추후 figure클릭시 영상 출력을 위해서 videoId값 data-vid란 커스텀 속성에 미리 담아둠 -->
          <figure class='pic' data-vid=${data.snippet.resourceId.videoId}>
            <img src=${data.snippet.thumbnails.high.url} />
          </figure>
          <p>${desc}</p>
          <span>${data.snippet.publishedAt
            .split('T')[0]
            .split('-')
            .join('.')}</span>
        </article>      
      `;
    });

    //해당 시점이 빈문서에 동적으로 썸네일이 생성되는 시점 (동적 요소 생성 시점)
    frame.innerHTML = tags;

    //모달 열고 닫기 이벤트 연결 (동적돔이 생성된 이후에 이벤트 연결 가능)
    const popup = document.querySelector('.popup');
    const popupCon = popup.querySelector('.con');
    const pics = document.querySelectorAll('.pic');
    const closePop = document.querySelector('.closePop');

    //복수개 썸네일 요소에 일괄적으로 이벤트 연결
    pics.forEach((data, index) => {
      data.addEventListener('click', e => {
        e.preventDefault();

        console.dir(data);

        // 썸네일 클릭시 미리 준비한 data-vid의 속성에 있는 videoId값 가져옴
        const vidId = data.getAttribute('data-vid');
        console.log(vidId);

        //console.log(`${index}번째 썸네일 클릭`);
        popup.style.display = 'block';
        // 해당 vidId값을 ifrrame의 src 부분에 연결해서 유튜브 영상 프레임 동적 생성
        popupCon.innerHTML = `<iframe src="http://www.youtube.com/embed/${vidId}"></iframe>`;
      });
    });

    // 팝업 닫기 버튼 이벤트 연결
    closePop.addEventListener('click', e => {
      e.preventDefault();
      popup.style.display = 'none';
    });
  });


_work.scss

.work {
  width: 100%;

  h1 {
    font: 600 1.3rem/1 'orbitron';
    margin-bottom: 40px;
    text-align: left;
  }

  section {
    width: 100%;
    display: flex;
    justify-content: space-between;
    margin-bottom: 50px;

    article {
      width: 32%;
      text-align: left;

      h2 {
        font-weight: bold;
        font-size: 1rem;
        margin-bottom: 10px;
        text-align: left;
      }

      figure {
        width: 100%;
        height: 10vw;
        margin-bottom: 10px;
        filter: saturate(0);
        transition: 0.5s;

        &:hover {
          filter: saturate(1.6);
        }
      }

      p {
        font-size: 0.8rem;
        line-height: 1.2;
        text-align: justify;
        opacity: 0.6;
      }
      span {
        font-size: 0.7rem;
        color: var(--point-lch);
        font-family: 'orbitron';
      }
    }
  }
}

.popup {
  width: 80%;
  height: 80vh;
  position: fixed;
  top: 50%;
  left: 50%;
  background: black;
  margin-left: -40%;
  margin-top: -40vh;
  display: none;
  padding: 100px;

  .closePop {
    position: absolute;
    top: 50px;
    right: 50px;
    color: white;
    cursor: pointer;
    transition: 0.5s;

    &:hover {
      color: var(--point-lch);
    }
  }

  .con {
    width: 100%;
    height: 100%;
    border: 1px solid gray;

    iframe {
      width: 100%;
      height: 100%;
      object-fit: cover;
      border: none;
    }
  }
}



댓글 쓰기

다음 이전