第八週作業訂正、Twitch API


Posted by s103071049 on 2021-06-07

優化程式碼

每做好一步,請確定功能沒壞
目前代碼長相:

  <!DOCTYPE html>

<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Twitch Live Games</title>
  <meta name="description" content="Week8 作業">
  <link rel="stylesheet" href="https://necolas.github.io/normalize.css/8.0.1/normalize.css">
  <style>
    * {
      box-sizing: border-box;
    }

    .navbar {
      position: fixed;
      height: 60px;
      background: white;
      box-shadow: 1.4px 1.4px 6px 0 #97a2a0;
      left: 0;
      right: 0;
      top: 0;
      display: flex;
      justify-content: space-between;
      padding: 0px 36px;
      align-items: center;
      z-index: 2;
    }

    .navbar__site {
      font-size: 32px;
    } 

    .navbar__nav {
      display: flex;
      list-style: none;
      margin: 0;
      padding: 0;
      flex: 1;
      justify-content: flex-end;
      align-items: stretch;
      height: 100%;
    }

    .navbar__nav li {
      cursor: pointer;
      padding: 10px;
      display: flex;
      align-items: center;
      margin-left: 16px;
      transition: all 0.2s;
    }

    .navbar__nav li:hover {
      background: rgba(0, 0, 0, 0.7);
      color: white;
    }

    .wrapper {
      max-width: 1440px;
      margin: 0px auto 0px auto;
      padding: 80px 0px;
      text-align: center;
      color: white;
      position: relative;
    }

    .streams {
      display: inline-flex;
      flex-wrap: wrap;
      justify-content: center;
    }

    .stream {
      width: 360px;
      background: #333;
      color: white;
      text-align: left;
      cursor: pointer;
      transition: all 0.2s;
      opacity: 0.9;
      margin-left: 16px;
      margin-top: 16px;
    }

    .stream > img {
      width: 100%;
    }

    .stream__data {
      display: flex;
      align-items: center;
      padding: 6px;
    }

    .stream__avatar {
      width: 64px;
      height: 64px;
      border-radius: 50%;
      overflow: hidden;
      margin-right: 12px;
      min-width: 64px;
    }

    .stream__avatar > img {
      width: 100%;
      height: 100%;
    }

    .stream__intro {
      display: flex;
      flex-direction: column;
      justify-content: space-between;
      overflow: hidden;
    }

    .stream__title {
      font-size: 20px;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
      margin-bottom: 10px;
    }

    .stream:hover {
      transform: scale(1.07);
      filter: brightness(1.2);
      box-shadow: 5px 5px 20px 5px rgba(0, 0, 0, 0.5);
      opacity: 1;
    }

    .stream-empty {
      width: 360px;
      margin-left: 16px;
    }

    .bg {
      background: url(bg.jpg) no-repeat;
      background-size: 100% 100%;
      position: relative;

    }

    .bg:before {
      content: '';
      position: absolute;
      top: 0;
      bottom: 0;
      left: 0;
      right: 0;
      background: rgba(0, 0, 0, 0.3);
    }
  </style>
</head>

