JavaScript:添加交互性

JavaScript 是一种为网站添加交互性的编程语言。你可以用它来控制几乎所有内容——表单数据验证、按钮功能、游戏逻辑、动态样式、动画更新等等。本文将带你入门 JavaScript,并引导你为你的第一个网站添加一些有趣的功能。

预备知识 对你的计算机操作系统、用于构建网站的基本软件和文件系统有基本了解。
学习成果
  • JavaScript 的目的和功能。
  • 对 JavaScript 语言基础知识的基本理解,例如变量、运算符、条件语句、函数和事件。

什么是 JavaScript?

JavaScript 是一种功能齐全的编程语言——它包含你可能在其他编程语言中见过(或至少听说过)的所有经典编程功能,例如变量循环函数

JavaScript 在网页上使用时(尽管它也可以在其他地方使用),通常通过以下方式工作:

  • 获取对一个或多个值(例如数字或页面上的元素)的引用。
  • 对这些值进行操作,例如将数字相加。
  • 返回一个结果,该结果可以用于后续的其他操作。例如,你可能希望在页面上显示这些数字的总和。

我们来看一个例子。我们将使用我们在前几篇文章中看到的相同的基本列表

html
<p>Instructions for life:</p>

<ul>
  <li>Eat</li>
  <li>Sleep</li>
  <li>Repeat</li>
</ul>

我们还将定义一个名为 .done 的 CSS 类,它将样式化任何应用它的元素,使其看起来像一个已完成的任务,带有绿色文本颜色和删除线。我们将在下一步中使用 JavaScript 将其应用于我们的 <li> 元素。

css
.done {
  color: darkseagreen;
  text-decoration: line-through solid black 2px;
}

现在是 JavaScript 部分。在这里,我们首先将对 <li> 元素的引用存储在一个名为 listItems 的变量中。然后我们定义一个名为 toggleDone() 的函数,如果列表项没有 done 类,则添加该类;如果它有该类,则删除该类。最后,我们遍历列表项(使用 forEach())并为每个列表项添加一个事件监听器(使用 addEventListener()),这样当它被点击时,done 类就会被切换,从而应用我们之前定义的 CSS。

js
const listItems = document.querySelectorAll("li");

function toggleDone(e) {
  if (!e.target.className) {
    e.target.className = "done";
  } else {
    e.target.className = "";
  }
}

listItems.forEach((item) => {
  item.addEventListener("click", toggleDone);
});

如果你现在不理解上面的 JavaScript,请不要担心。熟悉 JavaScript 比熟悉 HTML 和 CSS 更具挑战性,但稍后在本课程中,事情会变得更清晰。

此示例将在网络浏览器中呈现如下:

尝试点击列表项几次,并注意“完成”样式是如何因此而切换开和关的。对于 11 行 JavaScript 来说,这还不错。

“Hello world!” 演练

为了让你开始编写 JavaScript,我们将引导你为你的示例网站添加一个 Hello world! 示例。(Hello world! 是标准的入门编程示例。)

警告:如果你没有按照我们课程的其余部分进行操作,请下载此示例代码并将其用作起点。

  1. 在你的 first-website 文件夹或你刚刚下载的示例文件夹中,创建一个名为 scripts 的新文件夹。

  2. scripts 文件夹中,创建一个名为 main.js 的新文本文档,并保存它。

  3. 转到你的 index.html 文件,并在紧靠关闭 </head> 标签之前的新行中输入以下代码:

    html
    <script async src="scripts/main.js"></script>
    

    这与 CSS 的 <link> 元素作用相同——它将 JavaScript 应用到页面,以便它可以影响 HTML(以及页面上的 CSS 和其他任何内容)。

  4. 将此代码添加到你的 scripts/main.js 文件中:

    js
    // Store a reference to the <h1> in a variable
    const myHeading = document.querySelector("h1");
    // Update the text content of the <h1>
    myHeading.textContent = "Hello world!";
    
  5. 确保 HTML 和 JavaScript 文件已保存,然后在浏览器中加载 index.html。你应该会看到类似以下内容:

Heading "hello world" above a firefox logo

让我们分解一下这个例子是如何工作的。

