构建你自己的函数
在上一篇文章中处理了大部分基本理论之后,本文将提供实践经验。在这里,你将获得一些构建自己的自定义函数的实践。在此过程中,我们还将解释一些处理函数的有用细节。
让我们构建一个函数
我们要构建的自定义函数将命名为 displayMessage()。它将在网页上显示一个自定义消息框,并作为浏览器内置 alert() 函数的自定义替代品。我们之前见过这个,但让我们刷新一下记忆。在你的浏览器 JavaScript 控制台中,在任何你喜欢的页面上输入以下内容:
alert("This is a message");
alert() 函数接受一个参数——在警报框中显示的字符串。尝试改变字符串来改变消息。
alert() 函数是有限的:你可以修改消息,但不能轻易修改其他任何东西,例如颜色、图标或其他任何东西。我们将构建一个更有趣的。
注意:此示例应该在所有现代浏览器中正常工作,但在稍微旧的浏览器中样式可能会有点奇怪。我们建议你在现代浏览器(如 Firefox、Opera 或 Chrome)中进行此练习。
基本函数
首先,让我们组合一个基本函数。
注意:对于函数命名约定,你应该遵循与变量命名约定相同的规则。这很好,因为你可以区分它们——函数名后面带有括号,而变量名没有。
-
首先访问 function-start.html 文件并制作一个本地副本。你会看到 HTML 很简单——
只包含一个按钮。我们还提供了一些基本的 CSS 来样式化自定义消息框,以及一个空的<script>元素来放置我们的 JavaScript。 -
接下来,在
<script>元素中添加以下内容jsfunction displayMessage() { // … }我们以关键字
function开头,这意味着我们正在定义一个函数。这后面跟着我们希望给函数起的名称、一组括号和一组花括号。我们希望给函数的任何参数都放在括号内,而当我们调用函数时运行的代码则放在花括号内。 -
最后,在花括号内添加以下代码
jsconst body = document.body; const panel = document.createElement("div"); panel.setAttribute("class", "msgBox"); body.appendChild(panel); const msg = document.createElement("p"); msg.textContent = "This is a message box"; panel.appendChild(msg); const closeBtn = document.createElement("button"); closeBtn.textContent = "x"; panel.appendChild(closeBtn); closeBtn.addEventListener("click", () => panel.parentNode.removeChild(panel), );
这有很多代码需要理解,所以我们将逐步为你讲解。
第一行使用 DOM API 获取全局 document 对象的 body 属性,选择 <body> 元素,并将其赋值给一个名为 body 的常量,以便我们以后可以使用它
const body = document.body;
下一节使用一个名为 document.createElement() 的 DOM API 函数来创建一个 <div> 元素,并将其引用存储在一个名为 panel 的常量中。这个元素将是我们消息框的外部容器。
然后,我们使用另一个名为 Element.setAttribute() 的 DOM API 函数,为我们的面板设置一个 class 属性,值为 msgBox。这使得样式化元素更容易——如果你查看页面上的 CSS,你会看到我们正在使用 .msgBox 类选择器来样式化消息框及其内容。
最后,我们在之前存储的 body 常量上调用一个名为 Node.appendChild() 的 DOM 函数,它将一个元素嵌套在另一个元素内部作为其子元素。我们将面板 <div> 指定为我们要追加到 <body> 元素内部的子元素。我们需要这样做,因为我们创建的元素不会自己出现在页面上——我们需要指定将其放在何处。
const panel = document.createElement("div");
panel.setAttribute("class", "msgBox");
body.appendChild(panel);
接下来的两部分使用了我们已经见过的相同的 createElement() 和 appendChild() 函数来创建两个新元素——一个 <p> 和一个 <button>——并将它们作为面板 <div> 的子元素插入到页面中。我们使用它们的 Node.textContent 属性(它表示元素的文本内容)在段落中插入一条消息,在按钮中插入一个“x”。当用户想要关闭消息框时,这个按钮就是需要点击/激活的。
const msg = document.createElement("p");
msg.textContent = "This is a message box";
panel.appendChild(msg);
const closeBtn = document.createElement("button");
closeBtn.textContent = "x";
panel.appendChild(closeBtn);
最后,我们调用 addEventListener() 来添加一个函数,该函数将在用户点击“关闭”按钮时被调用。该代码将从页面中删除整个面板——以关闭消息框。
简而言之,addEventListener() 方法由按钮(实际上,是页面上的任何元素)提供,它可以传递一个函数和一个事件名称。在这种情况下,事件名称是“click”,这意味着当用户点击按钮时,该函数将运行。你将在我们的事件文章中学习更多关于事件的知识。函数内部的行使用 Node.removeChild() DOM API 函数来指定我们要删除 HTML 元素的特定子元素——在这种情况下,是面板 <div>。
closeBtn.addEventListener("click", () => panel.parentNode.removeChild(panel));
基本上,这整段代码正在生成一段看起来像这样的 HTML,并将其插入到页面中:
<div class="msgBox">
<p>This is a message box</p>
<button>x</button>
</div>
这需要处理很多代码——如果现在你记不住它的每个部分是如何工作的,也别太担心!我们这里主要关注的是函数的结构和用法,但我们想为这个例子展示一些有趣的东西。
调用函数
你现在已经把你的函数定义很好地写到了 <script> 元素中,但它目前什么也不会做。
-
尝试在函数下方添加以下行来调用它:
jsdisplayMessage();此行调用函数,使其立即运行。当你保存代码并在浏览器中重新加载时,你会看到小消息框立即出现,只出现一次。毕竟,我们只调用它一次。
-
现在打开示例页面上的浏览器开发者工具,进入 JavaScript 控制台并再次输入该行,你会看到它再次出现!所以这很有趣——我们现在有一个可重用的函数,我们可以随时调用它。
然而,我们可能希望消息框响应用户和系统操作而出现。在实际应用中,这样的消息框可能会在新数据可用、发生错误、用户尝试删除其配置文件(“你确定吗?”)或用户添加新联系人并操作成功完成等情况下被调用。
在这个演示中,我们将让消息框在用户点击按钮时出现。以下是你需要遵循的步骤:
-
删除你之前添加的行(
displayMessage();)。 -
选择
<button>元素并将其引用存储在一个常量中。在函数定义上方添加以下行到你的代码中:jsconst btn = document.querySelector("button"); -
为按钮点击创建一个事件监听器,该监听器会调用我们的函数。在
const btn =之后添加以下行:jsbtn.addEventListener("click", displayMessage);与我们的 closeBtn 的点击事件处理程序类似,这里我们是在响应按钮点击时调用一些代码。但在这种情况下,我们不是调用包含某些代码的匿名函数,而是按名称调用我们的
displayMessage()函数。 -
最后,尝试保存并刷新页面——现在你应该会在点击按钮时看到消息框出现。
你可能想知道为什么我们没有在函数名称后面加上括号。这是因为我们不想立即调用函数——只有在按钮被点击后才调用。如果你尝试将该行更改为:
btn.addEventListener("click", displayMessage());
然后保存并重新加载,你会发现消息框在没有点击按钮的情况下就出现了!在这种情况下,括号有时被称为“函数调用运算符”。你只在希望函数在当前作用域中立即运行时使用它们。同样,匿名函数内部的代码不会立即运行,因为它在函数作用域内。
如果你尝试了上一个实验,请务必在继续之前撤消最后一次更改。
用参数改进函数
就目前而言,该函数仍然不是很实用——我们不想每次都只显示相同的默认消息。让我们通过添加一些参数来改进我们的函数,从而允许我们用不同的选项调用它。
-
首先,更新函数的第一行
jsfunction displayMessage() {改为
jsfunction displayMessage(msgText, msgType) {现在当我们调用函数时,我们可以在括号内提供两个变量值,以指定要在消息框中显示的消息和消息的类型。
-
要使用第一个参数,请更新函数中的以下行:
jsmsg.textContent = "This is a message box";改为
jsmsg.textContent = msgText; -
最后但同样重要的是,你现在需要更新你的函数调用,以包含一些更新后的消息文本。更改以下行:
jsbtn.addEventListener("click", displayMessage);到这个代码块
jsbtn.addEventListener("click", () => displayMessage("Woo, this is a different message!"), );如果我们想在括号中为我们正在调用的函数指定参数,那么我们不能直接调用它——我们需要将其放在一个匿名函数中,这样它就不在立即作用域内,因此不会立即被调用。现在,它要等到按钮被点击后才会被调用。
-
重新加载并再次尝试代码,你会看到它仍然运行良好,只是现在你还可以更改参数中的消息,以在框中显示不同的消息!
一个更复杂的参数
接下来是下一个参数。这个参数将涉及更多的工作——我们将设置它,以便根据 msgType 参数的设置,函数将显示不同的图标和不同的背景颜色。
-
首先,从 GitHub 下载本次练习所需的图标(warning 和 chat)。将它们保存在与 HTML 文件相同位置的名为
icons的新文件夹中。注意: 警告和聊天图标最初来自 iconfinder.com,由 Nazarrudin Ansyari 设计——谢谢!(实际的图标页面已移动或删除。)
-
接下来,找到 HTML 文件中的 CSS。我们将进行一些更改,以便为图标腾出空间。首先,将
.msgBox宽度从以下内容更新:csswidth: 200px;改为
csswidth: 242px; -
接下来,在
.msgBox p { }规则中添加以下行:csspadding-left: 82px; background-position: 25px center; background-repeat: no-repeat; -
现在我们需要在
displayMessage()函数中添加代码来处理图标的显示。在函数的右大括号 (}) 正上方添加以下代码块:jsif (msgType === "warning") { msg.style.backgroundImage = 'url("icons/warning.png")'; panel.style.backgroundColor = "red"; } else if (msgType === "chat") { msg.style.backgroundImage = 'url("icons/chat.png")'; panel.style.backgroundColor = "aqua"; } else { msg.style.paddingLeft = "20px"; }这里,如果
msgType参数设置为"warning",则显示警告图标并将面板的背景颜色设置为红色。如果设置为"chat",则显示聊天图标并将面板的背景颜色设置为水蓝色。如果msgType参数根本没有设置(或设置为不同的值),则代码的else { }部分将起作用,段落将获得默认的内边距,没有图标,也没有设置背景面板颜色。这提供了在未提供msgType参数时的默认状态,这意味着它是一个可选参数! -
让我们测试一下我们更新后的函数,尝试将
displayMessage()调用从这个jsdisplayMessage("Woo, this is a different message!");更改为其中一个
jsdisplayMessage("Your inbox is almost full — delete some mails", "warning"); displayMessage("Brian: Hi there, how are you today?", "chat");你可以看到我们的(现在不再那么)小的函数变得多么有用。
注意:如果你在让示例工作时遇到问题,请随时将你的代码与 GitHub 上的完成版本进行检查(也可以查看其运行情况),或向我们寻求帮助。
总结
恭喜你到达终点!本文带领你完成了构建一个实用的自定义函数的整个过程,再稍加努力,这个函数就可以移植到实际项目中。在下一篇文章中,我们将通过解释另一个重要的相关概念——返回值来总结函数。