<body>
  <header class="navbar">
    <div class="navbar__site">Twitch Top Games</div>
    <ul class="navbar__nav">
    </ul>
  </header>
  <div class="bg">
    <div class="wrapper">
    <h1>League of Legends</h1>
    <h2>Top 20 popular live streams sorted by current viewers</h2>
    <section class="streams">

    </section>
  </div>
  <script>
    // <div class="stream-empty"></div>
    const request = new XMLHttpRequest();
    request.open('GET', 'https://api.twitch.tv/kraken/games/top?limit=5', true);
    request.setRequestHeader('Client-ID', 's44s145uexjgeu9mqqa1s93oc1bnli')
    request.setRequestHeader('Accept', 'application/vnd.twitchtv.v5+json')
    request.onload = function() {
      if (request.status >= 200 && request.status < 400) {
        const games = JSON.parse(this.response).top
        for(let game of games) {
          let element = document.createElement('li')
          element.innerText = game.game.name
          document.querySelector('.navbar__nav').appendChild(element)
        }

        // 顯示第一個遊戲的實況名稱
        document.querySelector('h1').innerText = games[0].game.name

        // 抓取第一個遊戲的實況內容
        const request2 = new XMLHttpRequest();
        request2.open('GET', 'https://api.twitch.tv/kraken/streams?game=' + encodeURIComponent(games[0].game.name), true);
        request2.setRequestHeader('Client-ID', 's44s145uexjgeu9mqqa1s93oc1bnli')
        request2.setRequestHeader('Accept', 'application/vnd.twitchtv.v5+json')
        request2.onload = function() {
          if (request2.status >= 200 && request2.status < 400) {
            const data = JSON.parse(request2.response).streams
            for(let stream of data) {
              let element = document.createElement('div');
              document.querySelector('.streams').appendChild(element);
              element.outerHTML = `<div class="stream">
                <img src="${stream.preview.large}" />
                <div class="stream__data">
                    <div class="stream__avatar">
                        <img src="${stream.channel.logo}">
                    </div>
                    <div class="stream__intro">
                        <div class="stream__title">${stream.channel.status}</div>
                        <div class="stream__channel">
                            ${stream.channel.name}
                        </div>
                    </div>
                </div>
              </div>`

            }
          }
        }
        request2.send()

      }
    }
    request.send();

    document.querySelector('.navbar__nav').addEventListener('click', e => {
      if(e.target.tagName.toLowerCase() === 'li') {
        const gameName = e.target.innerText;
        document.querySelector('h1').innerText = gameName
        document.querySelector('.streams').innerHTML = ''
        const request2 = new XMLHttpRequest();
        request2.open('GET', 'https://api.twitch.tv/kraken/streams?game=' + encodeURIComponent(gameName), true);
        request2.setRequestHeader('Client-ID', 's44s145uexjgeu9mqqa1s93oc1bnli')
        request2.setRequestHeader('Accept', 'application/vnd.twitchtv.v5+json')
        request2.onload = function() {
          if (request2.status >= 200 && request2.status < 400) {
            const data = JSON.parse(request2.response).streams
            for(let stream of data) {
              let element = document.createElement('div');
              document.querySelector('.streams').appendChild(element);
              element.outerHTML = `<div class="stream">
                <img src="${stream.preview.large}" />
                <div class="stream__data">
                    <div class="stream__avatar">
                        <img src="${stream.channel.logo}">
                    </div>
                    <div class="stream__intro">
                        <div class="stream__title">${stream.channel.status}</div>
                        <div class="stream__channel">
                            ${stream.channel.name}
                        </div>
                    </div>
                </div>
              </div>`

            }
          }
        }
        request2.send()
      }
    })
  </script>
</body>
</html>

有兩段關於抓取遊戲完全重複的程式碼,目標是做到共用 => 抽出來變成 function

送 request 拿參數名稱底下的遊戲,然後把它都放到畫面上。
現在代碼長相

    // <div class="stream-empty"></div>
    const request = new XMLHttpRequest();
    request.open('GET', 'https://api.twitch.tv/kraken/games/top?limit=5', true);
    request.setRequestHeader('Client-ID', 's44s145uexjgeu9mqqa1s93oc1bnli')
    request.setRequestHeader('Accept', 'application/vnd.twitchtv.v5+json')
    request.onload = function() {
      if (request.status >= 200 && request.status < 400) {
        const games = JSON.parse(this.response).top
        for(let game of games) {
          let element = document.createElement('li')
          element.innerText = game.game.name
          document.querySelector('.navbar__nav').appendChild(element)
        }

        // 顯示第一個遊戲的實況名稱
        document.querySelector('h1').innerText = games[0].game.name

        // 抓取第一個遊戲的實況內容
        getStreams(games[0].game.name)

      }
    }
    request.send();

    document.querySelector('.navbar__nav').addEventListener('click', e => {
      if(e.target.tagName.toLowerCase() === 'li') {
        const gameName = e.target.innerText;
        document.querySelector('h1').innerText = gameName
        document.querySelector('.streams').innerHTML = ''
        getStreams(gameName)

      }
    })
    function getStreams(gameName) {
        const request2 = new XMLHttpRequest();
        request2.open('GET', 'https://api.twitch.tv/kraken/streams?game=' + encodeURIComponent(gameName), true);
        request2.setRequestHeader('Client-ID', 's44s145uexjgeu9mqqa1s93oc1bnli')
        request2.setRequestHeader('Accept', 'application/vnd.twitchtv.v5+json')
        request2.onload = function() {
          if (request2.status >= 200 && request2.status < 400) {
            const data = JSON.parse(request2.response).streams
            for(let stream of data) {
              let element = document.createElement('div');
              document.querySelector('.streams').appendChild(element);
              element.outerHTML = `<div class="stream">
                <img src="${stream.preview.large}" />
                <div class="stream__data">
                    <div class="stream__avatar">
                        <img src="${stream.channel.logo}">
                    </div>
                    <div class="stream__intro">
                        <div class="stream__title">${stream.channel.status}</div>
                        <div class="stream__channel">
                            ${stream.channel.name}
                        </div>
                    </div>
                </div>
              </div>`

            }
          }
        }
        request2.send()
    }