我们使用 JavaScript 将标题文本更改为 Hello world!。我们获取了标题的引用并将其存储在一个名为 myHeading 的变量中(一个存储值的容器)。这类似于你将 CSS 应用于元素的方式——你首先使用 CSS 选择器选择要影响的元素,然后定义这些元素所需的样式。在这两种情况下,当你想对元素执行某些操作时,你都需要先选择它。

之后,我们将 myHeading 变量的 textContent 属性(代表 <h1> 元素的文本内容)的值设置为 Hello world!

// 开头的行是 JavaScript 注释。与 HTML 和 CSS 注释一样,浏览器会忽略这些注释,为你提供一种添加关于代码的注释的方法,以帮助解释其工作原理。

我们继续为示例网站添加一些新功能。

警告:在继续之前,请从 main.js 文件中删除“Hello world!”代码。如果你不这样做,现有代码将与你即将添加的新代码冲突。

添加一个图像切换器

在本节中,你将使用 JavaScript 和 DOM API 功能在两张图片之间交替显示。当用户点击显示的图片时,将发生此更改。

  1. 选择另一张图片作为你示例网站的特色图片。理想情况下,该图片应与你之前添加的图片大小相同,或尽可能接近。

  2. 将此图片保存到你的 images 文件夹中。

  3. 将以下 JavaScript 代码添加到你的 main.js 文件中,确保将 firefox2.png 和两个 firefox-icon.png 实例分别替换为你的第二张和第一张图片名称。

    js
    const myImage = document.querySelector("img");
    
    myImage.addEventListener("click", () => {
      const mySrc = myImage.getAttribute("src");
      if (mySrc === "images/firefox-icon.png") {
        myImage.setAttribute("src", "images/firefox2.png");
      } else {
        myImage.setAttribute("src", "images/firefox-icon.png");
      }
    });
    
  4. 保存所有文件并在浏览器中加载 index.html。现在当你点击图片时,它应该会切换到另一张图片。

在此代码中,你将对 <img> 元素的引用存储在 myImage 变量中。然后你为其分配了一个 click 事件处理函数。每次点击 <img> 时,该函数都会执行以下操作:

  • 检索图像的 src 属性的值。
  • 使用条件语句(if...else 结构)检查 src 值是否等于原始图像的路径
    • 如果是,代码会将 src 值更改为第二张图像的路径,强制将另一张图像加载到 <img> 元素中。
    • 如果不是(这意味着图像已经更改),src 值将换回到原始图像路径。

注意:本节介绍了一些重要术语。关键概念包括:

  • API:一组允许开发人员与编程环境交互的功能。Web API(例如我们上面使用的 DOM API 功能)构建在 JavaScript 语言之上,允许你操纵浏览器的各个部分及其显示的网页。
  • 事件:浏览器中发生的事情。它们是使网站具有交互性的关键。你可以使用事件处理函数响应事件运行代码——这些是事件发生时运行的代码块。最常见的例子是点击事件,当用户点击某个东西时,浏览器会触发该事件。
  • 函数:一种打包你希望重用代码的方式。你可以在函数中定义一次代码,然后根据需要多次运行它,这有助于你避免一遍又一遍地编写相同的代码。在本例中,我们定义了一个 click 事件处理函数,该函数在用户每次点击图像时运行。
  • 条件语句:用于测试表达式是返回 true 还是 false 并根据每个结果运行不同代码的代码结构。条件语句的一种非常常见的形式是 if...else 语句。

添加一个个性化欢迎消息

