知識點 | 使用說明 |
---|---|
linear-gradient | 設定線性的漸層背景 |
flexbox | 在此用於製作卡片的排版且有RWD效果 |
知識點 | 使用說明 |
---|---|
async / await | 簡化promise以及對多個 Promise 物件執行某些操作 |
fetch() | 使用 fetch 發送請求 ( request ) |
Object.keys() | 回傳一個包含物件中所有可列舉之屬性的陣列 |
find() | 回傳第一個滿足所提供之測試函式的元素值,否則回傳 undefined |
map() | 遍歷陣列中的元素 |
slice() | 為原陣列選擇之 begin 至 end(不含 end)部分的淺拷貝(shallow copy) |
padStart() | 將編號的前面自動補0 |
indexOf() | 回傳給定元素於陣列中第一個被找到之索引,若不存在則回傳 -1 |
<h1>Pokedex</h1>
<div class="container" id="container">
<!-- 1 -->
<div class="pokemon" style="background-color: red;">
<div class="img-container">
<img src="..." alt="...">
</div>
<div class="info">
<span class="number">#001</span>
<span class="name">皮卡丘</span>
<small class="type"> <span>電</span> </small>
</div>
</div>
<!-- 2 -->
<div class="pokemon" style="background-color: red;">
<div class="img-container">
<img src="..." alt="...">
</div>
<div class="info">
<span class="number">#002</span>
<span class="name">妙蛙草</span>
<small class="type"> <span>草</span> </small>
</div>
</div>
<!-- 3 -->
<div class="pokemon" style="background-color: red;">
<div class="img-container">
<img src="..." alt="...">
</div>
<div class="info">
<span class="number">#003</span>
<span class="name">傑尼龜</span>
<small class="type"> <span>水</span> </small>
</div>
</div>
</div>
* {
box-sizing: border-box;
}
body {
background: #efefbb;
background: linear-gradient(to right, #d4d3dd, #efefbb);
margin: 0;
padding: 0;
display: flex; /*讓內容在viewport的中間*/
flex-direction: column;
justify-content: center;
align-items: center;
}
h1 {
letter-spacing: 3px;
}
設定好後呈現如下
接下來要把圖片變成卡片的排版,從縱向變成橫向,呈現大概會如下圖這樣
卡片內部
.pokemon {
background-color: #eee;
border-radius: 10px;
box-shadow: 0 3px 15px rgba(100, 100, 100, 0.5);
margin: 10px;
padding: 20px;
text-align: center;
}
.pokemon .img-container {
background-color: rgba(255, 255, 255, 0.6);
border-radius: 50%;
width: 120px;
height: 120px;
margin: 5px auto;
text-align: center;
}
.pokemon .img-container img {
max-width: 90%;
margin-top: 20px;
}
.pokemon .info .number {
background-color: rgba(0, 0, 0, 0.1);
border-radius: 10px;
padding: 5px 10px;
font-size: 14px;
}
.pokemon .info .name {
margin: 15px 0 7px;
letter-spacing: 1px;
}
樣式的部分大致上是完成了,要來處理今天的核心
變數宣告
const container = document.getElementById("container");
const pokemon_count = 150; //要抓的寶可夢的總數
const colors = {
fire: "#FDDFDF",
grass: "#DEFDE0",
electric: "#FCF7DE",
water: "#DEF3FD",
ground: "#f4e7da",
rock: "#d5d5d4",
fairy: "#fceaff",
poison: "#98d7a5",
bug: "#f8d5a3",
dragon: "#97b3e6",
psychic: "#eaeda1",
flying: "#F5F5F5",
fighting: "#E6E0D4",
normal: "#F5F5F5",
會設定那麼多顏色,是之後要去為不同寶可夢的類型去做分類,同個類型就同種顏色
API
接下來要從外部的API(點此)取得POKEMON的資料和圖片
可以透過ID、類型、能力、種類來客製化我們的API,在這邊我們選用ID的方式來設計
const fetchPokemons = async () => {
for (let i = 1; i <= pokemon_count; i++) {
await getPokemon(i); //這裡i代表id
}
};
const getPokemon = async (id) => {
const url = `https://pokeapi.co/api/v2/pokemon/${id}`;
const res = await fetch(url);
const data = await res.json();
createPokemonCard(data);
console.log(data); //請看下圖
};
fetch()
是一個全域的方法,需要傳入一個參數,也就是資料的 URL,會回傳一個包含 response 的 promise,這裡我們用async await的讓語法更簡潔易讀
接著把data印出來,就是一堆密密麻麻的資料啦~okok代表我們成功獲取到資料了
接下來我們要回到HTML把部分預先寫好的程式碼先註解掉,因為要直接用JS來操控,HTML只需留下以下這部分即可
<h1>Pokedex</h1>
<div class="poke-container" id="poke-container"></div>
建立pokemon元素
const createPokemonCard = (pokemon) => {
const pokemonEl = document.createElement("div"); //建立元素
pokemonEl.classList.add("pokemon");
const pokemonInnerHTML = `
<div class="img-container">
<img src="省略不寫" alt="pikachu">
</div>
<div class="info">
<span class="number">#001</span>
<span class="name">Pikachu</span>
<small class="type"> <span>electric</span> </small>
</div>
`;
pokemonEl.innerHTML = pokemonInnerHTML;
container.appendChild(pokemonEl);
};
把img-container的內容放到樣板字串中,設定好呈現如下,非常多隻皮卡丘,每張圖都一樣,原因是我在省略的圖片網址中先寫死的,接著要把它成動態呈現,依照不同id代表不同圖片來完成
動態呈現(編號、名稱、圖片、類型、顏色)
const mainType = Object.keys(colors);
const createPokemonCard = (pokemon) => {
const pokemonEl = document.createElement("div");
pokemonEl.classList.add("pokemon");
//編號
const id = pokemon.id.toString().padStart(3, "0"); //補0在每個編號前面,共3位數
//名稱
const name = pokemon.name[0].toUpperCase() + pokemon.name.slice(1); //第一個字母大寫,其餘都小寫
//類型
const pokemonType = pokemon.types.map((type) => type.type.name);
const type = mainType.find((type) => pokemonType.indexOf(type) != -1); //不等於-1代表有找到值
//顏色
const color = colors[type];
pokemonEl.style.backgroundColor = color;
// 圖片
const pokemonInnerHTML = `
<div class="img-container">
<img src="https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/${pokemon.id}.png" alt="${name}">
</div>
<div class="info">
<span class="number">#${id}</span>
<span class="name">${name}</span>
<small class="type"> <span>${type}</span> </small>
</div>
`;
pokemonEl.innerHTML = pokemonInnerHTML;
container.appendChild(pokemonEl);
};
fetchPokemons();
設定好呈現如下
以上是這次的project,若有解說不夠詳盡或是錯誤歡迎指教,感激不盡!
附上codepen連結 https://codepen.io/hangineer/pen/zYjJqyE
50 Projects In 50 Days - HTML, CSS & JavaScript
寶可夢官網
本篇用到很多陣列處理方法,像是find()
、 slice()
、 map()
、 indexOf()
,還有ferch API ,還會連貫到 promise、async await 的概念,有很多重點中的重點,剛好藉由這個賽project而有再次練習的機會,覺得挺好的~
今天也是最後一篇文了,很開心自己做到了對自己的承諾ヽ(✿゚▽゚)ノ,這30天各種酸甜苦辣,簡單一點的project可以3個小時內完成並打完文章,複雜一點的甚至3-5個小時都有,加上沒有庫存文章(下次參賽要記得庫存!!),所以常常在有時間壓力下趕緊把文章發布出去,過程中最困難的無非就是自律以及把project梳理成文字來呈現其脈絡,參加鐵人賽剛好是一個很好的自我訓練,也謝謝IT邦幫忙提供了這個機會,鐵人賽我們後會有期