假設有一天,twitchApi 網址換了,就要改動兩個地方,所以我們可以直接在最外層宣告一個 const 存取 twitchApi,好處是當我 API_URL 變動,我就只要改一個地方,同時看的人也會比較好了解,你串的是哪個 API_URL。同理,將 CLIENT_ID 進行相同改動。

NOTE : 命名方法,常數通常會是全大寫。

現在代碼長相

    const API_URL = 'https://api.twitch.tv/kraken'
    const CLIENT_ID = 's44s145uexjgeu9mqqa1s93oc1bnli'
    const request = new XMLHttpRequest();
    request.open('GET', `${API_URL}/games/top?limit=5`, true);
    request.setRequestHeader('Client-ID', CLIENT_ID)
    request.setRequestHeader('Accept', 'application/vnd.twitchtv.v5+json')
    request.onload = function() {
      if (request.status >= 200 && request.status < 400) {
        const games = JSON.parse(this.response).top
        for(let game of games) {
          let element = document.createElement('li')
          element.innerText = game.game.name
          document.querySelector('.navbar__nav').appendChild(element)
        }

        // 顯示第一個遊戲的實況名稱
        document.querySelector('h1').innerText = games[0].game.name

        // 抓取第一個遊戲的實況內容
        getStreams(games[0].game.name)

      }
    }
    request.send();

    document.querySelector('.navbar__nav').addEventListener('click', e => {
      if(e.target.tagName.toLowerCase() === 'li') {
        const gameName = e.target.innerText;
        document.querySelector('h1').innerText = gameName
        document.querySelector('.streams').innerHTML = ''
        getStreams(gameName)

      }
    })
    function getStreams(gameName) {
        const request2 = new XMLHttpRequest();
        request2.open('GET', `${API_URL}/streams?game=${encodeURIComponent(gameName)}`, true);
        request2.setRequestHeader('Client-ID', CLIENT_ID)
        request2.setRequestHeader('Accept', 'application/vnd.twitchtv.v5+json')
        request2.onload = function() {
          if (request2.status >= 200 && request2.status < 400) {
            const data = JSON.parse(request2.response).streams
            for(let stream of data) {
              let element = document.createElement('div');
              document.querySelector('.streams').appendChild(element);
              element.outerHTML = `<div class="stream">
                <img src="${stream.preview.large}" />
                <div class="stream__data">
                    <div class="stream__avatar">
                        <img src="${stream.channel.logo}">
                    </div>
                    <div class="stream__intro">
                        <div class="stream__title">${stream.channel.status}</div>
                        <div class="stream__channel">
                            ${stream.channel.name}
                        </div>
                    </div>
                </div>
              </div>`

            }
          }
        }
        request2.send()
    }

為了方便維護,用 FUNCTION 代替行為,採用函式填空法。