接下来,让我们更改页面标题,以便在用户首次访问网站时显示个性化的欢迎消息。此欢迎消息将使用 Web Storage API 保存到浏览器中,因此如果用户离开网站稍后返回,他们的个性化数据仍将存在。我们还将提供一种让用户更改消息的方式。

  1. index.html 中,在关闭 </body> 标签之前添加以下行:

    html
    <button>Change user</button>
    
  2. main.js 中,将以下代码放在文件的底部,完全按照原样写入。这会创建对新按钮和标题的引用,将每个引用存储在变量中:

    js
    let myButton = document.querySelector("button");
    let myHeading = document.querySelector("h1");
    
  3. 添加以下函数来设置个性化问候语。这目前不会做任何事情;我们稍后会调用该函数。

    js
    function setUserName() {
      const myName = prompt("Please enter your name.");
      localStorage.setItem("name", myName);
      myHeading.textContent = `Mozilla is cool, ${myName}`;
    }
    

    setUserName() 函数包含一个 prompt() 函数,该函数要求用户输入数据,并在他们单击确定后将其存储在变量中。在此示例中,我们要求用户输入一个名称并将其存储在 myName 中。

    接下来,代码使用 Web Storage API,它允许我们将数据存储在浏览器中并稍后检索。我们使用 localStorage.setItem() 函数创建和存储一个名为 "name" 的数据项,将其值设置为 myName 变量,其中包含用户的输入。

    最后,我们将标题的 textContent 设置为一个包含用户存储名称的字符串。

  4. 在函数声明之后添加以下条件块。这是我们的初始化代码——它在页面首次加载时运行以启动程序:

    js
    if (!localStorage.getItem("name")) {
      setUserName();
    } else {
      const storedName = localStorage.getItem("name");
      myHeading.textContent = `Mozilla is cool, ${storedName}`;
    }
    

    此块的第一行使用否定运算符(逻辑非,由 ! 字符表示)检查 name 数据项是否尚未存储在 localStorage 中。如果未存储,则运行 setUserName() 函数来创建它。如果它存在(即用户在之前访问期间设置了用户名),我们使用 localStorage.getItem() 检索存储的名称,并将标题的 textContent 设置为字符串,再加上用户的名称——就像我们在 setUserName() 中所做的那样。

  5. 向按钮添加一个 click 事件处理函数。当点击时,setUserName() 运行。这允许用户如果愿意,可以存储不同的名称。

    js
    myButton.addEventListener("click", () => {
      setUserName();
    });
    
  6. 保存所有文件并在浏览器中加载 index.html。你应该会立即被要求输入你的姓名。完成操作后,你的姓名将作为个性化问候语的一部分出现在 <h1> 中。请注意,即使重新加载页面,个性化设置也会持久存在。你可以点击“更改用户”按钮输入新名称。

注意:术语运算符指的是对一个或多个值执行操作的 JavaScript 语言字符。示例包括 +(加值)、-(从一个值中减去另一个值)和 !(否定一个值——正如你之前看到的)。

用户名为 null?

当你运行示例并出现提示你输入姓名的对话框时,请尝试按下取消按钮。你最终会得到一个标题,上面写着Mozilla 很酷,null。发生这种情况是因为当你取消提示时,该值被设置为null。在 JavaScript 中,null 是一个特殊值,表示缺少值。

另外,尝试在不输入姓名的情况下点击确定。你最终会得到一个标题,上面写着Mozilla 很酷,,因为你已将 myName 设置为空字符串。

为了避免这些问题,你可以添加另一个条件来检查用户是否未输入空白名称。将你的 setUserName() 函数更新为以下内容:

js
function setUserName() {
  const myName = prompt("Please enter your name.");
  if (!myName) {
    setUserName();
  } else {
    localStorage.setItem("name", myName);
    myHeading.textContent = `Mozilla is cool, ${myName}`;
  }
}

用人类语言来说,这意味着:如果 myName 没有值,则从头开始再次运行 setUserName()。如果它确实有值(如果上述语句不为真),则将该值存储在 localStorage 中,并将其设置为标题的文本。

总结

如果你已按照本文中的所有说明进行操作,你最终会得到一个页面,看起来如下图所示。你也可以查看我们的版本

Final look of HTML page after creating elements: a header, large centered logo, content, and a button

如果你遇到问题,可以将你的工作与我们 GitHub 上的最终示例代码进行比较。

在本文中,我们只是触及了 JavaScript 的皮毛。你将在本课程稍后的 使用 JavaScript 进行动态脚本编程核心模块中学习更多内容。

另见

Scrimba:学习 JavaScript MDN 学习合作伙伴

Scrimba 的 学习 JavaScript 课程通过解决 140 多个互动编码挑战,构建包括游戏、浏览器扩展甚至移动应用程序在内的项目来教你 JavaScript。Scrimba 提供由知识渊博的老师讲授的有趣互动课程。

学习 JavaScript

这是有抱负的 Web 开发人员的绝佳资源!在互动环境中学习 JavaScript,通过短课和互动测试,并通过自动化评估进行指导。前 40 节课是免费的。完整课程只需一次小额付款即可获得。