发布于 2026-01-06 9 阅读
0

使用原生 JavaScript 构建宝可梦图鉴

使用原生 JavaScript 构建宝可梦图鉴

像 React 这样的前端框架备受关注,但你并非总是需要它。在本文中,我将结合我对 JavaScript 和宝可梦的热爱。我们将使用原生 HTML、CSS 和 JavaScript 构建一个包含最初 150 种宝可梦的图鉴。

请访问Codepen查看源代码!

搭建项目脚手架

这个项目不会包含很多文件,只有index.htmlapp.cssapp.js这三个文件。也就是说,要开始的话,请在你的电脑上创建一个文件夹,然后用你喜欢的编辑器打开它。我用的是VS Code

打开文件夹后,您需要创建上面提到的三个文件。

  • index.html
  • app.css
  • app.js

试试 VS Code 扩展程序Web Boilerplate,它可以为你生成这三个文件。

文件创建完成后,现在需要将 CSS 和 JavaScript 文件链接到 index.html 文件中。您的 HTML 代码将如下所示。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Quick's Pokedex</title>
    <link rel="stylesheet" href="app.css" />
  </head>
  <body>
    <script src="app.js"></script>
  </body>
</html>

完成样板代码后,我们就可以开始向页面添加内容了。首先,在 body 标签内添加一个class 为container的div 元素。我们将把所有内容都放在这里。

在容器 div 内部,添加一个h1元素,并填写你的应用名称。我的应用名称是“Quick's Pokedex”。最后,添加一个id 为pokedex的ol元素我们将在这个有序列表中显示所有宝可梦的信息。

你的HTML文件应该如下所示。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Quick's Pokedex</title>
    <link rel="stylesheet" href="app.css" />
    <link
      href="https://fonts.googleapis.com/css?family=Rubik&display=swap"
      rel="stylesheet"
    />
  </head>
  <body>
    <div class="container">
      <h1>Quick's Pokedex</h1>
      <ol id="pokedex"></ol>
    </div>
    <script src="app.js"></script>
  </body>
</html>

使用 PokeAPI 获取宝可梦数据

信不信由你,这就是我们要添加到 HTML 页面中的所有内容。接下来,我们转到 JavaScript,从PokeAPI加载宝可梦数据。为此,我们将使用JavaScript 的 Fetch 函数向 API 发送 HTTP 请求。

如需复习 Fetch API,请查看JavaScript Fetch API - 入门指南!

我们先来看看API是如何工作的。要获取特定宝可梦的信息,你需要发出请求并传入该宝可梦的ID。例如,如果你想获取妙蛙种子(编号1)的信息,你需要在请求末尾加上1,就像这样。

https://pokeapi.co/api/v2/pokemon/1

这种方法虽然可行,但我们需要获取150只宝可梦的信息,而不仅仅是一只。为此,我们可以遍历1到150的数字,并为每个数字发起API请求。以下是代码片段示例。

for (let i = 1; i <= 150; i++) {
  const url = `https://pokeapi.co/api/v2/pokemon/${i}`;
  fetch(url)
    .then(res => res.json())
    .then(pokemon => {
      console.log(pokemon);
    });
}

这里有几个地方需要注意。我们使用了 ES6 模板字符串字面量,将索引i的值附加到每个请求的末尾。此外,我们还需要调用`res.json()`将初始的 Fetch 响应转换为 JavaScript 对象。我们使用了“Promise 链”来实现这一点。

想要复习一下 JavaScript Promise 的相关知识,请查看JavaScript Promise - 入门指南。

最后,我们终于可以访问存储宝可梦数据的宝可梦变量了。但这里存在一个很大的问题。这种发起大量 API 请求的方式效率非常低。因为 API 调用位于一个 for 循环中,所以我们必须等待上一次调用完成后才能进行下一次。

通常情况下,你不应该在 For 循环中进行异步调用。