閱讀程式碼變得容易:
抓遊戲(看裡面在做甚麼) => 對每個遊戲加 eventListener => 換遊戲

    const API_URL = 'https://api.twitch.tv/kraken'
    const CLIENT_ID = 's44s145uexjgeu9mqqa1s93oc1bnli'
    getGames()

    document.querySelector('.navbar__nav').addEventListener('click', e => {
      if(e.target.tagName.toLowerCase() === 'li') {
        const gameName = e.target.innerText;
        document.querySelector('h1').innerText = gameName
        document.querySelector('.streams').innerHTML = ''
        getStreams(gameName)

      }
    })

    function getGames() {
      const request = new XMLHttpRequest();
      request.open('GET', `${API_URL}/games/top?limit=5`, true);
      request.setRequestHeader('Client-ID', CLIENT_ID)
      request.setRequestHeader('Accept', 'application/vnd.twitchtv.v5+json')
      request.onload = function() {
        if (request.status >= 200 && request.status < 400) {
          const games = JSON.parse(this.response).top
        for(let game of games) {
          let element = document.createElement('li')
          element.innerText = game.game.name
          document.querySelector('.navbar__nav').appendChild(element)
        }
        document.querySelector('h1').innerText = games[0].game.name

        // 抓取第一個遊戲的實況內容
        getStreams(games[0].game.name)
        }
      }
    request.send();
    }

    function getStreams(gameName) {
        const request2 = new XMLHttpRequest();
        request2.open('GET', `${API_URL}/streams?game=${encodeURIComponent(gameName)}`, true);
        request2.setRequestHeader('Client-ID', CLIENT_ID)
        request2.setRequestHeader('Accept', 'application/vnd.twitchtv.v5+json')
        request2.onload = function() {
          if (request2.status >= 200 && request2.status < 400) {
            const data = JSON.parse(request2.response).streams
            for(let stream of data) {
              let element = document.createElement('div');
              document.querySelector('.streams').appendChild(element);
              element.outerHTML = `<div class="stream">
                <img src="${stream.preview.large}" />
                <div class="stream__data">
                    <div class="stream__avatar">
                        <img src="${stream.channel.logo}">
                    </div>
                    <div class="stream__intro">
                        <div class="stream__title">${stream.channel.status}</div>
                        <div class="stream__channel">
                            ${stream.channel.name}
                        </div>
                    </div>
                </div>
              </div>`

            }
          }
        }
        request2.send()
    }

最理想方式,api 歸 api,資料歸資料。目標用 getGames() 得到的只有遊戲資料,好處是當同事要資料,我可以將資料的部分給它就好了。

但因為這個函式是非同步,所以我不可以這樣寫

    const games = getGames()
    for(let game of games) {
      let element = document.createElement('li')
      element.innerText = game.game.name
      document.querySelector('.navbar__nav').appendChild(element)
    }
    document.querySelector('h1').innerText = games[0].game.name
    getStreams(games[0].game.name)
    document.querySelector('.navbar__nav').addEventListener('click', e => {
      if(e.target.tagName.toLowerCase() === 'li') {
        const gameName = e.target.innerText;
        document.querySelector('h1').innerText = gameName
        document.querySelector('.streams').innerHTML = ''
        getStreams(gameName)

      }
    })

我只能用 CB FUNCTION 去呼叫它。
理想中,我可以用 getGames 拿到遊戲資料,games 就是我的資料。所以等下在實作 getGames 必須去呼叫裡面的回呼函式,然後把 games 帶入我才拿的到東西。

    getGames(function(games) {
      for(let game of games) {
      let element = document.createElement('li')
      element.innerText = game.game.name
      document.querySelector('.navbar__nav').appendChild(element)
      }
      document.querySelector('h1').innerText = games[0].game.name
      getStreams(games[0].game.name)
    })

    document.querySelector('.navbar__nav').addEventListener('click', e => {
      if(e.target.tagName.toLowerCase() === 'li') {
        const gameName = e.target.innerText;
        document.querySelector('h1').innerText = gameName
        document.querySelector('.streams').innerHTML = ''
        getStreams(gameName)

      }
    })

底下的 funct getGames(),帶入參數 callback,getGames 接受回呼函式,我們拿到 games 後,回傳。它就會執行我們傳進來的 function,把值帶進去。我們傳進的 function 就是後面這個 funct

getGames(function(games) {
      for(let game of games) {
      let element = document.createElement('li')
      element.innerText = game.game.name
      document.querySelector('.navbar__nav').appendChild(element)
      }
      document.querySelector('h1').innerText = games[0].game.name
      getStreams(games[0].game.name)
    })
function getGames(callback) {
      const request = new XMLHttpRequest();
      request.open('GET', `${API_URL}/games/top?limit=5`, true);
      request.setRequestHeader('Client-ID', CLIENT_ID)
      request.setRequestHeader('Accept', 'application/vnd.twitchtv.v5+json')
      request.onload = function() {
        if (request.status >= 200 && request.status < 400) {
          const games = JSON.parse(this.response).top
          callback(games)
        }
      }
    request.send();
    }
  1. call getGames()
  2. 它會執行到這邊並一路往下執行
  3. 到 onload
  4. 發 request 出去
  5. 直到 response 回來,呼叫 callback(games),callback 就會被執行
  6. 第一步的 fun 被執行,進入底下
    因為是 cb 所以要拿到資料才會回去

