在进一步介绍 JavaScript 之前,我们首先看一个 JavaScript 实例。通过这个实例,我们将陆续引入一些知识点。在本节,我们不会详细介绍这些知识点。此处引入它们的目的是为了让大家了解这些知识点的大致概念,这样之后在介绍这些知识点时不会太突兀。
例 1 的功能是:初始状态显示一个宽度和高度都为 200px,且背景颜色为灰色的 div;当将光标移到 div 上时 div 的宽度变为 400px,背景颜色变为粉红色;当将光标从 div 上移出时 div 的宽度和背景颜色都恢复为初始样式。
通过分析可知,上述功能包含两种效果:一是初始效果,二是动态效果。由此我们可以按照使用 JavaScript 实现网页动态变化效果的步骤来实现上述功能需求:初始效果可以使用 CSS 来设置,而光标移入、移出所产生的动态效果则使用 JavaScript 来实现。具体代码如下所示:
【例 1】第一个 JavaScript 实例。
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>第一个JavaScript实例</title>
<style>
/*设置div的宽度、高度和背景样式*/
div{
width:200px;
height:200px;
background:#CCC;
}
</style>
</head>
<body>
<div id="div1"></div>
<script>
//使用document对象调用getElmentById()方法获取文档中的元素
var oDiv = document.getElementById("div1"); // ①
//光标移入div上时调用函数修改div样式
oDiv.onmousemover = changeStyle; // ②
//alert("hi"); // ③
//光标移出div时调用函数恢复div最初样式
oDiv.onmouseout = resetStyle; // ④
//oDiv.onmouseout=resetStyl;// ⑤
//alert("hello"); // ⑥
//定义函数,修改div的宽度和背景颜色
function changeStyle(){ // ⑦
oDiv.style.width = "400px";
oDiv.style.background = "#FCF";
}
//定义函数,将div的宽度和背景样式恢复为最初状态
function resetStyle(){ // ⑧
oDiv.style.width = "200px";
oDiv.style.background = "#CCC";
}
</script>
</body>
</html>
上述代码在 Chrome 浏览器中运行后的初始效果和光标移出 div 后的效果完全一样,如图 1 所示。
光标移入 div 后的效果如图 2 所示。
例 1 使用 CSS 代码获得图 1 所示的初始效果,包括设置 div 的宽度、高度和背景样式。而图 2 所示的效果,以及由图 2 恢复到图 1 所示的效果则使用 JavaScript 代码来实现。这些 JavaScript 代码在示例中通过<script></script>标签嵌入到 HTML 页面中。浏览器加载 HTML 文档的过程中,一遇到<script></script>就会调用 JavaScript 引擎对脚本代码进行解析和执行。
注:JavaScript 引擎,简单地说,就是能够“读懂”JavaScript 代码,并准确地给出代码运行结果的一段程序。JavaScript 引擎是浏览器的一个组成内容,一般由各个浏览器开发商自行开发,所以不同浏览器的 JavaScript 引擎有可能是不同的,比如:IE 的 JavaScript 引擎是 Chakra、Chrome 的 JavaScript 引擎是 V8 等。
在早期,JavaScript 引擎可以说就是一个解释器,但现在的 JavaScript 引擎其实都具有了一些编译器的功能,比如 Chrome 的 JS 引擎 V8,为了提高 JS 的运行性能,在运行之前会先将 JS 编译为本地的机器码码,然后再去执行机器码,这样速度就快很多。
例 1 <script></script>中脚本代码到目前为此,对初学者来说还很陌生,下面我们将对它们进行一一讲解。
上述代码中以//开头的语句表示注释语句。注释语句的作用是对代码进行描述说明。注释语句主要是给开发人员和维护人员看的,目的是为了提高代码的可读性和可维护性。浏览器对注释语句既不会显示,也不会执行。
在 JavaScrip t中,注释有单行注释和多行注释两种形式。所谓单行注释,就是注释文字比较少,在一行内可以显示完;多行注释就是注释文字比较多,需要分多行来显示。多行注释也可以用多个单行注释来表示。单行注释以//开始,后面跟着的内容就是注释,例 1 中的注释全部都是单行注释;多行注释以/*开始,以*/结束,它们之间的内容就是注释,示例如下:
注释 ① 对应的代码:用于获取文档中指定 id 的元素,并将元素储存在指定的变量中,其中的“var”用于声明变量,var 后面跟着的单词就是变量名。因为状态动态变化是通过修改特定元素的样式来实现的,另外,光标的移入和移出也是针对特定的元素的,所以必须首先获取这些特定元素。
获取文档中的特定元素最常用的方法是使用 document 对象或其他文档元素对象调用 getElementById(元素 id 属性值)方法。由于 getElementById() 方法需要使用 id 值,所以对应的元素中必须包含 id 属性。
注:获取文档元素除了可以使用 getElementById(),还有其他一些常用的方法,如 getElementsByTagName('标签名'),这个方法将会返回指定标签名的所有元素,结果是一个数组,这些方法我们之后会陆续介绍。
注释 ② 和 ④ 处的代码:分别表示光标移入和光标移出 div 的事件处理。在 JavaScript 中,光标移入和光标移出分别表示两个事件(所谓事件,就是用户与 Web 页面交互时产生的操作。而在 Web 页面中产生事件的对象,称为事件目标),这些事件一旦发生,将会由事件目标调用相关的脚本代码进行处理。例如,用户将光标移到和移出 div 元素时,会分别触发光标移入和光标移出事件,此时事件目标是 div 元素。
注释 ② 处的代码通过事件目标调用 changeStyle 函数来处理光标移入事件;注释 ④ 处代码则通过事件目标调用 resetStyle 函数来处理光标移出事件。在 JavaScript 中,除了上述示例中的光标移入和光标移出事件外,还有许多事件,例如键盘事件、表单事件、窗口事件等,对这些事件及其处理我们之后会详细介绍。
注释 ⑦ 和 ⑧ 处的代码:分别定义了两个函数,函数名分别为 changeStyle 和 resetStyle。所谓函数,其实就是实现某种功能的一系列命令(即脚本代码)的集合。
function为函数定义的关键字,不能省略;函数名可以任意命名或使用函数表达式时可以直接省略函数名,命名时名称需要符合规范;参数可以包含 0 到多个,不管参数有没有,小括号都必须保留;函数中的所有命令必须放到一对大括号中。
需要注意的是,函数定义后,不会自动执行,必须通过调用,函数才可以执行。函数的调用方式有多种,常用方式有:直接调用函数以及事件调用。事件调用需要在脚本代码中将函数名或函数定义作为元素的事件属性值,所以这种调用方式也称为事件绑定。事件绑定的函数在事件发生时会自动执行,事件没发生则不会执行。
需要注意的是,使用函数名来绑定事件时,函数名后面不能跟小括号,否则,代码执行到函数名所在行时事件没有发生也会自动调用函数执行。例 1 中的函数调用代码分别如注释 ② 和 ④ 处所示,它们都使用了事件绑定方法,将 changeStyle 和 resetStyle 两个函数分别绑定到了 onmouseover 和 onmouseout 事件,这样一旦发生光标移入事件和光标移出事件就会调用相应的函数。有关函数的调用及其他内容我们之后介绍。
注释 ③ 和 ⑥ 处的代码在此作为调试代码使用,alert() 的作用是弹出警告对话框。当我们将注释 ④ 处的代码用//注释起来,同时将注释 ③、⑤ 和 ⑥ 处的代码前面的//删掉,然后再次运行例 1,结果只弹出图 3 所示的警告对话框。
由此可知 ③ 处的代码执行了,但 ⑥ 处的代码没有执行,因此可以判断,③ 处代码前面的代码都没有问题,但 ③ 和 ⑥ 之间的 ⑤ 处的代码有问题。经检查,原来把定义的函数名“resetStyle”写成了“resetStyl”。
除了可以使用 alert() 方法调试脚本,还可以使用浏览器的“开发者工具”调试。打开 Chrome 浏览器的“开发者工具”,在默认打开的控制台窗口,可以看到图 4 所示的错误信息。
图 4 所示的错误信息提示 ex1.html 文件中的第 26 行代码的“resetStyl”没有定义。可见,使用“开发者工具”同样可以很容易得知错误所在地方。
在前面的介绍中,我们说事件绑定既可以使用函数名,也可以使用函数定义,这两种方式的作用是完全一样的,所以我们可以将例 1 注释 ② 和 ④ 处的函数调用进行如下修改:
//使用函数定义绑定事件
oDiv.onmouseover = function changeStyle(){
oDiv.style.width = "400px";
oDiv.style.background = "#FCF";
};
//使用函数定义绑定事件
oDiv.onmouseout = function resetStyle(){
oDiv.style.width = "200px";
oDiv.style.background = "#CCC";
};
很显然,通过绑定函数定义可以使代码更加简洁。不过,绑定函数定义有一个条件,就是该函数只需要绑定到一个事件上。如果一个函数需要绑定在多个事件上,则需要使用例 1 所示的方法,即将函数名绑定到事件。
一个函数只需要绑定在一个事件上时,我们还可以通过省略函数名进一步简化代码,此时可将上述代码修改为如下代码:
//使用没有函数名的函数定义绑定事件
oDiv.onmouseover = function (){ //使用匿名函数
oDiv.style.width = "400px";
oDiv.style.background = "#FCF";
};
//使用没有函数名的函数定义绑定事件
oDiv.onmouseout = function (){ //使用匿名函数
oDiv.style.width = "200px";
oDiv.style.background = "#CCC";
};
上述代码中,没有函数名的函数称为匿名函数,相对应的,有函数名的函数称为有名函数。从前面的介绍可知,当一个函数需要在多处调用时,需要使用有名函数;如果只需要在一个地方调用,则建议使用匿名函数,这样可以使代码更加简洁。
在例 1 中,我们看到 <script> 标签出现在所有页面元素的后面,这是否说明,<script> 标签只能以这种方式出现呢?答案是否定的。事实上,JavaScript 脚本代码可以出现在 HTML 文档中的任何地方。如此,我们可以把例 1 中的脚本代码放到头部区域中吗?回答这个问题前,我们先测试一下。
现在我们把例 1 的 <script> 标签及其中所有脚本代码移到文档头部区域的<style></style>标签后面,保存文件后在 Chrome 浏览器中运行,结果发现光标移入和光标移出事件都没有效果。打开 Chrome 浏览器的“开发者工具”,单击“Console”,出现图 5 所示的错误信息。
图 5 所示的错误信息提示 ex1.html 文件中的第 18 行代码不能设置空值的“onmouseover”属性。为什么会出现这个错误信息呢?
我们介绍了非事件处理代码在载入 HTML 文档时会按 JavaScript 在文档中出现的顺序,从上往下依次执行。将例 1 中的脚本代码调到头部区域后,注释 ① 处的代码属于非事件处理代码,所以它会按载入的顺序依次执行,即会执行代码获取 div 元素。
但问题是根据文档加载的顺序,此时 div 元素还没有加载到文档中,导致脚本执行后得到的结果都是 null,即空值,所以脚本引擎解析到注释②处的代码时,代码变为了 null.onmouseover。这就是控制台报错的原因。脚本引擎解析到注释 ② 处的代码出错后就使脚本代码停滞下来而无法往下执行,因而后面的光标移出事件也无法正常处理。
应如何解决图 5 所示的错误呢?从上面的分析我们知道,之所以会出现图示错误,是因为执行注释 ① 处的脚本代码前,需要获取的元素还没有加载到文档中,由此可以想到,如果我们在这些元素加载之后再执行获取这些元素的脚本代码不就可以了吗?确实是这样的,这正是示例 1 的脚本代码放到 HTML 元素的后面的原因。
那是否对这种情况,脚本代码的出现位置就只能如例 1 所示的那样呢?答案是否定的。其实实际应用中最常用的一种解决图 5 所示问题的方法是使用事件处理。在 JavaScript 中,有一个窗口加载事件,该事件会在 HTML 文档加载完后自动触发执行。因此我们可以把需要元素加载完后才执行的脚本代码作为窗口加载事件处理代码。
使用窗口加载事件后,脚本代码可以放到文档的任意位置,而不需要考虑元素以及脚本代码的加载顺序。窗口加载事件的事件目标为“window”对象,对应的事件属性是“onload”。窗口加载事件处理代码格式为:
下面我们使用匿名函数以及窗口加载事件修改例 1 代码:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>使用匿名函数及窗口加载事件</title>
<style>
/*设置div的宽度、高度和背景样式*/
div{
width:200px;
height:200px;
background:#CCC;
}
</style>
<script>
window.onload = function (){ //使用窗口加载事件绑定匿名函数
//使用document对象调用getElmentById()方法获取文档中的元素
var oDiv = document.getElementById("div1");
//光标移入div上时调用函数修改div样式
oDiv.onmouseover = function (){ //使用匿名函数
oDiv.style.width = "400px";
oDiv.style.background = "#FCF";
}
//光标移出div时调用函数恢复div最初样式
oDiv.onmouseout = function(){ //使用匿名函数
oDiv.style.width = "200px";
oDiv.style.background = "#CCC";
}
}
</script>
</head>
<body>
<div id="div1"></div>
</body>
</html>
在 Chrome 浏览器运行上述代码,结果和图 1、图 2 所示完全一样。