我们可以使用Promise.all()来更新它。Promise.all() 允许我们并行执行异步 API 调用,而不是顺序执行。这意味着发出 150 个请求所需的时间与发出 1 个请求所需的时间大致相同!这是一个巨大的改进!

以下是这段代码的样子。

const promises = [];
for (let i = 1; i <= 150; i++) {
  const url = `https://pokeapi.co/api/v2/pokemon/${i}`;
  promises.push(fetch(url).then(res => res.json()));
}

Promise.all(promises).then(results => {
  console.log(results);
});

这看起来可能有点复杂,所以我们来分解步骤。

  1. 创建一个空数组来保存 Promise。
  2. 迭代 1-150
  3. 发出 API 请求,该请求会返回一个 Promise。
  4. 将该承诺添加到承诺数组中。
  5. 使用 Promise.all() 等待所有请求(并行)完成
  6. 使用结果变量获取一系列宝可梦信息。

转换宝可梦数据

宝可梦数据加载完毕后,我们需要将其转换为我们需要的格式。例如,每个返回的宝可梦对象都包含大量不必要的数据,而我们只关心其中几个属性。

  • 姓名
  • ID
  • 类型
  • 图像

一般来说,我们希望将请求中的数据数组转换为仅包含上述信息的宝可梦数据数组。我们可以使用`Array.map()`函数来完成这种转换。

任何时候你想转换数组中的每个元素,都要考虑使用Array.map()

const pokemon = results.map(data => ({
  name: data.name,
  id: data.id,
  image: data.sprites["front_default"],
  type: data.types.map(type => type.type.name).join(", "),
}));

如您所见,我们几乎毫不费力地就获取了所需的大部分数据。然而,类型数据却并非如此简单。传入的宝可梦数据以数组形式表示类型,但我们想要的是以逗号分隔的字符串。为了实现这种转换,我们可以结合使用map()数组函数和join()字符串函数

type: data.types.map(type => type.type.name).join(", ");

显示宝可梦数据

现在我们已经转换好了宝可梦数据,是时候把它显示在屏幕上了。这可能看起来有点奇怪,但我们将使用 JavaScript 生成一个 HTML 字符串来实现这一点。这个字符串代表要放入`<ol>`元素中的 HTML 内容。以下是我们将要遵循的步骤。

  1. 创建一个名为 displayPokemon 的函数
  2. 从 fetchPokemon 函数调用此函数,并将宝可梦数据作为参数传递。
  3. 使用 Arraymap ()将每个宝可梦对象转换为li元素字符串。
  4. 使用 String join()函数连接所有元素字符串。
  5. 在 JavaScript 中获取ol元素的引用
  6. 将ol元素的innerHTML设置为生成的字符串

首先创建一个名为 displayPokemon 的函数,该函数接受一个名为pokemon 的参数。

const displayPokemon = pokemon => {};

在 fetchPokemon 函数内部调用新函数。确保将宝可梦变量作为参数传递。

Promise.all(promises).then(results => {
  const pokemon = results.map(data => ({
    name: data.name,
    id: data.id,
    image: data.sprites["front_default"],
    type: data.types.map(type => type.type.name).join(", "),
  }));
  displayPokemon(pokemon);
});

现在,我们将使用`map()``join()`函数生成 HTML 字符串。由于我们使用的是ES6 模板字面量字符串,因此可以实现一些实用功能。例如,我们可以让字符串跨越多行并保持正确的格式。我们还可以使用字符串插值将变量注入到字符串中。最后,请注意我们正在为创建的元素应用类。我们将在下一节中使用这些类来添加样式。

const pokemonHTMLString = pokemon
  .map(
    pokeman =>
      `
    <li class="card">
        <img class="card-image" src="${pokeman.image}"/>
        <h2 class="card-title">${pokeman.id}. ${pokeman.name}</h2>
        <p class="card-subtitle">Type: ${pokeman.type}</p>
    </li>
    `
  )
  .join("");