如果同事需要 api ,我就是將這段 copy 給它

    function getGames(callback) {
      const request = new XMLHttpRequest();
      request.open('GET', `${API_URL}/games/top?limit=5`, true);
      request.setRequestHeader('Client-ID', CLIENT_ID)
      request.setRequestHeader('Accept', 'application/vnd.twitchtv.v5+json')
      request.onload = function() {
        if (request.status >= 200 && request.status < 400) {
          const games = JSON.parse(this.response).top
          callback(games)
        }
      }
    request.send();
    }

所以朋友可以在這邊改成自己的邏輯

getGames(function(games) {
      for(let game of games) {
      let element = document.createElement('li')
      element.innerText = game.game.name
      document.querySelector('.navbar__nav').appendChild(element)
      }
      document.querySelector('h1').innerText = games[0].game.name
      getStreams(games[0].game.name)
    })

目前代碼長相:

   const API_URL = 'https://api.twitch.tv/kraken'
    const CLIENT_ID = 's44s145uexjgeu9mqqa1s93oc1bnli'

    getGames(function(games) {
      for(let game of games) {
      let element = document.createElement('li')
      element.innerText = game.game.name
      document.querySelector('.navbar__nav').appendChild(element)
      }
      document.querySelector('h1').innerText = games[0].game.name
      getStreams(games[0].game.name)
    })

    document.querySelector('.navbar__nav').addEventListener('click', e => {
      if(e.target.tagName.toLowerCase() === 'li') {
        const gameName = e.target.innerText;
        document.querySelector('h1').innerText = gameName
        document.querySelector('.streams').innerHTML = ''
        getStreams(gameName)
      }
    })

    function getGames(callback) {
      const request = new XMLHttpRequest();
      request.open('GET', `${API_URL}/games/top?limit=5`, true);
      request.setRequestHeader('Client-ID', CLIENT_ID)
      request.setRequestHeader('Accept', 'application/vnd.twitchtv.v5+json')
      request.onload = function() {
        if (request.status >= 200 && request.status < 400) {
          const games = JSON.parse(this.response).top
          callback(games)
        }
      }
    request.send();
    }

    function getStreams(gameName) {
        const request2 = new XMLHttpRequest();
        request2.open('GET', `${API_URL}/streams?game=${encodeURIComponent(gameName)}`, true);
        request2.setRequestHeader('Client-ID', CLIENT_ID)
        request2.setRequestHeader('Accept', 'application/vnd.twitchtv.v5+json')
        request2.onload = function() {
          if (request2.status >= 200 && request2.status < 400) {
            const data = JSON.parse(request2.response).streams
            for(let stream of data) {
              let element = document.createElement('div');
              document.querySelector('.streams').appendChild(element);
              element.outerHTML = `<div class="stream">
                <img src="${stream.preview.large}" />
                <div class="stream__data">
                    <div class="stream__avatar">
                        <img src="${stream.channel.logo}">
                    </div>
                    <div class="stream__intro">
                        <div class="stream__title">${stream.channel.status}</div>
                        <div class="stream__channel">
                            ${stream.channel.name}
                        </div>
                    </div>
                </div>
              </div>`

            }
          }
        }
        request2.send()
    }

現在,處理重複類型的代碼,也就是處理遊戲換遊戲的部分

getGames(function(games) {
      for(let game of games) {
      let element = document.createElement('li')
      element.innerText = game.game.name
      document.querySelector('.navbar__nav').appendChild(element)
      }
      changeGame(games[0].game.name)
    })

    document.querySelector('.navbar__nav').addEventListener('click', e => {
      if(e.target.tagName.toLowerCase() === 'li') {
        const gameName = e.target.innerText
        changeGame(gameName)
      }
    })

    function changeGame(gameName) {
      document.querySelector('h1').innerText = gameName
      document.querySelector('.streams').innerHTML = ''
      getStreams(gameName)
    }

調整 getStreams 將資料與 UI 分開。一樣,我是回呼函式拿到資料才做底下的事情。

  function changeGame(gameName) {
      document.querySelector('h1').innerText = gameName
      document.querySelector('.streams').innerHTML = ''
      getStreams(gameName, function(streams) {
        for(let stream of streams) {
              let element = document.createElement('div');
              document.querySelector('.streams').appendChild(element);
              element.outerHTML = `<div class="stream">
                <img src="${stream.preview.large}" />
                <div class="stream__data">
                    <div class="stream__avatar">
                        <img src="${stream.channel.logo}">
                    </div>
                    <div class="stream__intro">
                        <div class="stream__title">${stream.channel.status}</div>
                        <div class="stream__channel">
                            ${stream.channel.name}
                        </div>
                    </div>
                </div>
              </div>`  
        }
      })
    }
  1. 執行 getStreams 帶兩個參數進去
  2. 跑到這行
  3. 發 request
  4. 等待收到 response
  5. request 回來,判斷成功拿到資料,呼叫 callback data,
  6. 這個 callback data 就是我們傳進去的這個 fun
  7. 帶好 streams 的參數繼續往下執行

目前代碼

    const API_URL = 'https://api.twitch.tv/kraken'
    const CLIENT_ID = 's44s145uexjgeu9mqqa1s93oc1bnli'

    getGames(function(games) {
      for(let game of games) {
      let element = document.createElement('li')
      element.innerText = game.game.name
      document.querySelector('.navbar__nav').appendChild(element)
      }
      changeGame(games[0].game.name)
    })

    document.querySelector('.navbar__nav').addEventListener('click', e => {
      if(e.target.tagName.toLowerCase() === 'li') {
        const gameName = e.target.innerText
        changeGame(gameName)
      }
    })

    function changeGame(gameName) {
      document.querySelector('h1').innerText = gameName
      document.querySelector('.streams').innerHTML = ''
      getStreams(gameName, function(streams) {
        for(let stream of streams) {
              let element = document.createElement('div');
              document.querySelector('.streams').appendChild(element);
              element.outerHTML = `<div class="stream">
                <img src="${stream.preview.large}" />
                <div class="stream__data">
                    <div class="stream__avatar">
                        <img src="${stream.channel.logo}">
                    </div>
                    <div class="stream__intro">
                        <div class="stream__title">${stream.channel.status}</div>
                        <div class="stream__channel">
                            ${stream.channel.name}
                        </div>
                    </div>
                </div>
              </div>`  
        }
      })
    }

    function getStreams(gameName, callback) {
        const request2 = new XMLHttpRequest();
        request2.open('GET', `${API_URL}/streams?game=${encodeURIComponent(gameName)}`, true);
        request2.setRequestHeader('Client-ID', CLIENT_ID)
        request2.setRequestHeader('Accept', 'application/vnd.twitchtv.v5+json')
        request2.onload = function() {
          if (request2.status >= 200 && request2.status < 400) {
            const data = JSON.parse(request2.response).streams
            callback(data)
          }
        }
        request2.send()
    }

    function getGames(callback) {
      const request = new XMLHttpRequest();
      request.open('GET', `${API_URL}/games/top?limit=5`, true);
      request.setRequestHeader('Client-ID', CLIENT_ID)
      request.setRequestHeader('Accept', 'application/vnd.twitchtv.v5+json')
      request.onload = function() {
        if (request.status >= 200 && request.status < 400) {
          const games = JSON.parse(this.response).top
          callback(games)
        }
      }
    request.send();
    }

outerHTML 太長了,等東西變更大會更難維護。
用const 存取,並將原本的 ${} 用特殊符號代替,目的是方便識別,因為後面要做字串取代。

const STREAM_TEMPLATE = `<div class="stream">
                <img src="$preview" />
                <div class="stream__data">
                    <div class="stream__avatar">
                        <img src="$logo">
                    </div>
                    <div class="stream__intro">
                        <div class="stream__title">$title</div>
                        <div class="stream__channel">
                            $name
                        </div>
                    </div>
                </div>
              </div>`
for(let stream of streams) {
              let element = document.createElement('div');
              document.querySelector('.streams').appendChild(element);
              element.outerHTML = STREAM_TEMPLATE
              .replace('$preview', stream.preview.large)
              .replace('$logo', stream.channel.logo)
              .replace('$title', stream.channel.status)
              .replace('$name', stream.channel.name) 
        }