在文件顶部,您需要使用 JavaScript 获取对id 为pokedex的ol元素的引用。

const pokedex = document.getElementById("pokedex");

现在,将ol元素的 innerHTML 设置为我们生成的 HTML 字符串。

pokedex.innerHTML = pokemonHTMLString;

以下是整个函数的代码。

const displayPokemon = pokemon => {
  console.log(pokemon);
  const pokemonHTMLString = pokemon
    .map(
      pokeman =>
        `
    <li class="card">
        <img class="card-image" src="${pokeman.image}"/>
        <h2 class="card-title">${pokeman.id}. ${pokeman.name}</h2>
        <p class="card-subtitle">Type: ${pokeman.type}</p>
    </li>
    `
    )
    .join("");
  pokedex.innerHTML = pokemonHTMLString;
};

风格宝可梦卡牌

现在所有宝可梦数据都显示出来了,但是看起来不太美观!让我们进入CSS代码部分,开始添加一些样式吧。

我们先来给正文添加一些基本样式,主要是字体和背景颜色。

body {
  background-color: orangered;
  margin: 0;
  font-family: rubik;
  color: white;
}

字体方面,我使用的是名为Rubik的 Google 字体。如果您也想使用它,需要在 HTML 文件的 head 部分添加以下代码。

<link
  href="https://fonts.googleapis.com/css?family=Rubik&display=swap"
  rel="stylesheet"
/>

接下来,我们可以给内容容器添加一些样式。这样可以让内容显得更简洁美观。

.container {
  padding: 40px;
  margin: 0 auto;
}

我们还会给应用程序的标题添加一些样式。

h1 {
  text-transform: uppercase;
  text-align: center;
  font-size: 54px;
}

然后,我们添加宝可梦图鉴“卡片”的基本样式。

.card {
  list-style: none;
  padding: 40px;
  background-color: #f4f4f4;
  color: #222;
  text-align: center;
}

.card-title {
  text-transform: uppercase;
  font-size: 32px;
  font-weight: normal;
  margin-bottom: 0;
}

.card-subtitle {
  font-weight: lighter;
  color: #666;
  margin-top: 5px;
}

.card-image {
  height: 180px;
}

这些效果看起来好多了,但我们希望能够让网格系统自动适应屏幕尺寸。为此,我们将使用CSS Grid。这里我们就不详细讲解 CSS Grid 了。如果您需要更多相关资料,我推荐以下两个资源。

  1. Wes Bos 的CSS Grid
  2. Bryan Robinson 的《实用 CSS Grid》

通常情况下,我们希望卡片水平显示,每张卡片的最小宽度为 320 像素。如果卡片宽度超过屏幕显示范围,则卡片应换行显示。我们可以使用以下样式来实现这一点。

#pokedex {
  padding-inline-start: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  grid-gap: 20px;
}

鼠标悬停时使宝可梦卡牌动起来

本教程的最后一步是为用户鼠标悬停在宝可梦上时添加动画效果。这样,当用户滚动浏览时,就能增添一些有趣的互动元素。

让我们给鼠标悬停在卡片上添加动画效果。

.card:hover {
  animation: bounce 0.5s linear;
}

现在,我们需要创建动画。这将是一个简单的弹跳效果。这个动画会让卡片上下弹跳两次。

@keyframes bounce {
  20% {
    transform: translateY(-6px);
  }
  40% {
    transform: translateY(0px);
  }
  60% {
    transform: translateY(-2px);
  }
  80% {
    transform: translateY(-0px);
  }
}

包起来

就这样。你应该已经拥有一个功能齐全的宝可梦图鉴了,它是用原生 HTML、CSS 和 JavaScript 创建的。瞧,你并不总是需要框架才能创造出有趣的东西!

文章来源:https://dev.to/jamesqquick/build-a-pokedex-with-vanilla-javascript-358m