現在,STREAM_TEMPLATE 就是每個 stream 的長相,所以只要 html 切來有變,我改這邊就可以了

接下來是 getGames 如果要把 api 給別人串,我將 getGames 與 getStreams 給它,然後把一些參數跟他講。它就可以發 req 拿資料。

所以拿到資料後的處理,就不會被我的 ui 侷限住。

funct 名稱取的好,不用點開就可以知道裡面在做甚麼

改完後的版本

  <!DOCTYPE html>

<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Twitch Live Games</title>
  <meta name="description" content="Week8 作業">
  <link rel="stylesheet" href="https://necolas.github.io/normalize.css/8.0.1/normalize.css">
  <link rel="stylesheet" href="style.css">
</head>

<body>
  <header class="navbar">
    <div class="navbar__site">Twitch Top Games</div>
    <ul class="navbar__nav">
    </ul>
  </header>
  <div class="bg">
    <div class="wrapper">
    <h1>Loading...</h1>
    <h2>Top 20 popular live streams sorted by current viewers</h2>
    <section class="streams">

    </section>
  </div>
  <script>
    const API_URL = 'https://api.twitch.tv/kraken'
    const CLIENT_ID = 's44s145uexjgeu9mqqa1s93oc1bnli'
    const STREAM_TEMPLATE = `<div class="stream">
                <img src="$preview" />
                <div class="stream__data">
                    <div class="stream__avatar">
                        <img src="$logo">
                    </div>
                    <div class="stream__intro">
                        <div class="stream__title">$title</div>
                        <div class="stream__channel">
                            $name
                        </div>
                    </div>
                </div>
              </div>` 

    getGames(function(games) {
      for(let game of games) {
      let element = document.createElement('li')
      element.innerText = game.game.name
      document.querySelector('.navbar__nav').appendChild(element)
      }
      changeGame(games[0].game.name)
    })

    document.querySelector('.navbar__nav').addEventListener('click', e => {
      if(e.target.tagName.toLowerCase() === 'li') {
        const gameName = e.target.innerText
        changeGame(gameName)
      }
    })

    function changeGame(gameName) {
      document.querySelector('h1').innerText = gameName
      document.querySelector('.streams').innerHTML = ''
      getStreams(gameName, function(streams) {
        for(let stream of streams) {
          appendStream(stream)

        }
      })
    }

    function appendStream(stream) {
      let element = document.createElement('div');
              document.querySelector('.streams').appendChild(element);
              element.outerHTML = STREAM_TEMPLATE
              .replace('$preview', stream.preview.large)
              .replace('$logo', stream.channel.logo)
              .replace('$title', stream.channel.status)
              .replace('$name', stream.channel.name) 
    }

    function getStreams(gameName, callback) {
        const request2 = new XMLHttpRequest();
        request2.open('GET', `${API_URL}/streams?game=${encodeURIComponent(gameName)}`, true);
        request2.setRequestHeader('Client-ID', CLIENT_ID)
        request2.setRequestHeader('Accept', 'application/vnd.twitchtv.v5+json')
        request2.onload = function() {
          if (request2.status >= 200 && request2.status < 400) {
            const data = JSON.parse(request2.response).streams
            callback(data)
          }
        }
        request2.send()
    }

    function getGames(callback) {
      const request = new XMLHttpRequest();
      request.open('GET', `${API_URL}/games/top?limit=5`, true);
      request.setRequestHeader('Client-ID', CLIENT_ID)
      request.setRequestHeader('Accept', 'application/vnd.twitchtv.v5+json')
      request.onload = function() {
        if (request.status >= 200 && request.status < 400) {
          const games = JSON.parse(this.response).top
          callback(games)
        }
      }
    request.send();
    }


  </script>
</body>
</html>

#作業檢討







Related Posts

[06] JavaScript 入門 - 拉升、嚴格模式

[06] JavaScript 入門 - 拉升、嚴格模式

自動化測試 x Puppeteer - 玩偶QA參一咖 Day01

自動化測試 x Puppeteer - 玩偶QA參一咖 Day01

[筆記]Netlist 01 -Introduction & Framework

[筆記]Netlist 01 -Introduction & Framework


Comments