首页 >web前端 >js教程 >脚本更智能:从头开始的质量JavaScript

脚本更智能:从头开始的质量JavaScript

尊渡假赌尊渡假赌尊渡假赌
尊渡假赌尊渡假赌尊渡假赌原创
2025-03-08 00:04:10983浏览

Script Smarter: Quality JavaScript from Scratch

>它可能直接在其中有代码:

<script type="text/javascript"> <br>
function saySomething(message) <br>
{ <br>
  alert(message); <br>
} <br>
saySomething('Hello world!'); <br>
</script>

不必担心这些片段之间的差异。我们可以在网页上添加JavaScript的多种方法 - 好与坏。我们将在本章稍后详细介绍这些方法。

> JavaScript是由Netscape开发的,并在Netscape 2中实施,尽管它最初称为Livescript。另一种语言Java越来越受欢迎,促使Netscape更改名称以试图兑现连接,因为JavaScript提供了在浏览器和Java Applet之间进行交流的能力。

但是,由于语言是由Netscape,其原始形式和Microsoft开发的,在类似但不同的JScript实现中,很明显,Web脚本太重要了,无法留给供应商竞争的狼。因此,在1996年,开发被移交给了一个名为ECMA的国际标准机构,JavaScript成为Ecmascript或ECMA-262。

大多数人仍然将其称为JavaScript,这可能是造成混乱的原因:除了语法,Java和JavaScript的名称和相似之处外,都不一样。

> JavaScript的限制

JavaScript >由于JavaScript无法访问服务器环境,因此有许多任务,尽管在PHP中执行琐碎的任务,但JavaScript:读取和写入数据库或创建文本文件就无法实现。但是,由于JavaScript确实可以访问客户端环境,因此可以根据服务器端语言根本没有的数据做出决定,例如鼠标的位置或元素的渲染大小。
activex?

>

>

如果您已经对Microsoft的JScript非常熟悉,则可能会在考虑“但是JavaScript可以使用ActiveX来做其中的某些事情”,但这是事实 - 但是ActiveX并不是Ecmascript的一部分。 ActiveX是一种特定于Windows的机制,用于允许Internet Explorer访问COM(Windows脚本技术核心的组件对象模型),通常仅在受信任的环境(例如Intranet)中运行。我们会遇到一些具体的例外 - IE中没有特殊安全性的ActiveX控件的示例(例如Flash插件和XMLHTTPRequest) - 但在大多数情况下,使用ActiveX的脚本不在这本书的范围之内。

>

通常,运行客户端的计算机不会像服务器那样强大,因此JavaScript并不是进行大量数据处理的最佳工具。但是,对客户的数据处理的即时性使此选项对少量处理有吸引力,因为可以立即收到响应;例如,表单验证是客户端处理的良好候选人。

>

但是要比较服务器端和客户端语言与“更好”的视图是误导的。这两个都不是更好 - 它们是用于不同工作的工具,它们之间的功能交叉很小。但是,客户端和服务器端脚本之间的交互增加正在引起新一代的Web脚本,该脚本使用XMLHTTPRequest之类的技术来提出服务器数据的请求,运行服务器端脚本,然后在客户端端管理结果。我们将在第18章中深入研究这些技术,并使用JavaScript构建Web应用程序。

安全限制

由于JavaScript在高度敏感的数据和程序的领域内运行,因此其功能受到限制,以确保无法恶意使用它。因此,简直不允许JavaScript做很多事情。例如,它无法从计算机中读取大多数系统设置,直接与硬件进行交互或导致程序运行。 此外,由于该元素的属性,在JavaScript中不允许在JavaScript中允许某些特定的交互。例如,更改表单

的值 通常没有问题,但是如果它是文件输入字段(例如,),完全不允许写信给它 - 一种限制,可以防止恶意脚本使用户上传他们没有选择的文件。

>

>有很多类似的安全性限制的示例,我们将在本书中介绍的应用程序中进行扩展。但总而言之,以下是JavaScript的主要限制和安全限制的列表,包括我们已经看到的那些。 JavaScript不能:

  • >直接打开并读取文件(在特定情况下(如第18章中详细介绍),使用JavaScript构建Web应用程序)。
  • >在用户的计算机上创建或编辑文件(cookie除外,这是在第8章中讨论的,使用cookie)。
  • >
  • 读取http post data。
  • >读取系统设置或用户计算机中未通过语言或主机对象提供的任何其他数据(主机对象是窗口和屏幕之类的东西,这些内容由环境而不是语言本身提供。)
  • 修改文件输入字段的值。
  • 更改A的显示器的显示。
  • 关闭或修改脚本未打开的窗口的工具栏和其他元素(即,主浏览器窗口)。
  • >
  • >最终,JavaScript可能根本不支持。
>

>还值得记住的是,许多浏览器都包含允许更精确的选项,而不是简单地启用或禁用JavaScript。例如,Opera包括禁止脚本关闭窗口,移动窗口,写入状态栏,接收右键单击的选项……列表还在继续。您几乎无法做到这一点,但是大多数情况下,您不需要吗?这样的选择已经演变成压制“烦人的”脚本(状态栏滚动器,无右键单击脚本等),因此,如果您远离这些脚本,那么这个问题只会很少出现。

>>

> JavaScript最佳实践
JavaScript最佳实践
最重视您应该为浏览器不支持脚本的人做什么的问题。

最终问题是最难解决的,我们将重点关注第16章,JavaScript和可访问性的解决方案。在本节中,我想查看良好JavaScript的三个核心原则:

渐进式增强 - 为没有JavaScript的用户提供
    的用户
  • >不引人注目的脚本 - 将内容与行为分开
  • 一致的编码实践 - 使用牙套和半终止量
  • >第一个原则可确保每当我们在网站上使用脚本时,我们都在考虑更大的情况。第二点使我们可以更轻松地维护我们,并为用户提供更好的可用性和优雅的降解
。 (优雅的退化意味着,如果不支持JavaScript,浏览器可以自然地落在或“退化”到非脚本功能。)第三个原理使代码更易于阅读和维护。

> 为没有JavaScript(渐进增强)的用户提供 >用户可能没有JavaScript的原因有几个:

>
  • 他们使用的是根本不支持脚本的设备,或以有限的方式支持它。
  • >它们是滤波javaScript的代理服务器或防火墙后面。
  • 他们故意关闭JavaScript。
  • >
第一点涵盖了令人惊讶且不断增长的设备,包括PDAS,包括WebTV和Sony PSP等小屏幕设备,包括Opera 5和NetScape 4等传统JavaScript浏览器。

>上面列表中的最后一点可以说是最不可能的(除了其他扮演魔鬼的倡导者的开发人员之外!),但原因并不重要:有些用户根本没有JavaScript,我们应该容纳它们。没有办法量化属于此类别的用户数量,因为众所周知,从服务器中检测JavaScript支持是不可靠的,但是我看到的数字将JavaScript的用户比例放在5%和20%之间,具体取决于您是否将搜索引擎描述为“用户”。

解决方案

>解决此问题的长期方法是使用HTML NoScript元素,其内容是由根本不支持脚本元素的浏览器渲染的内容,并且浏览器支持它,但脚本已关闭。 尽管这是一个合理的想法,但实际上,随着时间的流逝,该解决方案变得越来越少,因为NoScript无法通过功能来区分。提供有限的JavaScript支持的浏览器将无法运行复杂的脚本,但是此类设备是具有脚本功能的浏览器,因此它们也不会解析NoScript元素。这些浏览器最终将一无所有。

解决此问题的一种更好的方法是从静态HTML开始,然后使用脚本修改或在该静态内容中添加动态行为。

>让我们看一个简单的示例。制作DHTML菜单的首选技术使用无序的列表作为主菜单结构。我们将在第15章,DHTML菜单和导航上全部专门针对此主题,但是这个简短的例子说明了这一点:

>

>链接列表是普通的HTML,因此对于所有用户都存在,无论是否启用了脚本。如果支持脚本,我们的菜单脚本可以应用动态行为,但是如果不支持脚本,则内容仍然出现。我们没有明确区分设备 - 如果浏览器可以处理它,我们只是提供了动态的内容,如果没有,则静态。

讨论

>“传统”方法是在纯JavaScript中生成单独的,动态的菜单,并在NoScript元素中具有后备静态内容:
<script type="text/javascript"> <br>
function saySomething(message) <br>
{ <br>
  alert(message); <br>
} <br>
saySomething('Hello world!'); <br>
</script>

,但是,正如我们已经看到的那样,由于JavaScript支持不再是全有或全无的主张,因此各种各样的设备将掉落。上面的方法为所有设备提供默认内容,并且仅在工作时才应用脚本功能。

>

这种脚本方法通常被称为渐进式增强,这是我们在本书中使用的一种方法。

>

>不要问!

>> 均不应使用此技术和NoScript元素添加一条读的消息,该消息读:“请打开JavaScript继续进行。”充其量,这样的信息是自以为是的(“为什么?”);最糟糕的是,它可能是无助的(“我不能!”)或毫无意义(“什么是JavaScript?”)。就像那些说“请升级您的浏览器”的飞溅页面一样,这些消息对普通网络用户也一样有用,就像路标一样,读写:“请使用其他汽车”。 有时,您可能会面临一个情况,在没有JavaScript的情况下,无法提供等效功能。在这种情况下,我认为可以发出一条静态信息,该消息将这种不相容性告知用户(当然,以非技术性的术语)。但是,在大多数情况下,除非实际上是唯一的方法,否则尽量避免提供这种信息。

将内容与行为分开(不引人注目的脚本)

> >将内容与行为分开意味着将网页构造的各个方面与众不同。杰弗里·扎尔德曼(Jeffrey Zeldman)著名地将其称为网络开发的“三足脚凳”(Zeldman,J。使用网络标准设计。新车手,2003年) - 包含内容(HTML),演示(CSS)和行为(JavaScript) - 不仅强调了每个方面功能的差异,而且还应该与他们分开良好的分离使得更易于维护,更容易访问并在较旧或较低的浏览器中降低的网站。

>
解决方案

在一个极端,这与将内容与行为分开的理想直接相反,我们可以直接在属性事件处理程序中编写内联代码。这很混乱,通常应该避免:

我们可以通过获取完成工作并将其抽象为函数的代码来改善情况:> >定义一个为我们完成工作的函数,让我们可以在单独的JavaScript文件中提供大多数代码:>

<script type="text/javascript"> <br>
function saySomething(message) <br>
{ <br>
  alert(message); <br>
} <br>
saySomething('Hello world!'); <br>
</script>

>但是,更好的方法是避免完全使用内联事件处理程序。相反,我们可以利用文档对象模型(DOM)将事件处理程序绑定到HTML文档中的元素。 DOM是一个标准编程界面,诸如JavaScript之类的语言可以访问HTML文档的内容,从而消除了任何JavaScript代码出现在HTML文档本身中的需求。在此示例中,我们的HTML代码看起来如下:

<ul > <br>
  <li><a href="/">Home</a></li> <br>
  <li><a href="/about/">About</a></li> <br>
  <li><a href="/contact/">Contact</a></li> <br>
</ul> <br>
 <br>
<script type="text/javascript" src="menu.js"></script>

这是我们要使用的脚本:

<script type="text/javascript" src="menu.js"></script> <br>
 <br>
<noscript> <br>
  <ul> <br>
    <li><a href="/">Home</a></li> <br>
    <li><a href="/about/">About</a></li> <br>
    <li><a href="/contact/">Contact</a></li> <br>
  </ul> <br>
</noscript>

>这种方法允许我们不必编辑HTML添加,删除或更改事件处理程序,并且由于文档本身根本不依赖或参考脚本,因此不了解JavaScript的浏览器不会受到影响。该解决方案还提供了可重用性的好处,因为我们可以根据需要将相同的功能绑定到其他元素,而无需编辑HTML。

该解决方案取决于我们通过DOM访问元素的能力,我们将在第5章中深入介绍文档对象模型。

>

分离的好处 通过实践内容和行为的良好分离,我们不仅会从更顺畅的退化方面获得实际好处,而且还可以从分离方面进行思考的优势。由于我们已经将HTML和JavaScript分开了,而不是将它们组合在一起,而是当我们查看HTML时,不太可能忘记其核心函数应该描述页面的内容,而不是独立于任何脚本。

安迪·克拉克(Andy Clarke)指的是网络标准的琐事,这是一个有用的类比,一个琐事看起来像一个好的网站应该:当您看碗时,您可以看到所有组成甜点的单独层。相反的情况可能是水果蛋糕:当您看蛋糕时,您无法分辨每种不同的成分是什么。您只能看到一块蛋糕。

> 讨论

>重要的是要注意,当您将事件处理程序绑定到这样的元素时,直到元素实际存在之前,您才能做到这一点。如果将上一个脚本放在页面的头部部分中,则它将报告错误并且无法正常工作,因为在处理脚本时尚未呈现内容div。

>最直接的解决方案是将代码放入加载事件处理程序中。它总是很安全,因为在文档完全渲染之后,加载事件才发射: 或更清楚,有更多的打字:

<script type="text/javascript"> <br>
function saySomething(message) <br>
{ <br>
  alert(message); <br>
} <br>
saySomething('Hello world!'); <br>
</script>

加载事件处理程序的问题是,页面上只有一个脚本可以使用它。如果两个或多个脚本试图安装加载事件处理程序,则每个脚本将覆盖之前的处理程序。解决此问题的方法是以更现代的方式响应负载事件。我们将很快在“在同一页面上使用多个脚本工作”的部分中查看。

使用牙套和分号(一致的编码实践) 在许多JavaScript操作中,括号和半柱都是可选的,因此,当它们不是必需的时,包括它们是否有任何价值?
解决方案

>尽管括号和半龙通常是可选的,但您应该始终包括它们。这使得代码更易于阅读 - 其他人以及将来您自己都可以帮助您避免在脚本中重复使用和重组代码时避免问题(这通常会呈现出可选的Semicolon Essential。 例如,此代码是完全有效的: 由于JavaScript解释器中的一个名为Semicolon插入的过程,此代码是有效的。每当解释器找到两个由一个或多个线路分离的代码片段时,如果它们在一条线上,这些片段就不会有意义,那么解释器就会对待它们,就像它们之间存在半分离龙一样。通过类似的机制,即使不存在,通常可以从语法中推断出要在if-else语句中执行的代码的括号,即使它们不存在。将此过程视为解释器,为您添加缺少的代码元素。

> 即使这些代码元素并不总是必要的,即使在需要时使用它们,也更容易记住它们,并且易于读取结果代码,如果您确实使用它们。

我们上面的示例会更好地写下:

此版本代表代码可读性中的终极:
<ul > <br>
  <li><a href="/">Home</a></li> <br>
  <li><a href="/about/">About</a></li> <br>
  <li><a href="/contact/">Contact</a></li> <br>
</ul> <br>
 <br>
<script type="text/javascript" src="menu.js"></script>

使用函数文字

<script type="text/javascript" src="menu.js"></script> <br>
 <br>
<noscript> <br>
  <ul> <br>
    <li><a href="/">Home</a></li> <br>
    <li><a href="/about/">About</a></li> <br>
    <li><a href="/contact/">Contact</a></li> <br>
  </ul> <br>
</noscript>
>随着您对JavaScript语言的复杂性的经验,您将使用函数文字根据需要创建匿名函数并将其分配给JavaScript变量和对象属性很普遍。在这种情况下,函数定义应遵循半隆,该函数终止变量分配:

>
<div  <br>
    onmouseover="this.style.borderColor='red'" <br>
    onmouseout="this.style.borderColor='black'">
>

var saymething = function(message)> {  ...

};

>将脚本添加到页面

>在脚本开始做令人兴奋的事情之前,您必须将其加载到网页中。有两种技术可以做到这一点,其中一种比另一种技术要好得多。>

解决方案

>正如我们之前看到的那样,第一个也是最直接的技术是直接在脚本元素中编写代码:
>
<script type="text/javascript"> <br>
function saySomething(message) <br>
{ <br>
  alert(message); <br>
} <br>
saySomething('Hello world!'); <br>
</script>

这种方法的问题是,在旧版和仅文本浏览器中 - 那些根本不支持脚本元素的浏览器 - 内容可以用作文字文本。

>

避免此问题的更好替代方案始终将脚本放在外部JavaScript文件中。这就是外观:

<ul > <br>
  <li><a href="/">Home</a></li> <br>
  <li><a href="/about/">About</a></li> <br>
  <li><a href="/contact/">Contact</a></li> <br>
</ul> <br>
 <br>
<script type="text/javascript" src="menu.js"></script>

这将加载一个名为What-IS-JavaScript.js的外部JavaScript文件。该文件应包含您否则将其放入脚本元素中的代码,例如:

>
<script type="text/javascript" src="menu.js"></script> <br>
 <br>
<noscript> <br>
  <ul> <br>
    <li><a href="/">Home</a></li> <br>
    <li><a href="/about/">About</a></li> <br>
    <li><a href="/contact/">Contact</a></li> <br>
  </ul> <br>
</noscript>

>使用此方法时,浏览脚本元素的浏览器将忽略它,也不会渲染任何内容(因为该元素为空),但是浏览器的浏览器确实会加载和处理脚本。这有助于将脚本和内容分开,并且更容易维护 - 您可以在多个页面上使用相同的脚本,而无需在多个文档中维护代码的副本。

讨论

>您可能会质疑不直接在脚本元素中使用代码的建议。 “没问题,”您可能会说。 “我只是将HTML评论围绕着。”好吧,我必须不同意这一点:使用HTML评论“隐藏”代码是一个非常不好的习惯,我们应该避免陷入。

>

围绕代码添加html注释

>验证解析器不需要阅读评论,更不用说处理它们了。评论JavaScript完全有效的事实是一种过时的,这是对旧的,过时的实践的回归,该实践对文档的假设可能是不真实的:它假设该页面被用于非验证的解析器。>

本书中的所有示例均在HTML中(与XHTML相反)提供,因此,如果您使用XHTML(正确地使用MIME类型的应用程序/XHTML XML),则可以通过验证XML的文档录制的案件,该案件在BROSSER的情况下进行了验证,因此可以通过验证XHTML的评论来确定代码中的评论。为了确保向前的兼容性(以及对您自己的编码习惯的相关好处以及对单个项目的相关好处),我强烈建议您避免以这种方式在代码周围发表评论。您的JavaScript应始终包含在外部JavaScript文件中。

>

语言属性

不再需要语言属性。在Netscape 4及其同时代人是主要的浏览器的日子里,<script> TAG的语言属性具有嗅探以获得上层支持的作用(例如,通过指定JavaScript1.3),并影响了脚本解释器工作方式的小方面。<p>>但要指定JavaScript版本的JavaScript是eCmascript,并且语言属性已被弃用以替代类型属性。此属性指定了随附的文件的MIME类型,例如脚本和样式表,并且是您唯一需要使用的文件:</script>

>
<script type="text/javascript"> <br>
function saySomething(message) <br>
{ <br>
  alert(message); <br>
} <br>
saySomething('Hello world!'); <br>
</script>
从技术上讲,该值应该是文本/ecmascript,但是Internet Explorer不明白这一点。就个人而言,如果这样做,我会更快乐,仅仅是因为JavaScript(具有讽刺意味的)我很难键入一个字 - 我丢失了脚本失败的次数,因为我输入了type =“ text/javsacript”。

获得多个脚本可以在同一页面上工作

>当多个脚本无法一起使用时,几乎总是因为脚本想在给定元素上为同一事件分配事件处理程序。由于每个元素对于每个事件都只能具有一个处理程序,因此脚本互相覆盖彼此的事件处理程序。

解决方案

通常的怀疑是窗口对象的加载事件处理程序,因为页面上只有一个脚本可以使用此事件。如果两个或多个脚本正在使用它,那么最后一个将覆盖它之前的脚本。

>

我们可以从单个负载处理程序内调用多个功能,例如:

>

>但是,如果我们使用了此代码,我们将与一件代码绑定,我们必须在加载时完成所有需要做的一切。一个更好的解决方案将提供一种添加与其他处理程序不冲突的负载事件处理程序的方法。
<ul > <br>
  <li><a href="/">Home</a></li> <br>
  <li><a href="/about/">About</a></li> <br>
  <li><a href="/contact/">Contact</a></li> <br>
</ul> <br>
 <br>
<script type="text/javascript" src="menu.js"></script>
>

>调用以下单个功能时,它将允许我们分配任意数量的加载事件处理程序,而没有任何相互冲突:

>

该功能到位后,我们可以多次使用它:>
<script type="text/javascript" src="menu.js"></script> <br>
 <br>
<noscript> <br>
  <ul> <br>
    <li><a href="/">Home</a></li> <br>
    <li><a href="/about/">About</a></li> <br>
    <li><a href="/contact/">Contact</a></li> <br>
  </ul> <br>
</noscript>

你明白了!

<div  <br>
    onmouseover="this.style.borderColor='red'" <br>
    onmouseout="this.style.borderColor='black'">

讨论

> JavaScript包括添加(和删除)事件侦听器的方法,这些方法与事件处理程序类似,但允许多个侦听器在元素上订阅单个事件。不幸的是,Internet Explorer中的事件听众语法与其他浏览器中的语法完全不同:IE使用专有方法,而其他浏览器则实现了W3C标准。我们将经常遇到这种二分法,我们将在第13章中详细讨论基本动态HTML。

W3C标准方法称为AddeventListener:

IE方法称为attachevent:

>

如您所见,标准构造以事件的名称(没有“ ON”前缀),然后在事件发生时要调用的功能,以及控制事件冒泡的参数(请参阅第13章,基本动态HTML,有关此的更多详细信息)。 IE方法获取事件
<div  <br>
    onmouseover="changeBorder('red')" <br>
    onmouseout="changeBorder('black')">
handler

名称(包括“

on
Example 1.1. separate-content-behaviors.js (excerpt) <br>
 <br>
function changeBorder(element, to) <br>
{ <br>
  element.style.borderColor = to; <br>
}
”前缀),然后是功能的名称。

>

要将它们放在一起,我们需要添加一些测试来检查每种方法的存在,然后再尝试使用它。我们可以使用JavaScript运算符Typeof来执行此操作,该类型可以标识不同类型的数据(如“字符串”,“ number”,“ boolean”,“对象”,“ array”,“ function”,“ function”或“ undefined”)。一种不存在的方法将返回“未定义”。

>
<script type="text/javascript"> <br>
function saySomething(message) <br>
{ <br>
  alert(message); <br>
} <br>
saySomething('Hello world!'); <br>
</script>

还有一个附加的复杂性:在Opera中,可以触发多个事件侦听器的负载事件来自文档对象,而不是窗口。但是我们不能仅仅使用文档,因为这在较旧的Mozilla浏览器中不起作用(例如Netscape 6)。要绘制穿过这些怪癖的路线,我们需要测试window.addeventlistener,然后是document.addeventlistener,然后按照该顺序进行window.attachevent。

>最后,对于不支持任何这些方法的浏览器(实际上是Mac IE 5),后备解决方案是将多个老式的事件处理程序链接在一起,以便在事件发生时依次被调用。我们通过动态构建一个新事件处理程序来做到这一点,该新事件处理程序在事件发生时调用新分配的处理程序之前调用任何现有处理程序。 (这项技术是由西蒙·威利森(Simon Willison)开创的。)

<ul > <br>
  <li><a href="/">Home</a></li> <br>
  <li><a href="/about/">About</a></li> <br>
  <li><a href="/contact/">Contact</a></li> <br>
</ul> <br>
 <br>
<script type="text/javascript" src="menu.js"></script>
如果您不了解其工作原理的细节,请不要担心 - 我们将探讨第13章基本动态HTML中更详细地涉及的技术。在那里,我们将了解事件听众不仅对负载事件有用,而且对任何类型的事件驱动脚本有用。

隐藏JavaScript源代码
>如果您曾经创建过自己为之骄傲的东西,那么您将了解保护自己的知识产权的愿望。但是网络上的JavaScript本质上是一种开源语言。它以其源形式介绍浏览器,因此,如果浏览器可以运行它,一个人可以阅读它。

>网络上有一些应用程序声称提供源代码加密,但实际上,您无能为力地加密另一个编码器在几秒钟内无法解密的源代码。实际上,其中一些程序实际上会引起问题:它们通常以使其较慢,效率降低或易于破坏的方式重新格式化代码。我的建议?像瘟疫一样远离他们。

>但是,隐藏代码的愿望仍然存在。您可以做一些事情来混淆您的用户可以看到的代码,即使不是直接加密。

解决方案

已经删除了所有注释和不必要的空间的代码很难阅读,正如您可能期望的那样,从此类代码中提取单个功能的位置非常困难。以这种方式压缩您的脚本的简单技术可以剥夺除最确定的黑客外的所有方法。例如,以此代码:

<script type="text/javascript" src="menu.js"></script> <br>
 <br>
<noscript> <br>
  <ul> <br>
    <li><a href="/">Home</a></li> <br>
    <li><a href="/about/">About</a></li> <br>
    <li><a href="/contact/">Contact</a></li> <br>
  </ul> <br>
</noscript>
我们可以简单地删除不必要的空格来将该代码压缩到以下两行中:

<script type="text/javascript"> <br>
function saySomething(message) <br>
{ <br>
  alert(message); <br>
} <br>
saySomething('Hello world!'); <br>
</script>
但是,请记住那个重要的词 - 不必要。某些空格是必不可少的,例如var和typeof之后的单个空间。

>

讨论 这种做法除了混淆的好处外,还具有很高的优势。剥夺了评论和不必要的白道的脚本较小;因此,它们的加载速度更快,并且可能会更快地处理。

>

>但请记住,该代码必须使用半隆线终止器和牙套进行严格格式(如我们在“使用括号和半隆(一致的编码实践)”部分所讨论的那样));否则,删除线路断裂将使代码线一起运行,并最终导致错误。

>开始压缩之前,请记住制作脚本的副本。我知道这似乎很明显,但是我已经犯了很多次,而且要变得如此小,这更加艰巨!这些天我要做的是以完全间隔和评论的形式编写和维护脚本,然后在发布之前通过大量搜索/替换表达式运行它们。通常,我保留两个脚本的副本,命名为myScript.js和myScript-commented.js或类似的内容。

>

>我们将在第20章中回到这个主题,以保持步伐,在这里我们将在提高脚本的速度和效率的一系列技术中进行讨论,并减少所需的物理空间。

调试脚本

调试是查找和(希望)修复错误的过程。大多数浏览器都内置了某种错误报告,并且几个外部辩论者也值得研究。

了解浏览器的内置错误报告

Opera,Mozilla浏览器(例如Firefox)和Internet Explorer都内置了不错的错误报告功能,但是Opera和Mozilla的调试工具是最有用的。
>

opera

从工具>高级> JavaScript控制台打开JavaScript控制台。您还可以通过转到工具>“偏好>高级>内容”时将其设置为自动打开,然后单击JavaScript选项按钮以打开其对话框,并在错误时检查Open JavaScript Console。

firefox和其他Mozilla浏览器

> 从工具> JavaScript控制台打开JavaScript控制台。 Windows的Internet Explorer

转到工具> Internet选项>高级并取消选中选项禁用脚本调试,然后检查选项显示有关每个脚本错误的通知,以在发生错误时弹出一个对话框。 Mac


Mac

的Internet Explorer 转到Explorer>“首选项”> Web浏览器> Web内容,然后检查显示脚本错误警报选项。

> Safari默认不包括错误报告,但是最近的版本具有“秘密”调试菜单,包括JavaScript控制台,您可以通过输入以下终端命令来启用该菜单。 ($代表命令提示

<script type="text/javascript"> <br>
function saySomething(message) <br>
{ <br>
  alert(message); <br>
} <br>
saySomething('Hello world!'); <br>
</script>
>您还可以使用称为Safari增强剂的扩展程序,该扩展程序包括将JavaScript消息转移到Mac OS控制台的选项;但是,这些消息不是很有帮助。

>

了解各种浏览器的控制台消息可能需要一些练习,因为每个浏览器都提供了如此不同的信息。这是一个错误的示例 - 错误的函数调用:

Firefox提供了一个简洁但非常准确的报告,其中包括发生错误的行号,以及描述,如图1.1所示,“ Firefox中的JavaScript错误控制台”。
<ul > <br>
  <li><a href="/">Home</a></li> <br>
  <li><a href="/about/">About</a></li> <br>
  <li><a href="/contact/">Contact</a></li> <br>
</ul> <br>
 <br>
<script type="text/javascript" src="menu.js"></script>

>图1.1。 firefox 脚本更智能:从头开始的质量JavaScript
中的JavaScript错误控制台 如图1.2所示,“歌剧中的JavaScript控制台”说明了Opera提供了极其详细的报告,包括回溯到该错误发起的事件,发生在该行发生的线路的通知以及描述。 当在其他代码最初调用的代码中发生错误时,回溯有助于;例如,事件处理程序调用一个函数,该函数继续调用第二个功能,而在这一点上发生了错误。 Opera的控制台将通过每个阶段追溯此过程到其原始事件或呼叫。 > Internet Explorer提供了相当基本的报告,如图1.3所示,“ Windows IE中的JavaScript控制台”。它提供了解释器遇到错误的行数(这可能与实际问题的真实位置接近),以及错误类型的摘要,尽管它没有解释错误本身的细节。 (Internet Explorer在位于外部JavaScript文件中的错误方面特别糟糕。通常,它会报告的行号实际上是将脚本加载到HTML文件中的行的数量。)

>图1.2。 opera

中的JavaScript控制台

脚本更智能:从头开始的质量JavaScript>图1.3。 Windows中的JavaScript控制台IE
>您可能会收集到的,我对Internet Explorer的错误报告并没有给我留下深刻的印象,但是它总比没有好:至少您知道发生了错误。

使用警报

警报功能是分析错误的一种非常有用的方法 - 您可以在脚本中的任何时候使用它来探测对象和变量,以查看它们是否包含您期望的数据。例如,如果您的函数具有多个条件分支,则可以在每个条件中添加一个警报以找出正在执行的:

<script type="text/javascript"> <br>
function saySomething(message) <br>
{ <br>
  alert(message); <br>
} <br>
saySomething('Hello world!'); <br>
</script>

也许多年来的价值不会像应该一样回到数字。您可以将脚本的开始添加到一个警报,该警报测试变量以查看其是什么类型:>

从理论上讲,您可以在警报对话框中放置任何数量的信息,尽管很长的数据可能会创建如此宽的对话框,以至于某些信息将被删除或窗口外面。您可以通过使用逃生字符格式化输出,例如n段中断。
<ul > <br>
  <li><a href="/">Home</a></li> <br>
  <li><a href="/about/">About</a></li> <br>
  <li><a href="/contact/">Contact</a></li> <br>
</ul> <br>
 <br>
<script type="text/javascript" src="menu.js"></script>
使用try-catch

> try-catch构造是获取脚本以“尝试某些东西”的一种非常有用的方法,使您可以处理可能导致的任何错误。基本结构看起来像这样:

>如果您不确定错误来自哪里,则可以在非常大的代码块上包裹一个试用器以捕获一般故障,然后将其拧紧,然后在该块内逐渐较小的代码块拧紧。例如,您可以在函数的上半部分(在代码的方便点),然后在下半部分布试用撑杆,以查看错误的发生位置;然后,您可以在方便的位置再次将嫌疑人一半划分为一半,然后继续前进,直到您隔离了有问题的线。

<script type="text/javascript" src="menu.js"></script> <br>
 <br>
<noscript> <br>
  <ul> <br>
    <li><a href="/">Home</a></li> <br>
    <li><a href="/about/">About</a></li> <br>
    <li><a href="/contact/">Contact</a></li> <br>
  </ul> <br>
</noscript>
>通常,我使用一个for-In迭代器来贯穿整个对象,并找出它说的内容:

<div  <br>
    onmouseover="this.style.borderColor='red'" <br>
    onmouseout="this.style.borderColor='black'">
写入页面或窗口

>如果您在调试时正在检查大量数据,或者要处理以复杂方式格式化的数据,那么将数据直接写入页面或弹出窗口通常比尝试处理大量警报对话框要好。如果您在循环中检查数据,特别是您最终可能会产生数百个对话框,每个对话都必须手动解散?一个非常乏味的过程。
<div  <br>
    onmouseover="changeBorder('red')" <br>
    onmouseout="changeBorder('black')">
> 在这种情况下,我们可以使用元素的InnerHTML属性将数据写入页面。这是一个示例,我们在其中使用数组的内容(数据)构建列表,然后将其写入测试div:>

>我们还可以将数据写入弹出窗口,如果没有方便的位置将其放在页面上很有用:

>您可以根据自己喜欢的方式格式化输出,并以任何方式构建数据,以使您更容易找到错误。

>
Example 1.1. separate-content-behaviors.js (excerpt) <br>
 <br>
function changeBorder(element, to) <br>
{ <br>
  element.style.borderColor = to; <br>
}
>使用少量数据时,您可以通过将数据写入主要标题元素来获得类似的优势:

<script type="text/javascript"> <br>
function saySomething(message) <br>
{ <br>
  alert(message); <br>
} <br>
saySomething('Hello world!'); <br>
</script>

在跟踪连续或迅速变化的数据时,这种最终方法最有用,例如由setInterval函数处理的值(异步计时器我们将在第14章,时间和运动中正确碰到)。

>)。

使用外部调试器

我可以推荐两个辩论者:

    Mozilla和Firefox
  • > Venkman Windows Internet Explorer的Microsoft Script Debugger
  • > Microsoft脚本调试器
  • >外部调试者是分析您的脚本的一种更详细的方法,并且比其浏览器内部的功能更大。外部辩论者可以做一些事情,例如停止在特定点停止执行脚本,或者观看特定的属性,以便您知道对它们的任何更改,但是可能会导致。它们还包含允许您按行“逐步浏览”代码的功能,以便帮助您找到可能仅短暂发生或其他难以隔离的错误。
>

>外部调试者是复杂的软件,开发人员可能需要花费一些时间来学习如何正确使用它们。它们对于突出逻辑错误非常有用,并且本身就是学习工具的有价值,但是它们的能力有限,可以帮助浏览器不兼容:只有当您要寻找的错误是在调试器支持的浏览器中,它们才有用!

严格警告

如果您在Firefox中打开JavaScript控制台,您会发现它包含显示错误和警告的选项。警告通知您代码,尽管它本身不是错误的,但确实依赖于自动错误处理,使用弃用语法,或者以其他方式对Ecmascript规范不真实。 (要查看这些警告,可能有必要通过在地址中输入有关以下地址来启用严格的报告:config and javaScript.options.strict to true。)
例如,可变水果在下面的代码中进行了两次定义:

>

>我们应该省略第二个var,因为VAR用于首次声明变量,我们已经完成了。图1.4,“ Firefox中的JavaScript警告控制台”显示了JavaScript控制台如何突出我们的错误作为警告。

<ul > <br>
  <li><a href="/">Home</a></li> <br>
  <li><a href="/about/">About</a></li> <br>
  <li><a href="/contact/">Contact</a></li> <br>
</ul> <br>
 <br>
<script type="text/javascript" src="menu.js"></script>

>图1.4。 firefox脚本更智能:从头开始的质量JavaScript
中的JavaScript警告控制台 有几种编码错误可能会引起这样的警告。例如:

  • >重新删除变量 - 如我们刚刚看到的。
  • >一开始就没有声明变量 - 此疏忽会产生“指定为未宣布的变量名称”的警告。 例如,如果我们的代码的第一行读取果实='Mango'; ,则可能会出现。
  • 假设存在一个对象 - 此假设会产生警告“对未定义属性名称”的警告。
  • 例如,例如(document.getElementById)的测试条件假设存在getElementById方法,并且基于以下事实:JavaScript的自动错误处理能力将不存在此方法不存在的浏览器中的false方法转换为false。为了在不看到警告的情况下达到相同的目的,我们会更具体地使用IF(typeof document.getElementById!='undefined')。
  • >也有一些与功能相关的警告,以及其他一系列其他警告,其中包括我个人最喜欢的“无用表达”,这是由函数中无用的陈述产生的:
>

为了彻底介绍该主题,我建议Alex Vincent的文章解决JavaScript严格警告。

警告在某种意义上并不能阻止我们的脚本工作,但要避免警告有助于我们采用更好的编码实践,这最终会带来效率优势。例如,如果没有严格的警告,脚本在Mozilla中运行得更快,这是我们在第20章中再次研究的主题,以保持步伐。
<script type="text/javascript"> <br>
function saySomething(message) <br>
{ <br>
  alert(message); <br>
} <br>
saySomething('Hello world!'); <br>
</script>

键入转换测试

>尽管我们不应该依靠类型转换来测试可能不确定的值,但是对于可能为null的值来说,这样做是完全可以的,因为ecmascript规范要求null评估为false。因此,例如,已经使用如上图所示的使用类型运算符建立了GetElementById的存在,从那时起,它是完全安全的,以测试单个元素,如下所示,因为GetElementById返回了DOM中的不存在的元素:

摘要

>在本章中,我们讨论了脚本的最佳实践方法,这些方法将使我们的代码易于阅读和管理,并允许其在不支持的设备中优雅地降级。我们还开始介绍一些我们需要构建有用脚本的技术,包括无处不在的负载事件侦听器,我们将用于本书中的几乎每个解决方案! >我们已经介绍了一些非常高级的东西,所以不用担心一些很难接受。我们将回到我们在此处介绍的所有概念和技巧,因为我们在其余的章节中进行。

<ul > <br>
  <li><a href="/">Home</a></li> <br>
  <li><a href="/about/">About</a></li> <br>
  <li><a href="/contact/">Contact</a></li> <br>
</ul> <br>
 <br>
<script type="text/javascript" src="menu.js"></script>
第5章。导航文档对象模型

浏览器通过文档对象模型(DOM)为JavaScript程序访问网页上的元素 - 标题,段落,列表,列表,样式,ID,类,类和所有其他数据的内部表示。

可以将DOM视为由互连节点组成的树。 HTML文档中的每个标签均由节点表示;嵌套在该标签中的任何标签都是与儿童相连的节点,或树上的分支。这些节点中的每一个称为元素节点。 (严格地说,每个元素节点代表一对标签 - 元素的开始和结束标签(例如

) - 或一个单个自关闭标签(例如,xhtml中的

)。最有用的是文档节点,文本节点和属性节点。文档节点代表文档本身,是DOM树的根。文本节点表示元素标签之间包含的文本。属性节点表示元素开放标签中指定的属性。考虑此基本HTML页面结构:

<script type="text/javascript"> <br>
function saySomething(message) <br>
{ <br>
  alert(message); <br>
} <br>
saySomething('Hello world!'); <br>
</script>
此页面的DOM可以看到如图5.1,“简单的HTML页面的DOM结构,可视化为树层次结构”。

>

每个页面都有一个文档节点,但是其后代是从文档本身的内容中得出的。通过使用元素节点,文本节点和属性节点,可以通过JavaScript访问页面上的每条信息。

不过,

不仅限于HTML和JavaScript。 W3C DOM规范网站的解释是如何解释此问题的:

文档对象模型是平台和语言中立的接口,它将允许程序和脚本动态访问和更新文档的内容,结构和样式。 因此,即使JavaScript和HTML的混合物是利用DOM的最常见组合的混合物,您从本章中获得的知识可以应用于许多不同的编程语言和文档类型。 为了使您成为“域的主人”,本章将解释如何在网页上找到您要查找的任何元素,然后更改它,重新布置或完全删除。

图5.1。简单的HTML页面的DOM结构,可视化为树层次结构

>

>访问元素脚本更智能:从头开始的质量JavaScript
访问提供控制,控制是电源,而您是电源程序员,对吗?因此,您需要访问网页上的所有内容。幸运的是,JavaScript可让您仅使用几个方法和属性访问页面上的任何元素。>

解决方案

>尽管可以像路线图这样的HTML文档浏览吗?从家里开始,一次朝着目标一个节点进行工作?这通常是找到元素的效率低下的一种方法,因为它需要大量代码,并且文档结构的任何更改通常意味着您必须重写脚本。如果您想快速而轻松地找到一些东西,则应该在手的背面纹身的方法是document.getElementById。

>假设您已经有正确的标记,getElementById将允许您通过其唯一的ID属性值访问任何元素。例如,想象一下您的网页包含此代码:>

>您可以使用A元素的ID属性来直接访问该元素本身:>
<script type="text/javascript"> <br>
function saySomething(message) <br>
{ <br>
  alert(message); <br>
} <br>
saySomething('Hello world!'); <br>
</script>

>变量ElementRef的值现在将引用到a元素 - 您在ElementRef上执行的任何操作都会影响该精确的超链接。

<ul > <br>
  <li><a href="/">Home</a></li> <br>
  <li><a href="/about/">About</a></li> <br>
  <li><a href="/contact/">Contact</a></li> <br>
</ul> <br>
 <br>
<script type="text/javascript" src="menu.js"></script>
从名称可以看出,getElementsbytagname取标签名称并返回该类型的所有元素。假设我们有此HTML代码:

>

<script type="text/javascript" src="menu.js"></script> <br>
 <br>
<noscript> <br>
  <ul> <br>
    <li><a href="/">Home</a></li> <br>
    <li><a href="/about/">About</a></li> <br>
    <li><a href="/contact/">Contact</a></li> <br>
  </ul> <br>
</noscript>
我们可以检索包含每个超链接的集合,例如:

>

<div  <br>
    onmouseover="this.style.borderColor='red'" <br>
    onmouseout="this.style.borderColor='black'">
>变量锚的值现在是元素的集合。集合类似于数组,因为使用方括号表示集合中的每个项目都在集合中引用,并且这些项目以数字索引从零开始。 getElementsbytagname返回的集合按元素顺序对元素进行分类,因此我们可以参考每个链接:

>

<div  <br>
    onmouseover="changeBorder('red')" <br>
    onmouseout="changeBorder('black')">
使用此集合,您可以通过元素迭代并在其上执行操作,例如使用元素Nodes的className属性分配类:

与getElementById不同,只能在文档节点上调用,getElementsBytagName方法可从每个元素节点获得。您可以通过在特定元素上执行getElementsBytagname方法的范围。 getElementsBytaGname只会返回元素,这些元素是该方法所在的元素的后代。
Example 1.1. separate-content-behaviors.js (excerpt) <br>
 <br>
function changeBorder(element, to) <br>
{ <br>
  element.style.borderColor = to; <br>
}

如果我们有两个列表,但要将新类分配给一个列表中的链接,我们可以通过在其父母列表上调用getElementsbytagname来专门针对这些元素:

>
<div >

为了定位恒星列表,我们需要获得对父元素元素的引用,然后直接在其上拨打getElementsbytagname:

变量星人的值将是无序列表中星星中的A元素的集合,而不是页面上所有A元素的集合。>
Example 1.2. separate-content-behaviors.js <br>
 <br>
function changeBorder(element, to) <br>
{ <br>
  element.style.borderColor = to; <br>
} <br>
 <br>
var contentDiv = document.getElementById('content'); <br>
 <br>
contentDiv.onmouseover = function() <br>
{ <br>
  changeBorder('red'); <br>
}; <br>
 <br>
contentDiv.onmouseout = function() <br>
{ <br>
  changeBorder('black'); <br>
};

dom 0 collections

window.onload = function() <br>
{ <br>
  var contentDiv = document.getElementById('content'); <br>
 <br>
  ... <br>
};
HTML文档中的许多“特殊”元素可以通过更直接的方式访问。文档的身体元素可以作为文档访问。文档中所有表格的集合可以在文档中找到。文档中的所有图像都可以在document..images中找到。

> >

实际上,这些集合中的大多数自从DOM被W3C标准化之前就已经存在,通常称为DOM 0属性。

>由于这些功能的初始实现不是标准化的,因此这些集合在朝着标准符合性方面的浏览器中证明是不可靠的。例如,一些Mozilla浏览器的早期版本(例如,Firefox)不支持XHTML文档上的这些收藏。

今天的浏览器通常在支持这些收藏方面做得很好;但是,如果您确实遇到了问题,那么值得尝试使用更多的详细getElementsbytagname方法来访问相关元素。例如,您可以使用:

,而不是文档。

var body = document.getElementsbytagname(“ body”)[0];

讨论

如果您确实需要按元素逐步浏览DOM层次结构元素,则每个节点都有几个属性,使您能够访问相关的节点:

> node.ChildNodes - 一个包含对指定节点的每个孩子的源订单引用的集合,包括元素和文本节点

>

> node.firstchild - 指定节点的第一个子节点

> node.lastchild - 特定节点的最后一个子节点
  • > node.parentnode - 指定节点的父元素的引用
  • > node.nextsibling - 文档中的下一个节点,其父母与指定的节点
  • 具有相同的父
  • > node.previoussibling - 以前的元素与指定节点
  • 相同的级别
  • >如果特定节点不存在这些属性(例如,父的最后一个节点将没有下一个兄弟姐妹),则它们的值为null。
  • 看这个简单的页面:
  • 可以使用以下任何表达式引用带有ID star2的列表项目:>

whitespace节点

>
<script type="text/javascript"> <br>
function saySomething(message) <br>
{ <br>
  alert(message); <br>
} <br>
saySomething('Hello world!'); <br>
</script>
一些浏览器将在任何从文本字符串(例如HTML文件)中解释的元素结构中的元素节点之间创建空格节点。空格节点是仅包含Whitespace(Tabs,Space,New Lines)的文本节点,以帮助将其写入源文件中的代码进行格式化。

> 当您使用上述属性通过节点遍历DOM节点时,应始终允许这些空间节点。通常,这意味着检查您检索到的节点是一个元素节点,而不仅仅是一个分开元素的空格节点。
<ul > <br>
  <li><a href="/">Home</a></li> <br>
  <li><a href="/about/">About</a></li> <br>
  <li><a href="/contact/">Contact</a></li> <br>
</ul> <br>
 <br>
<script type="text/javascript" src="menu.js"></script>

>有两种简单的方法来检查节点是元素节点还是文本节点。文本节点的nodeName属性将始终为“ #text”,而元素节点的nodeName将识别元素类型。但是,在区分文本节点和元素节点时,更容易选中nodeType属性。元素节点具有1个

的结节,而文本节点的结节为3。您可以在检索元素时将此知识用作测试:

>示例5.9。 Access_Element4.js(摘录)
 
var star2 = document.getElementById(“ star1”)。sextsibling;  
 
while(star2.nodeType ==“ 3”)
{
 star2 = star2.nextsibling;  
}

使用这些域属性,有可能在根HTML元素上开始您的旅程,并最终被埋葬在某些深nested Fieldset的传说中吗?这只是遵循节点的问题。

>
创建元素和文本节点
JavaScript

>不仅有能力修改DOM中的现有元素;它还可以创建新元素并将它们放置在页面结构中。

解决方案

<script type="text/javascript"> <br>
function saySomething(message) <br>
{ <br>
  alert(message); <br>
} <br>
saySomething('Hello world!'); <br>
</script>
<ul > <br>
  <li><a href="/">Home</a></li> <br>
  <li><a href="/about/">About</a></li> <br>
  <li><a href="/contact/">Contact</a></li> <br>
</ul> <br>
 <br>
<script type="text/javascript" src="menu.js"></script>
变量新建商将是一个新的A元素,准备插入页面。

>用XML Mime Type

指定文档中的命名空间

>如果您要编码JavaScript,以用于使用MIME类型的应用程序/XHTML XML(或其他某些XML MIME类型),则应使用方法createElementns,而不是CreateElement,以指定namespace的名称空间:您要为哪个元素:

<script type="text/javascript" src="menu.js"></script> <br>
 <br>
<noscript> <br>
  <ul> <br>
    <li><a href="/">Home</a></li> <br>
    <li><a href="/about/">About</a></li> <br>
    <li><a href="/contact/">Contact</a></li> <br>
  </ul> <br>
</noscript>

>

<div  <br>
    onmouseover="this.style.borderColor='red'" <br>
    onmouseout="this.style.borderColor='black'">
>

此区别适用于许多DOM方法,例如Removelement/RemoveElementns和GetAttribute/getAttributens;但是,我们不会在本书中使用这些方法的命名空间增强版。 Simon Willison

<div  <br>
    onmouseover="changeBorder('red')" <br>
    onmouseout="changeBorder('black')">
简要说明了与JavaScript和他的网站上不同的MIME类型一起工作。

元素内部的文本实际上是该元素的儿童文本节点,因此必须单独创建它。文本节点与元素节点不同,因此它们具有自己的创建方法,createTextNode:>

如果您正在修改现有文本节点,则可以通过NodeValue属性访问其包含的文本。这使您可以在文本节点中获取并设置文本:

变量oldText的值现在为“ monoceros”,文本节点内的文本现在为“ pyxis”。
Example 1.1. separate-content-behaviors.js (excerpt) <br>
 <br>
function changeBorder(element, to) <br>
{ <br>
  element.style.borderColor = to; <br>
}
>

>您可以使用其附录方法将元素节点或文本节点插入现有元素的最后一个孩子。此方法将在所有现有的孩子之后放置新节点。

考虑html的这个片段: 我们可以使用DOM方法在段落结束时创建和插入另一个链接:
<script type="text/javascript"> <br>
function saySomething(message) <br>
{ <br>
  alert(message); <br>
} <br>
saySomething('Hello world!'); <br>
</script>

变量纽子的值将是对新插入的元素的引用。

>

如果我们要在此代码执行HTML代码后翻译DOM的状态,则看起来像这样:>

<ul > <br>
  <li><a href="/">Home</a></li> <br>
  <li><a href="/about/">About</a></li> <br>
  <li><a href="/contact/">Contact</a></li> <br>
</ul> <br>
 <br>
<script type="text/javascript" src="menu.js"></script>
>我们没有为新元素指定任何属性,因此它目前尚未链接。在“读取和编写元素的属性”部分中,不久将解释了指定属性的过程。

>

讨论

有三种基本方法可以将新元素或文本节点插入到网页中。您使用的方法将取决于您希望将新节点插入的点:作为元素的最后一个孩子,在另一个节点之前或作为节点的替换。上面解释了像最后一个孩子一样附加元素的过程。您可以使用其父元素的插入方法在现有节点之前插入节点,并且可以使用其父元素的替换方法替换节点。>

为了使用插入,您需要对要插入的节点以及您希望插入的节点进行引用。考虑此HTML代码:

>我们可以通过从其父元素(段落)调用插入之前插入一个新链接:
<script type="text/javascript" src="menu.js"></script> <br>
 <br>
<noscript> <br>
  <ul> <br>
    <li><a href="/">Home</a></li> <br>
    <li><a href="/about/">About</a></li> <br>
    <li><a href="/contact/">Contact</a></li> <br>
  </ul> <br>
</noscript>
>

变量纽子的值将是对新插入的元素的引用。
<div  <br>
    onmouseover="this.style.borderColor='red'" <br>
    onmouseout="this.style.borderColor='black'">
>

如果我们要在此操作后转化为html DOM的状态,则看起来像这样:

而是,我们可以使用替代技术完全替换现有链接:>

<div  <br>
    onmouseover="changeBorder('red')" <br>
    onmouseout="changeBorder('black')">
dom然后看起来像这样:

>

Example 1.1. separate-content-behaviors.js (excerpt) <br>
 <br>
function changeBorder(element, to) <br>
{ <br>
  element.style.borderColor = to; <br>
}

更改元素的类型
<div >

>您的订购列表是否有些无序?您的标题有令人羡慕的段落吗?使用一些JavaScript知识,可以完全更改元素的类型,同时保留其孩子的结构。

解决方案

>没有直接,简单的方法来更改元素的类型。为了实现这一壮举,您必须执行一些杂耍表演。

>假设我们想将此段落更改为div:>

我们需要创建一个新的div,将每个段落的孩子都移入其中,然后将新元素交换为旧元素:

>这里唯一的陌生线应该是为每个段落的孩子创建克隆的点。 Clonenode方法产生了所谓的节点的相同副本。通过传递此方法,论点是正确的,我们指出,我们希望该元素的所有孩子与元素本身一起复制。使用CloneNode,我们可以在新的Div下镜像原始元素的孩子,然后在我们复制完成后删除段落。>在某些情况下,克隆节点很有用,但事实证明,有一种更干净的方法可以解决此特定问题。我们可以简单地将现有段落的子节点移至新的Div。 DOM节点一次只能属于一个父元素,因此将节点添加到DIV中也将其从段落中删除:

>

<script type="text/javascript"> <br>
function saySomething(message) <br>
{ <br>
  alert(message); <br>
} <br>
saySomething('Hello world!'); <br>
</script>
>

请注意更改DOM 的节点结构 >

集合中的元素在DOM中发生更改时会自动更新 - 即使您在更改发生之前将该集合复制到变量中。因此,如果您从DOM中删除了您一直在工作的集合中包含的元素,则该元素参考也将从集合中删除。这将改变集合的长度以及在删除元素后出现的任何元素的索引。 当执行影响DOM节点结构的操作(例如将节点移至新父元素)时,您必须谨慎对待迭代过程。上面的代码使用一个仅访问段落的第一个孩子的W循环,因为每次重新定位孩子时,子诺德斯集合的长度都会减少一个,并且集合中的所有元素都会随身携带。一个带有计数器变量的循环无法正确处理所有孩子,因为它假设该集合的内容在整个循环中保持不变。

讨论

>没有简单的方法将元素的属性复制到其替换。 (如果您查看DOM规范,则看起来好像是。不幸的是,Internet Explorer对相关属性和方法的支持只是不符合任务。)如果您希望新元素具有相同的ID,类,HREF等,则必须以手动复制该值:>>>

>>

>> >

删除元素或文本节点

>一旦元素已经超过了其实用性,就该给它切碎了。您可以使用JavaScript从DOM删除任何元素。
<ul > <br>
  <li><a href="/">Home</a></li> <br>
  <li><a href="/about/">About</a></li> <br>
  <li><a href="/contact/">Contact</a></li> <br>
</ul> <br>
 <br>
<script type="text/javascript" src="menu.js"></script>
>
解决方案

removechild方法从其父母那里删除了任何子节点,并返回对删除对象的引用。> 让我们从此HTML开始:

我们可以使用removechild从其父段中删除超链接,例如:

>变量删除的子将是对A元素的引用,但是该元素不会位于DOM中的任何位置:它将仅在内存中可用,就像我们刚刚使用CreateElement创建了它一样。这使我们能够将其重新安置到页面上的另一个位置,或者我们可以简单地让变量在脚本末尾消失,并且参考将完全丢失 - 有效地删除了它。遵循上述代码,DOM最终将像这样:>
<script type="text/javascript"> <br>
function saySomething(message) <br>
{ <br>
  alert(message); <br>
} <br>
saySomething('Hello world!'); <br>
</script>
当然,您无需将返回值从removechild分配给变量。您可以执行它,而完全忘记了元素:

<ul > <br>
  <li><a href="/">Home</a></li> <br>
  <li><a href="/about/">About</a></li> <br>
  <li><a href="/contact/">Contact</a></li> <br>
</ul> <br>
 <br>
<script type="text/javascript" src="menu.js"></script>

讨论

>如果要删除的元素有要保留的孩子(即,您只想通过删除父母来“解开”他们),则必须救出这些孩子,以确保在删除父母时他们留在文件中。您可以使用已经提到的插入方法来实现此目标,当在DOM中包含的元素上使用时,首先将其删除,然后在适当的点插入。

>以下html中的段落包含多个孩子:

>我们可以循环浏览段落的儿童款项,并在删除元素本身之前单独搬迁其每个孩子:

<script type="text/javascript" src="menu.js"></script> <br>
 <br>
<noscript> <br>
  <ul> <br>
    <li><a href="/">Home</a></li> <br>
    <li><a href="/about/">About</a></li> <br>
    <li><a href="/contact/">Contact</a></li> <br>
  </ul> <br>
</noscript>

该页面的DOM现在看起来像这样:

<div  <br>
    onmouseover="this.style.borderColor='red'" <br>
    onmouseout="this.style.borderColor='black'">

读写元素的属性

HTML元素中最常用的部分是其属性?它的ID,类,HREF,标题或其他一百个可以包含在HTML标签中的信息中的任何一个。 JavaScript不仅能够读取这些值,而且还可以写下它们。
<div  <br>
    onmouseover="changeBorder('red')" <br>
    onmouseout="changeBorder('black')">
>
解决方案

>存在读取和编写元素属性的两种方法。 getAttribute允许您读取属性的值,而setAttribute允许您编写它。 考虑此html:

我们将能够像这样读取元素的属性:

>

Example 1.1. separate-content-behaviors.js (excerpt) <br>
 <br>
function changeBorder(element, to) <br>
{ <br>
  element.style.borderColor = to; <br>
}
变量锚固的值将为“ antares”,变量锚定的值将为“遥远的位置”。

要更改超链接的属性,我们使用setAttribute,将其传递给要更改的属性的名称,以及我们要将其更改为:>的值

<div >
变量newtitle的值现在将“不那么遥远”。

>

讨论

Example 1.2. separate-content-behaviors.js <br>
 <br>
function changeBorder(element, to) <br>
{ <br>
  element.style.borderColor = to; <br>
} <br>
 <br>
var contentDiv = document.getElementById('content'); <br>
 <br>
contentDiv.onmouseover = function() <br>
{ <br>
  changeBorder('red'); <br>
}; <br>
 <br>
contentDiv.onmouseout = function() <br>
{ <br>
  changeBorder('black'); <br>
};
在从自由漫游的Netscape Wilderness到现代基于标准的基于标准的地形更加紧密定义的旅程中,DOM标准已经为与HTML打交道了相当多的额外语法。这些附加功能中最普遍的是dom属性和HTML属性之间的映射。

>

将文档解析为其DOM形式时,为元素的属性创建了特殊属性节点。这些节点无法作为该元素的“孩子”访问:仅通过上述两种方法才能访问它们。但是,作为对原始DOM实现的回报(称为DOM 0,零建议这些功能在标准之前出现),当前的DOM规格包含HTML特定的其他功能。特别是,属性可直接作为元素的属性访问。因此,可以通过link.getAttribute(“ href”)以及通过link.href。

>此快捷方式语法不仅更清洁,更可读性:在某些情况下,也有必要。 Internet Explorer 6及以下版本将不会通过setAttribute进行元素的视觉显示。因此,使用SetAttribute对元素的类,ID或样式进行的任何更改都不会影响其显示方式。为了使这些更改生效,必须通过元素节点的属性特定属性进行。 为了进一步混淆问题,当读取特定于属性的属性时返回的值在浏览器之间变化,这是Konqueror中最显着的变化。如果不存在属性,Konqueror将返回null作为特定于属性属性的值,而所有其他浏览器将返回一个空字符串。在更具体的情况下,一些浏览器将返回link.getAttribute(“ href”)作为绝对URL(例如,“ http://www.example.com/antares.html”),而另一些则返回实际属性值(例如,“ antares.html”)。在这种情况下,使用点属性是更安全的,因为它始终返回跨浏览器的绝对URL。

那么,解决这些问题的一般解决方案是什么?

基本规则是:如果您确定属性已被分配了一个值,则可以安全地使用点属性方法访问它。如果您不确定是否设置了属性,则应首先使用其中一种DOM方法来确保其具有值,然后使用点属性来获得其值。

读取

一个未验证的属性,请使用以下内容:>

这确保属性在获取其值之前存在,而不是null。

写入>未经验证的属性,请使用以下代码:>

此代码确保首先正确创建属性,然后以某种方式设置Internet Explorer如果属性会影响元素的可视化显示。

此规则对您可以保证的存在的属性有一些例外。这些“必备”属性中最著名的是样式和类别,对于任何给定的元素始终有效;因此,您可以立即将它们引用为dot属性(分别分别为element.Style and element.ClassName)。

>
<script type="text/javascript"> <br>
function saySomething(message) <br>
{ <br>
  alert(message); <br>
} <br>
saySomething('Hello world!'); <br>
</script>

>我们必须注意的另一个属性是标签的属性。它遵循与类相同的规则,但其属性表格为HTMLFOR。使用getAttribute/setAttribute,我们编写element.getAttribute(“ for”),但是在Internet Explorer中它的element.getAttribute(“ htmlfor”)。

>获取具有特定属性值的所有元素
当您需要修改具有相同类或标题的所有元素时,找到具有特定属性的所有元素的能力。

解决方案

为了找到具有特定属性值的元素,我们需要检查该属性页面上的每个元素。这是一个非常密集的操作,因此不应轻易进行。如果您想找到所有带有类型=“复选框”的输入元素,最好先将搜索限制为输入元素:> >这将比通过页面上的每个元素进行迭代并检查其类型所需的计算。但是,当您需要找到具有相同属性值的不同类型的元素时,此解决方案中介绍的功能是理想的。

>检查页面上的每个元素的最简单方法是循环浏览getElementsbytagname返回的集合(“*”)。这种方法的唯一问题是Internet Explorer 5.0和5.5不支持标签选择的星号通配符。幸运的是,这些浏览器支持文档。所有属性,该属性是包含页面上所有元素的数组。 getElementsByAttribute用简单的代码分支处理此问题,然后继续检查给定属性值的元素,将匹配添加到要返回的数组中:>

> getElementsbyAttribute中的许多代码都与本章前面提到的属性处理中的浏览器差异有关,该部分称为“读取和编写元素的属性”。如果所需的属性是类或用于,则使用必要的技术。作为检查类属性的匹配时,作为额外的奖励,如果元素已分配了多个类,则该函数会自动检查其中的每个类别,以查看其是否匹配所需值。
添加并删除多个类,以/从元素
组合多个类是一种非常有用的CSS技术。它通过允许在一个元素上组合多种不同的样式来提供一种非常原始的继承手段,从而使您可以在整个站点中混合和匹配不同的效果。它们在突出显示元素之类的情况下特别有用:可以添加一个类,该类可以突出显示元素而不打扰其他类可能已应用于该元素的任何其他视觉属性。但是,如果您要在JavaScript中分配类,则必须小心,不要无意间覆盖先前分配的类。

解决方案

任何元素的类可通过其className属性访问。此属性允许您既可以读写当前应用于该元素的类。因为它只是一个字符串,所以使用className最困难的部分是您需要处理它用来表示多个类的语法。

>

>元素的类名称属性中的类名是由空格分开的。第一类名称没有任何内容,最后一堂课的名称也不是任何内容。这使得可以轻松地在类列表中添加一类:只需将一个空间和新的类名称加入到ClassName的末尾。但是,您需要避免添加列表中已经存在的类名称,因为这将使删除班级更加困难。您还需要避免在className值开始时使用一个空间,因为这会在Opera 7中导致错误:>

首先,AddClass创建一个正则表达式模式,其中包含要添加的类。然后,它使用此模式测试当前的类名值。如果类名称不存在,我们会检查一个空的className值(在这种情况下,将类名称分配给属性逐字化),或者我们附加到现有值一个空间和新的类名称。

>
<script type="text/javascript"> <br>
function saySomething(message) <br>
{ <br>
  alert(message); <br>
} <br>
saySomething('Hello world!'); <br>
</script>

分开类

> 一些用于查找类的正则表达示例使用“边界特殊字符”(b)单词分开的类。但是,这将无法与所有有效的类名称(例如包含连字符的名称)一起使用。

> 删除类的过程使用的正则表达式模式与我们用来添加类的过程相同,但我们不需要执行尽可能多的检查:

>在RemoveClass在className属性值的副本上执行替换正则表达式之后,它通过删除任何尾随空间(当我们在多个类别类中删除最后一个类),然后将其分配给目标className。

>

>
<ul > <br>
  <li><a href="/">Home</a></li> <br>
  <li><a href="/about/">About</a></li> <br>
  <li><a href="/contact/">Contact</a></li> <br>
</ul> <br>
 <br>
<script type="text/javascript" src="menu.js"></script>
>

>

>
摘要

本章介绍了您需要的基本但功能强大的工具,以操纵文档对象模型。当您操纵任何网页时,重要的是要了解DOM(在浏览器中看到的所有内容)。知道如何创建,编辑和删除DOM的一部分对于理解本书的其余部分至关重要。掌握了这些技术后,您将成为一名熟练的JavaScript程序员。

第7章。使用Windows和Framames
>本章涉及简单的窗口和框架操纵,包括诸如打开弹出窗口,在帧之间进行通信(从iframe读取数据所涉及的技术),第18章将在第18章中介绍,使用JavaScript构建Web应用程序。)

>很多人觉得窗户的操纵类似于黑暗的一面。他们认为,窗口是用户GUI的一部分,而不是文档的一部分,并且由于JavaScript是文档脚本语言,因此没有业务操纵Windows。

>我通常倾向于同意,但我知道有时候意见是一种奢侈品。如果您的客户要求提供特定的东西,那么您不一定会改变他们的主意,或者自由地根据这样的原则拒绝工作。在本章中,我们将介绍一系列实用的窗口和框架操纵任务,同时对它们的使用可能引起的可用性和可访问性问题保持敏感。

> 但是,请注意,存在局限性,窗户脚本的某些品种特别不友好。我们不会处理积极的策略,例如关闭或修改用户的主要窗口,在屏幕上移动窗口,或打开全屏或“无镀”窗口。这些正是给JavaScript一个坏名称的滥用类型。

> 在本章的大部分时间里,我们将仔细研究窗口对象的属性和方法。这些都是由不同的浏览器以多种方式实施的,自JavaScript标准化以来,其中大多数已经使用。

>。

>我们将有很多代码分支要处理,但是我们会避免通过仔细使用对象检测,检测对象或功能来测试兼容性而不是检测特定浏览器的过程。

使用弹出窗口

您应该使用弹出窗口吗?我最考虑的答案是:如果您可以帮助您。弹出式窗口从营销人员对它们的积极使用中获得了糟糕的声誉,但即使要求的弹出窗口也可能是具有良好可用性的障碍。

>

>我不会说弹出窗口永远不合适,但是我会说他们很少如此。然而,在某些情况下,弹出打开新窗口可以说是最合适的解决方案:在线调查可能是一个例子,因为格式可能会使内容更平易近人; DHTML游戏是另一回事,因为视口可能需要具有已知尺寸。>

>我将通过讨论弹出窗口创建的问题,然后提供一种务实的方法来使用它们来减轻这些问题。

>弹出窗口有什么问题?

>大多数弹出窗口脚本的主要问题是他们不考虑用户的需求?它们仅满足设计师的需求。结果?我们都看过它们:

>从链接生成的弹出窗口,尽管这些链接在不可用时无能为力
    >
  • >没有状态栏的弹出窗口,因此您不一定要判断文档是否已加载或停滞,仍在加载等。
  • >弹出窗口无法使用户能够调整窗口的大小,并且无法生成可能在窗口外扩展的内容的弹出式弹出窗口
  • “镀铬”的窗口或向用户屏幕的全尺寸打开
  • 这些问题不仅是可用性的问题,而且是可访问性的问题。例如,屏幕阅读器用户可能不会被新窗口打开的设备通知。如果他们试图回到浏览器历史记录(他们不能),这显然可能会引起混乱。如果窗口全尺寸打开,则可能会发生同样的事情:您和我可能熟悉使用任务栏监视打开的窗口,但并非所有的计算机用户都是 - 他们甚至可能没有意识到新窗口已经弹出。
  • >
  • 如果您要使用弹出窗口,寻找此类问题,并且通常对其影响敏感,将使您的弹出窗口与用户更加友好,而对您的良心却更少。
>另外,请记住,从开发人员的角度来看,弹出窗口不能保证可以正常工作:现在,大多数浏览器都包含抑制弹出窗口的选项,并且在某些情况下,即使响应用户事件而生成弹出窗口,也会发生抑制。

>您可能能够像不支持脚本的情况一样允许这样做:通过确保弹出窗口的基础触发器,如果​​弹出窗口失败,仍然可以做一些有用的事情。或者,您可能会打开代码一个窗口,然后检查其自己的关闭属性,以查看它是否实际显示(我们将在下一个解决方案中查看此技术)。

>

>但是,这些方法都不能保证与每个浏览器和弹出式阻滞剂一起使用,因此,对于可用性的原因而言,避免在可能的情况下避免使用弹出窗口越来越简单。

>如何最大程度地减少问题?

我们需要做的是为弹出窗口的道德使用建立一些黄金规则:>

    确保在不可用时正确触发链接降低。
  • >
  • 始终包含状态栏。
  • 始终包含一个溢出内容的机制:允许窗口调整大小,或者允许滚动栏出现,或两者兼而有之。
  • 不要打开大于640×480像素的窗户。通过限制弹出窗口的大小,您可以确保它们在绝大多数监视器上的主要窗口小。这增加了用户意识到弹出窗口是一个新窗口的可能性。
解决方案

这是一个基于上述准则的通用弹出函数:>

以及限制窗口的大小,此脚本拒绝创建没有溢出的弹出窗口,因此,如果您不指定“滚动”,“ ressize”或“ acter”,则为溢出参数,则将使用“两者”的默认设置。

<script type="text/javascript"> <br>
function saySomething(message) <br>
{ <br>
  alert(message); <br>
} <br>
saySomething('Hello world!'); <br>
</script>
>三元运算符

>此脚本使用称为三元运算符的快捷表达式来评估每个溢出选项。三元操作员使用?和:字符划分评估的两个可能结果,相当于一对if..else条件。考虑使用此代码:

该代码等效于下面的标记:

<ul > <br>
  <li><a href="/">Home</a></li> <br>
  <li><a href="/about/">About</a></li> <br>
  <li><a href="/contact/">Contact</a></li> <br>
</ul> <br>
 <br>
<script type="text/javascript" src="menu.js"></script>
>

不需要括号,但是您可能会发现它们使表达式更易于阅读。有关此和其他有用的快捷方式的更多信息,请参见第20章,保持步伐。 >拥有弹出功能后,您可以以多种方式调用它。例如,您可以使用常规链接:

<script type="text/javascript" src="menu.js"></script> <br>
 <br>
<noscript> <br>
  <ul> <br>
    <li><a href="/">Home</a></li> <br>
    <li><a href="/about/">About</a></li> <br>
    <li><a href="/contact/">Contact</a></li> <br>
  </ul> <br>
</noscript>
如果脚本不可用,这将像其他任何链接一样起作用,但是如果可用脚本,该脚本可以触发单击事件处理程序,将其HREF传递给MakePopup功能以及其他设置。处理程序的返回值取决于窗口是否实际打开;阻止弹出窗口的浏览器将按照链接按照链接遵循:

通常,如果您有一个需要生成窗口的脚本,则可以使用url直接调用makePopup函数:

如果您需要在脚本稍后关闭该窗口,则可以使用存储的窗口参考上的关闭方法来进行:
<div  <br>
    onmouseover="this.style.borderColor='red'" <br>
    onmouseout="this.style.borderColor='black'">
>

<div  <br>
    onmouseover="changeBorder('red')" <br>
    onmouseout="changeBorder('black')">
讨论。

Example 1.1. separate-content-behaviors.js (excerpt) <br>
 <br>
function changeBorder(element, to) <br>
{ <br>
  element.style.borderColor = to; <br>
}
窗口。开机方法还可以采用许多参数(除了URL和窗口名称),该参数指定窗口是否应具有特定的装饰,例如菜单栏,工具栏或地址(位置)栏。这些参数以逗号限制的字符串传递给窗口的第三个参数。
<script type="text/javascript"> <br>
function saySomething(message) <br>
{ <br>
  alert(message); <br>
} <br>
saySomething('Hello world!'); <br>
</script>
在我们的popopup函数中,梅纳巴尔,工具栏和位置参数都是不可预见的,因为这些元素对于弹出窗口很少有用 - 毕竟它们是导航工具。弹出窗口主要用于一页接口,或不建议使用历史导航的弹出式接口,例如我们的调查示例或银行网站的登录过程。

> 如果需要,您可以更改这些参数,但是状态参数应始终设置为“是”,因为将其关闭会破坏良好的可用性。 (我知道 - 我已经提到过,但是我再说一遍,因为它很重要!)>

>可解析的参数可能没有任何效果 - 在某些浏览器中,无论是通过设计还是由于用户偏好的结果,也无法创建不可避免的窗口,即使您将此值设置为否。实际上,在Mac OS X的Opera 8中,根本不可能创建自定义大小的窗口 - 创建的窗口将显示为当前窗口中的新标签。该特定例外本身可能并不重要,但它可以说明对创建窗口属性的控制并不能绝对保证的一般点。

>

>打开新窗口后,您可以使用对象的焦点方法将其重点放在焦点中。这通常不是必需的 - 通常,默认情况下会发生 - 但是当您用多个窗口脚本脚本时,该技术可能会很有用:

或者,您可能需要打开一个弹出窗口,但将焦点保留在主窗口中(从而创建所谓的“ Popunder”)。您可以使用其模糊方法将焦点从窗口中取出:

但是,在这种情况下,您无法预测焦点将转移到下一步的位置,因此重新关注主要窗口是更可靠的:>
<ul > <br>
  <li><a href="/">Home</a></li> <br>
  <li><a href="/about/">About</a></li> <br>
  <li><a href="/contact/">Contact</a></li> <br>
</ul> <br>
 <br>
<script type="text/javascript" src="menu.js"></script>

>在新窗口中打开现场链接
<script type="text/javascript" src="menu.js"></script> <br>
 <br>
<noscript> <br>
  <ul> <br>
    <li><a href="/">Home</a></li> <br>
    <li><a href="/about/">About</a></li> <br>
    <li><a href="/contact/">Contact</a></li> <br>
  </ul> <br>
</noscript>
在HTML 4和XHTML 1的严格版本中,链接的目标属性不再存在。对此的一种解释是,网页根本不应该在新窗口中打开链接。另一个是目标没有通用语义,因此不应在HTML中定义。 (CSS 3的工作草案包括一组链接演示的目标属性,最终可以看到将此机制交给CSS。我个人希望这永远不会超越草稿阶段,因为它与CSS无关:界面控制与设计语言相比,在语义上的语言中,界面控制不太合适!)

还有其他解释,论点很长(有时甚至很乏味),但可以说您可能会发现自己需要解决这个问题的解决方案。无论您的个人观点是什么,这都是网络开发客户的共同要求。

>
<div  <br>
    onmouseover="this.style.borderColor='red'" <br>
    onmouseout="this.style.borderColor='black'">
解决方案

此脚本通过外部属性值标识链接。 REL属性是描述链接与其目标之间关系的一种方式,因此其用于识别指向另一个站点的链接的使用是语义上的无关:

>
<script type="text/javascript"> <br>
function saySomething(message) <br>
{ <br>
  alert(message); <br>
} <br>
saySomething('Hello world!'); <br>
</script>

如果这样识别每个外部链接,则一个文档。

<ul > <br>
  <li><a href="/">Home</a></li> <br>
  <li><a href="/about/">About</a></li> <br>
  <li><a href="/contact/">Contact</a></li> <br>
</ul> <br>
 <br>
<script type="text/javascript" src="menu.js"></script>

讨论

使用单个范围内的事件处理程序是最有效的方法 - 它比在所有链接中迭代并分别将处理程序绑定到每个链接的方法要好得多。我们可以通过引用事件目标属性来找出实际单击的元素。有关事件和事件属性的更多信息,请参见第13章,基本动态HTML,但这是有关情况的简要摘要。

>当前浏览器采用了两个完全不同的事件模型。该脚本建立了应该通过寻找e(Mozilla浏览器使用的事件参数)来使用的脚本,并且已被大多数其他浏览器采用 - 与Internet Explorer使用的窗口相反。然后,它保存了适用于使用的模型的对象属性:Mozilla的目标和喜欢浏览器,或IE。

目标对象(如果不是null)可以是以下三件事之一:链接节点,链接中的元素或文本节点或其他节点。我们希望前两个情况由我们的脚本处理,但是可以安全地忽略从最后情况引起的点击。我们要做的是遵循事件目标的父节点的踪迹,直到我们找到链接或到达身体元素。

>我们拥有一个统一的目标链接后,我们只需检查具有正确值的REL属性即可;如果存在,我们可以使用链接的HREF打开一个窗口,如果所有这些都成功(按照新窗口对象的封闭属性判断),处理程序将返回false,以防止遵循原始链接。

将链接传递到window。开放而不定义参数将创建一个带有默认装饰的窗口 - 带有target =“ _ blank”的链接也将创建一个。

第一个测试

我们使用getAttribute作为RER的第一个测试,因为属性特定的属性仅在您确定所涉及的属性已分配值时才可靠。我们不能直接去测试target.rel针对字符串,因为它可能是无效的或未定义的。在“读写元素的属性”部分中对此进行了详细讨论。

在框架之间进行通信

如果您在框架环境中工作,则可能有必要在框架之间进行脚本进行通信,读取或写作属性或在不同文档中调用函数。>

您可以选择是否使用框架,我强烈建议您不要这样做,因为它们存在许多严重的可用性和可访问性问题,除了它们在概念上被损坏(它们在无法解决的浏览器状态下创建)之外)。但是,就像您使用弹出窗口一样,在某些情况下,您可能没有选择使用框架。因此,如果您确实必须使用它们,这就是您需要做的。

>

解决方案

>让我们从一个简单的框架文档开始:

<script type="text/javascript"> <br>
function saySomething(message) <br>
{ <br>
  alert(message); <br>
} <br>
saySomething('Hello world!'); <br>
</script>

我们可以使用四个参考文献进行跨帧脚本:>

    窗口或自我指的是当前的框架页面。
  • parent指的是包含包含当前页面的帧的页面。
  • >
  • 顶部是指框架层次结构的顶部的页面,如果层次结构中只有一个框架,则该页面将与父母相同。
  • >
  • 框架集合是当前页面中所有帧的关联数组。
  • >假设我们有一个脚本在ContentFrame中,希望在NavigationFrame中传达页面。这两个页面都包含在单个框架集中 - 层次结构中唯一的页面 - 因此我们可以成功地从ContentFrame中进行以下任何引用:>

parent.frames [0]

    > top.frames [0]
  • parent.frames ['navigationFrame']
  • > top.frames ['navigationFrame']
  • 框架集合是一个关联数组(例如我们在第6章中看到的表单集合,处理和验证表单),因此可以通过索引或名称访问每个元素。通常最好使用该名称(除非您有充分的理由不这样做),这样,如果框架订单更改,则不必以后编辑代码。同样,如果层次结构更改,复杂嵌套框架集中的父母引用可能会更改,因此我通常建议开发人员始终开始从顶部引用。在上述选项中,我更喜欢的参考是top.frames ['navigation frame']。
现在我们有了对框架的引用,我们可以在另一个框架页面中调用函数:>

另外,我们可以参考其他框架文档,并从那里与DOM一起工作:>

<ul > <br>
  <li><a href="/">Home</a></li> <br>
  <li><a href="/about/">About</a></li> <br>
  <li><a href="/contact/">Contact</a></li> <br>
</ul> <br>
 <br>
<script type="text/javascript" src="menu.js"></script>
讨论

<script type="text/javascript" src="menu.js"></script> <br>
 <br>
<noscript> <br>
  <ul> <br>
    <li><a href="/">Home</a></li> <br>
    <li><a href="/about/">About</a></li> <br>
    <li><a href="/contact/">Contact</a></li> <br>
  </ul> <br>
</noscript>
帧之间的通信仅适用于同一域中的文档 - 出于安全原因,不可能使用与脚本不同域中加载的文档。例如,恶意网站所有者将您定期访问的网站加载并窃取您输入的个人数据。

>

实际上,有些浏览器让用户不允许所有脚本在帧之间进行通信,只是消除了跨站点脚本漏洞的任何可能性,如果您的脚本发现自己在浏览器中运行如此配置,则无法处理此偏好。

>如果您确实有抱怨问题的用户(并且他们无法或不会更改其设置以允许跨框架脚本),那么最安全的事情就是避免完全跨框架脚本。 第6章,处理和验证表格和第8章,与cookie合作。

获得滚动位置

页面滚动是JavaScript中最不可值的属性之一:不同版本的不同浏览器正在使用三种变体。但是,有了一些仔细的对象测试,我们可以可靠地获得一致的价值。

>

解决方案

有三种获取此信息的方法。我们将在每种方法上使用对象测试,以确定可用的支持级别:

> 现在可以根据需要调用该函数。这是一个简单的示范,使用窗口。Croll事件处理程序,它获取数字并将其写入标题栏:>

卷轴
<script type="text/javascript"> <br>
function saySomething(message) <br>
{ <br>
  alert(message); <br>
} <br>
saySomething('Hello world!'); <br>
</script>

的问题

>
<ul > <br>
  <li><a href="/">Home</a></li> <br>
  <li><a href="/about/">About</a></li> <br>
  <li><a href="/contact/">Contact</a></li> <br>
</ul> <br>
 <br>
<script type="text/javascript" src="menu.js"></script>
滚动不是事件中最可靠的:它可能根本不会在Konqueror或Safari 1.0中发射,或者用户在Firefox中用鼠标滚轮导航时。而且,如果它确实发射,它可能会不断地和快速地进行(就像在Internet Explorer中一样),如果您设置为事件的脚本响应的脚本非常复杂,则可能会缓慢且效率低下。

>>>

>

如果您遇到了这种困难,则可能会发现使用SetInterval功能而不是OnScroll事件处理程序更好。 SetInterval将允许您以可预测的间隔调用该功能,而不是响应事件。您可以在第14章,时间和动作中找到有关此类脚本的更多信息,但这是一个可比的示例:>

window.setInterval(function() {  var scrollpos = getsCrollingPosition();      

 document.title ='left ='scrollpos [0]'top ='

     scrollpos [1];       },250);



讨论

>这里唯一真正的复杂性是IE 5实际上确实识别了纪录片。CrollTop属性,但其值始终为零,因此我们必须检查值并查找属性的存在。

>否则,哪个浏览器正在使用哪个属性,这对我们来说并不重要。最重要的是,我们的脚本通过兼容性测试之一获得并返回有用的值。但是,此处显示每个浏览器使用的属性以供参考:>

    Firefox和其他Mozilla浏览器,Safari,Konqueror和Opera使用的 window。 IE 6在符合标准的模式下使用document.body.scrolltop由IE 5使用,IE 6在“怪异”模式下使用。
  • 此列表不能说明完整的故事,但主要是要描述测试的顺序。最近的Mozilla浏览器(例如Firefox)也支持Invoryelement.scrolltop和body.scrolltop,通过与IE 6相同的渲染模式规则。 Opera以任何模式支持所有三个属性!
  • >
  • >,但这对您来说都不重要 - 浏览器供应商添加了这些多个属性,以允许不知道一个属性或另一个属性的脚本,而不是为此而提供任意选择。从我们的角度来看,重要的是要确定一组兼容性测试,以确保我们的脚本尽可能广泛地工作。
渲染模式

“标准”模式和“怪异”模式是当前浏览器使用的两个主要渲染模式。这些模式会影响输出文档的各个方面,包括哪个元素是画布(或),以及如何计算CSS盒子大小。有关渲染模式的更多信息,请参见第11章,检测浏览器差异。

使页面滚动到特定位置 >所有当前浏览器实现了相同的(非标准)方法来滚动页面。至少这里的东西很简单!

>

解决方案

有两种方法可用于滚动页面(或更确切地说是窗口或框架),要么由特定量(window.scrollby)或特定点(window.scrollto):
>

这些示例说:向下滚动200个像素,然后用200个像素沿着200个像素,然后从左侧的300个像素和100像素从顶部,然后回到顶角。

>获取视口尺寸(窗口内的可用空间)

在许多类型的脚本中,无论可用空间是脚本逻辑中的一个因素,都需要视频大小的详细信息。该解决方案提供了一个实用程序功能,以获取视口大小,我们将在本书中再次看到该功能!

<script type="text/javascript"> <br>
function saySomething(message) <br>
{ <br>
  alert(message); <br>
} <br>
saySomething('Hello world!'); <br>
</script>
解决方案

我们需要的属性以三种不同的方式实现,例如我们在上一节中看到的页面滚动的属性(称为“使页面滚动到特定位置”的部分)。与该示例一样,我们可以使用对象测试来确定哪种实现相关,包括我们在IE 5中需要的零值测试(出于相同的原因需要此测试:因为,尽管存在属性,但它不是我们想要的):
>>>>>
<script type="text/javascript"> <br>
function saySomething(message) <br>
{ <br>
  alert(message); <br>
} <br>
saySomething('Hello world!'); <br>
</script>

该函数返回宽度和高度的数组,因此我们可以在需要该数据时称其为:

>
<ul > <br>
  <li><a href="/">Home</a></li> <br>
  <li><a href="/about/">About</a></li> <br>
  <li><a href="/contact/">Contact</a></li> <br>
</ul> <br>
 <br>
<script type="text/javascript" src="menu.js"></script>
摘要

>我们从本章中的实用主义者的角度涵盖了窗口和框架操纵的基础知识。我们还讨论了我们可以使用的原理和技术,以确保这样的脚本与我们可以制作的脚本一样易于且易于访问。毫无疑问,这种工作将保持争议,显然我们确实需要某种定位机制,因为即使使用框架正在慢慢垂死,更复杂的接口的出现也使这些问题保持了。

>我更喜欢Xlink Standard的show属性,该属性具有新的值和替换。这些暗示了一个目标过程(打开一个新窗口,分别替换当前窗口的内容),但实际上并未定义特定的行为。他们将其留给用户代理以控制实际发生的事情,例如,新的可以用来打开标签而不是Windows。

第13章。基本动态HTML

>动态HTML并不是您可以指出并说:“这是DHTML的一项技术。”该术语是一个描述符,其中包含所有结合起来以使网页动态的技术:使您可以创建新元素而不刷新页面,更改这些元素的颜色并使其扩展,收缩和放大屏幕的技术。 DHTML使用HTML,DOM和CSS与客户端的脚本语言(JavaScript)结合使用HTML,将生命带入传统上是一种静态媒介。在前几章中,我们了解到我们可以使用JavaScript来操纵页面的一部分以取得一些非常方便的结果。 DHTML通过将这些部分组装成一个连贯的整体来提供更复杂的问题的解决方案 - 满足现实世界需求而不是编程难题的解决方案。
>

>本章探讨了我们需要的一些工具,以便与DHTML创建有效的用户界面。然后,它讨论了几个简单的小部件,以准备在本书其余部分中考虑的更复杂的模块。

处理事件

>用户与网页的任何交互(无论是移动鼠标还是敲击键盘)都会导致浏览器生成事件。有时,我们希望我们的代码对此互动做出响应,因此我们聆听这些事件,这让我们知道何时应该执行代码。

解决方案

有两种处理事件的方法:简短的方式和W3C方式。每个人都有其优点和缺点,但是当事件发生在特定元素上时,您都可以执行指定的函数。

简短的方式:使用事件处理程序

处理事件的较短方法是使用分配为每个元素的快捷属性的DOM 0事件处理程序。正如我们在第5章中看到的那样,当我们讨论DOM 0属性快捷方式时,这些事件处理程序并非未来。但是,它们确实提供了比标准W3C活动听众的一些优势:

    >当前正在操作的每个浏览器都支持DOM 0事件处理程序,而无需代码分支。
  • DOM 0事件处理程序执行的每个函数都可以访问分配事件处理程序的确切元素。 (如稍后您会看到的那样,这在W3C活动听众中并不总是可用的。)
  • >
  • 使用DOM 0事件处理程序的主要问题是,它们并非设计用于使用多个脚本。每次分配DOM 0事件处理程序时,您都会覆盖该事件的任何先前分配的处理程序。这可能会干扰需要在同一元素上进行事件处理的多个脚本的操作。使用W3C活动听众,您可以在同一元素上应用任何数量的事件听众,并享受随时删除其中任何一个的能力。
>

>如果您可以确定您的代码不会干扰别人的事件处理(例如,您正在将事件放置在动态创建的元素上,则可以安全地使用DOM 0事件处理程序。但是 - 所有事物都是平等的 - 在本书中,使用W3C事件听众更加安全。

>可通过浏览器获得许多DOM 0事件处理程序;表13.1,“ DOM 0事件处理程序”列出了最常用的处理程序。

表13.1。 DOM 0事件处理程序


在使用DOM 0事件处理程序中,一旦您提到了要处理的事件的元素,这是将处理函数分配给适当属性的简单问题: 脚本更智能:从头开始的质量JavaScript

>您会注意到,在函数分配(button.onclick = gangem;)中,括号不遵循函数名称。他们的包含将立即执行该函数,并将返回值分配为事件处理程序。通过省略括号,您可以将功能本身分配给处理程序。这也意味着您不能直接向处理功能提供参数:该功能必须通过其他方式获取其信息。

<script type="text/javascript"> <br>
function saySomething(message) <br>
{ <br>
  alert(message); <br>
} <br>
saySomething('Hello world!'); <br>
</script>
匿名函数

您可以为事件处理程序提供匿名函数,而不是提供对命名函数的引用:

var mylink = document.getElementById(“ mylink”);      

      mylink.onclick = function() {

 警报(“参与!”);      

       返回false;      
}

>>取决于您是否需要重复使用处理功能(和您自己的编码首选项),这可能是编写事件处理代码的一种更简单的方法。 处理函数的返回值确定该事件的默认操作是否发生。因此,在前面的代码中,如果Mybutton是超链接,则单击时的默认操作将导航到其HREF位置。通过返回false,连接函数不允许执行默认操作,并且超链接导航不会发生。如果返回值为真,则在事件处理函数的代码执行后将发生默认操作。

发生事件时,详细的信息,有关该事件的方式,原因和何处的详细信息写入事件对象。在Internet Explorer中,这采用了全局窗口的形式。事实对象,但在其他浏览器中,该对象作为参数传递给事件处理函数。在处理功能中,此差异很容易解决:

>事件对象允许您找到一系列详细信息,例如单击哪个元素,是否按下任何键,事件的坐标(例如,在单击鼠标按钮时,光标位于位置)以及触发函数的事件类型。在浏览器中,相当多的事件属性名称是一致的,但有些不同。 Mozilla事件属性可以通过壁虎DOM参考查看,而Internet Explorer事件属性则可以在MSDN上看到。对于其名称在浏览器之间变化的属性,通常可以通过少量对象检测来纠正相关问题的潜力;我们将在本章稍后详细讨论。

>
<script type="text/javascript"> <br>
function saySomething(message) <br>
{ <br>
  alert(message); <br>
} <br>
saySomething('Hello world!'); <br>
</script>
w3c Way(事件听众)

>尽管DOM 0事件处理程序快速又容易,但它们确实有局限性(除了最终将被弃用的事实)。 W3C事件听众的主要优点是,他们在单个元素上本身支持同一事件的多个处理功能的添加和删除。活动听众还可以在多个阶段响应事件(尽管大多数浏览器尚未支持此功能)。 在W3C规范中,可以使用该元素的AddEventListener方法将事件添加到元素中,但是Windows的Internet Explorer选择使用一种称为AstactEvent的方法,该方法的语法略有不同。 (Mac的Internet Explorer不支持这两个事件模型,因此我们必须依靠DOM 0处理程序与此浏览器中的事件一起使用。)

>要在Internet Explorer以外的每个浏览器中添加事件侦听器,您将编写与此类似的代码:

为了支持Internet Explorer,您需要此代码:

<script type="text/javascript"> <br>
function saySomething(message) <br>
{ <br>
  alert(message); <br>
} <br>
saySomething('Hello world!'); <br>
</script>

以及不同的函数名称,重要的是要注意,Internet Explorer为事件使用DOM 0处理程序名称 - “ OnClick” - 而不是真实的事件名称:“ click click”。提供的额外参数用于AddEventListener,指定在捕获(true)还是气泡(false)事件传播阶段中应用听众。在下面的讨论中更详细地说明了事件传播,但是泡泡确实是最有用的选择,并确保在符合标准的浏览器中的行为与Internet Explorer中的相同行为。

这两种方法之间的差异很容易使用抽象功能。我们还可以为不支持W3C活动听众的浏览器提供后备。

>前两个IF语句分别涉及基于标准的和Internet Explorer方法,但是其他所有内容都涉及不支持这两种方法的旧浏览器,尤其是Internet Explorer 5。在最后一个情况下,使用了DOM 0事件处理程序,但是为了确保可以使用多个功能来处理特定元素的单个事件,请闭合来执行事件附加的任何现有功能。
<ul > <br>
  <li><a href="/">Home</a></li> <br>
  <li><a href="/about/">About</a></li> <br>
  <li><a href="/contact/">Contact</a></li> <br>
</ul> <br>
 <br>
<script type="text/javascript" src="menu.js"></script>
>

封闭是与范围有关的JavaScript的高级功能(您可以在第19章中阅读,在JavaScript中的对象方向)。闭合允许内部函数引用包含函数的变量,即使包含函数完成运行。西蒙·威利森(Simon Willison)已详细解释了与活动处理程序有关的用法。可以说封闭使我们可以在不支持W3C活动听众的浏览器中堆叠多个事件处理程序。>

>分配事件侦听器的跨浏览器代码如下:

不(完全)真正的文章

<script type="text/javascript" src="menu.js"></script> <br>
 <br>
<noscript> <br>
  <ul> <br>
    <li><a href="/">Home</a></li> <br>
    <li><a href="/about/">About</a></li> <br>
    <li><a href="/contact/">Contact</a></li> <br>
  </ul> <br>
</noscript>
> 尽管DOM 0事件处理程序后备模拟了在元素上添加多个事件侦听器的多个事件侦听器的能力,但它不能提供W3C事件模型的精确复制,因为无法从元素中删除特定的操作员。

> > DOM 0处理程序允许通过返回false的false,W3C事件听众取消元素的默认操作,以略有不同。要取消此模型中的默认操作,我们需要修改事件对象。 Internet Explorer要求您将其returnValue属性设置为false;基于标准的实现提供了预防违规方法来执行同一操作。我们可以创建一个小函数,以找出我们的区别:

>我们可以在要取消默认操作时调用此功能:> >您仍然需要在执行StopDefaultAction之后返回false,以确保不支持W3C事件模型的浏览器也将阻止默认操作。

>> safari和W3C事件听众

> 由于Safari中的一个错误,不可能取消使用W3C事件侦听器时单击该浏览器中的超链接的默认操作。为了实现取消,您必须使用具有false的返回值的DOM 0事件处理程序。

>

>检查AstactEvent

当使用attactevent用于附加事件侦听器时,

Internet Explorer实际上将事件对象传递给事件处理函数。但是,我们仍然需要检查使用使用旧事件模型的任何浏览器的对象的存在。

>使用W3C事件听众的优点之一是,您可以从元素中删除单个侦听器,而不会在同一事件上打扰任何其他侦听器。使用DOM 0处理程序是不可能的。 Internet Explorer使用Decachevent方法,而符合标准的浏览器则指定一种称为RemothEventListener的方法。这些方法中的每一种都与侦听器添加对应物相似:必须提供一个事件类型以及分配给处理该事件类型的功能。该标准方法还需要知道事件处理程序是否已注册在捕获或气泡阶段中进行响应。> 这是一个支持这种方法跨浏览器的函数:

W3C事件模型和匿名函数

>

<script type="text/javascript"> <br>
function saySomething(message) <br>
{ <br>
  alert(message); <br>
} <br>
saySomething('Hello world!'); <br>
</script>
W3C事件模型不允许删除匿名函数,因此,如果您需要删除事件侦听器,请挂在所讨论的功能上。 在不支持W3C事件听众的浏览器中,此功能在给定事件上删除了所有事件处理程序:不可能仅删除其中一个并留下其他事件。

讨论

引用目标元素 >通常,您需要使用事件处理程序本身内事件的目标的对象。使用DOM 0事件处理程序,使用特殊变量在处理函数内将是指事件目标对象。考虑此代码:

>在这里,这是指带有ID myLink的链接。我们可以使用它来获取链接的HREF属性。

但是,如果您使用W3C事件侦听器,则事件的目标作为事件对象的一部分存储在不同的浏览器中的不同属性下。 Internet Explorer将目标存储为SRCELEMENT,而标准模型将其作为目标存储。但是,这些属性点的元素不一定是分配事件侦听器的元素。实际上,这是事件影响的层次结构中最深的元素。看看以下html。

<script type="text/javascript"> <br>
function saySomething(message) <br>
{ <br>
  alert(message); <br>
} <br>
saySomething('Hello world!'); <br>
</script>

如果将单击事件侦听器放在段落上,并且用户单击链接,则将执行段落的单击事件处理程序,但是可以通过上述属性访问的事件目标是超链接。一些浏览器(最著名的是Safari)甚至可以将链接中的文本节点计为目标节点。

>我们可以编写一个返回事件目标的函数,而与已实施的属性无关,但这并不能解决找到我们最初应用事件侦听器的元素的问题。 (W3C标准指定了另一个称为CurrentTarget的属性,该属性使您可以获得侦听器的分配的元素,但没有互联网浏览器等效。支持CurrentTarget的浏览器也设置了事件处理程序,以相同的价值设置了此变量,但是再次,如果没有特别有用的Iss Tromist,则可以通过互联网探险者提供的目标,直到我们提供的目标。)找到一个可能是我们附上事件侦听器的元素。为此,我们可以针对元素的标签名称,类和其他属性执行检查。

>

抽象事件目标函数看起来像这样:

<ul > <br>
  <li><a href="/">Home</a></li> <br>
  <li><a href="/about/">About</a></li> <br>
  <li><a href="/contact/">Contact</a></li> <br>
</ul> <br>
 <br>
<script type="text/javascript" src="menu.js"></script>
if-else跨浏览器检索事件目标;然后,如果浏览器报告的目标恰好是文本节点。

如果我们要检索单击的元素,然后我们打电话给geteventtarget:>

>因为在这种情况下,我们知道事件处理函数将仅附加到链接(标签),所以我们可以从事件目标上迭代,从而检查“ A”的节点名称。我们发现的第一个将是与处理程序分配的链接;这样可以确保我们与链接中的某些元素不使用(例如强或跨度)。>

显然,这种目标发现方法不是理想的选择,除非您了解要与之合作的确切HTML,否则不能100%准确。最近,解决此问题的努力已经大大努力,并且有很多建议的解决方案提供了与DOM 0事件处理程序中可用的相同的此变量,并且在支持活动听众W3C标准的浏览器中(而不是Internet Explorer)。
<script type="text/javascript" src="menu.js"></script> <br>
 <br>
<noscript> <br>
  <ul> <br>
    <li><a href="/">Home</a></li> <br>
    <li><a href="/about/">About</a></li> <br>
    <li><a href="/contact/">Contact</a></li> <br>
  </ul> <br>
</noscript>
>这样的解决方案是使事件听力功能成为Internet Explorer中目标对象的方法。然后,当调用该方法时,这自然会指向该方法的对象。这需要修改AstactEventListener和distacheventlistener:>

在彼得·保罗·科赫(Peter Paul Koch)改进的Addevent竞赛的参赛作品中,这种思维方式很好地代表了。Dean Edwards的另一种解决方案完全避免了W3C事件模型,而有利于实现具有独立添加和删除功能的DOM 0事件处理程序。

>尽管这两种解决方案都可能被证明是写作和强大的,但在撰写本文时,它们在很大程度上没有测试,因此我们将坚持我们所知道和可以处理的缺陷的方法:在主要解决方案中呈现的方法。此外,在实践中,迭代寻找事件的目标的过程并不像看起来那样不可靠。

>

什么是事件冒泡,我如何控制它?

>

>您可能已经注意到,我们需要为W3C标准AddEventListener方法提供第三个参数,并且我们的tactereventleistener函数中包含捕获参数以适应此内容。该参数确定了侦听器操作的事件周期的阶段。

>

假设您有两个元素,一个元素嵌套在另一个元素:>

用户单击链接时,单击事件将在段落和超链接上注册。问题是,哪一个首先接收活动?

>
<script type="text/javascript"> <br>
function saySomething(message) <br>
{ <br>
  alert(message); <br>
} <br>
saySomething('Hello world!'); <br>
</script>
事件周期包含两个阶段,每个阶段都以不同的方式回答了这个问题。在捕获阶段,事件从外部起作用,因此该段落将首先单击,然后接收超链接。在气泡阶段,事件是从内而外工作的,因此锚将在段落之前接收单击。

>

Internet Explorer和Opera仅支持冒泡,这就是为什么AstactEvent不需要第三个参数的原因。对于支持AddEventListener的浏览器,如果第三个参数为真,则将在捕获阶段捕获该事件;如果是错误的,则该事件将在气泡阶段捕获。

> 在支持这两个阶段的浏览器中,捕获阶段首先发生,并且始终是气泡相。只要您为每个阶段设置侦听器,就可以在捕获阶段和冒泡阶段的同一元素上处理一个事件。

>

这些阶段还强调了嵌套元素受同一事件影响的事实。如果您不再希望事件继续在触发事件侦听器后继续向上或向下传播层次结构(取决于阶段),则可以停止。在Internet Explorer中,这涉及将事件对象的取消吹动属性设置为true;在W3C模型中,您必须调用其停止propagation方法:>

如果我们不希望事件比活动处理程序更进一步,我们将使用此代码:

>尽管我们已经分配了互动函数来收听链接和包含它的段落上的单击事件,但该函数只会每次点击一次调用一次,因为该事件的传播首次被召唤。
查找元素的大小

>有很多变量会影响元素的大小 - 内容长度,CSS规则,字体家族,字体大小,线高,文本缩放……列表还在继续。再加上这一事实,即浏览器不一致地解释CSS维度和字体大小,并且您永远无法预测呈现元素的尺寸。确定元素大小的唯一一致方法是一旦浏览器渲染。

解决方案

>您可以立即告诉您确切地知道一个元素有多大,这将是有用的。好吧,W3C无济于事:没有标准化的方法来确定元素的大小。值得庆幸的是,浏览器制造商或多或少地解决了一些让我们弄清楚的域。

尽管框模型差异意味着Internet Explorer在元素的CSS维度的一部分中包括填充和边界不一致,但OffsetWidth和Offseight属性将始终如一地返回元素的宽度,包括填充和边界,包括所有浏览器。

让我们想象一个元素的尺寸是在这样的CS中指定的:

>

<script type="text/javascript"> <br>
function saySomething(message) <br>
{ <br>
  alert(message); <br>
} <br>
saySomething('Hello world!'); <br>
</script>
我们可以通过检查相应的OffsetWidth和Offsesteight属性来确定JavaScript中元素的精确像素宽度:>

In Internet Explorer 6, Opera, Mozilla, and Safari, the variable pixelWidth will now be set to 450, and the variable pixelHeight will be set to 250. In Internet Explorer 5/5.5, pixelWidth will be 350 and pixelHeight 150, because those are the dimensions at which the broken box model approach used in those browsers will render the element.这些值在浏览器之间是不同的,但这仅仅是因为实际渲染尺寸也有所不同。偏移尺寸始终计算元素的精确像素尺寸。
<ul > <br>
  <li><a href="/">Home</a></li> <br>
  <li><a href="/about/">About</a></li> <br>
  <li><a href="/contact/">Contact</a></li> <br>
</ul> <br>
 <br>
<script type="text/javascript" src="menu.js"></script>
如果我们没有指定元素的尺寸,而是将其显示到默认块渲染(从而避免使用框模型错误),则该值在浏览器之间是可比的(允许Scrollbar宽度差异,字体等。

达到正确的尺寸

为了正确确定元素的尺寸,您必须等待,直到浏览器完成该元素的渲染,否则尺寸可能与用户最终看到的尺寸不同。没有保证的方法可以确保浏览器完成渲染元素,但是通常可以安全地假设一旦窗口的负载事件发射,所有元素都已渲染。

讨论

>可以检索元素的尺寸减去边界,但包括其填充。这些值将使用clientwidth和clientHeight属性访问,对于上面的示例元素,在Internet Explorer 5/5.5中将为300和100,在所有其他浏览器中为400和200。

没有任何属性可以让您在没有边界或填充的情况下检索元素的宽度。

>

找到元素的位置
当您希望将其他元素定位在其上时,了解元素的确切位置非常有帮助。但是,由于浏览器尺寸,字体大小和内容长度不同,在加载页面之前,通常不可能对元素的位置进行硬编码。 JavaScript提供了一种方法来确定页面呈现后任何元素的位置,因此您可以确切知道元素的位置。
>

解决方案

offsetTop和OffsetLeft属性告诉您元素顶部和其偏移量的顶部之间的距离。但是什么是偏移者?好吧,对于不同的元素和不同的浏览器,它的变化很大。有时是直接包含的元素;其他时候,它是HTML元素;在其他时候不存在。>

幸运的是,解决方案是遵循Outsparents的踪迹并添加其偏移位置 - 这种方法将为您在每个浏览器中在页面上的准确绝对位置提供。

如果所讨论的元素没有偏置,则元素本身的偏移位置就足够了。否则,我们将元素的偏移量添加到其偏移者的偏移量,然后重复其Oftsetparent的过程(如果有):>

ie 5 for Mac bug

Mac的Internet Explorer 5在计算偏移尺寸时,Internet Explorer 5不考虑身体的边距或填充,因此,如果您希望在此浏览器中进行准确的测量值,则应在体内具有零保证金和填充。
<script type="text/javascript"> <br>
function saySomething(message) <br>
{ <br>
  alert(message); <br>
} <br>
saySomething('Hello world!'); <br>
</script>

讨论

上面的方法适用于简单而复杂的布局;但是,当一个或多个元素的祖先将其CSS位置属性设置为静态以外的事物时,您可能会遇到问题(默认值)。

> >嵌套定位和浏览器差异有很多可能的组合,几乎不可能编写一个将它们全部考虑在内的脚本。如果您使用的是使用大量相对或绝对定位的界面,那么尝试特定案例并编写特殊功能来处理它们可能是最容易的。这只是您可能会遇到的一些区别:

    在Windows和Mozilla/Firefox的Internet Explorer中,任何其父母相对定位的元素都不会在其自身偏移中包含父母的边界;但是,父母的偏移只会衡量其边界的边缘。因此,这些值的总和将不包括边界距离。
  • > 在歌剧和野生动物园中,任何绝对或相对位置的元素,其偏见的人是身体的偏移。人体的偏移也将包括自己的余量。
  • 在Windows的Internet Explorer中,相对位置的元素内的任何绝对位置的元素都将在其偏移量中包括相对位置的元素。相对位置的元素也将包括其边距。
  • >
  • 检测鼠标光标的位置
使用鼠标事件(例如鼠标或鼠标)时,您通常需要使用鼠标光标的坐标作为操作的一部分(例如,将元素放在鼠标附近)。下面解释的解决方案实际上是一种比我们在“找到元素的位置”部分讨论的元素位置检测方法更可靠的位置检测方法,因此,如果可以使用以下解决方案而不是上一个解决方案,请努力!
解决方案

事件对象包含您需要知道的所有与光标位置一起使用的所有内容,尽管需要一点对象检测以确保您在所有浏览器中获得等效值。> >通过事件对象的pagex和pagy属性,获得光标的位置相对于整个页面获得的标准方法。 Internet Explorer不支持这些属性,但它确实包含了一些我们想要的属性。客户端和客户端可在Internet Explorer中找到,尽管它们测量了从鼠标光标到浏览器窗口边缘的距离。为了找到光标相对于整个页面的位置,我们需要将当前的滚动位置添加到这些维度。该技术在第7章中涵盖,使用窗户和框架;让我们使用该解决方案的getCrollingPosition函数来检索所需的尺寸:>

显示鼠标在元素

上时显示工具提示 在大多数浏览器中,工具提示是一个有用的功能,但是如果您打算将其用作界面的一部分,它们可能会有所限制。如果您想使用在需要时出现的图层,不会被截断,并且可以包含超过纯文本,为什么不制作自己的增强型工具提示?

解决方案
<script type="text/javascript"> <br>
function saySomething(message) <br>
{ <br>
  alert(message); <br>
} <br>
saySomething('Hello world!'); <br>
</script>
<ul > <br>
  <li><a href="/">Home</a></li> <br>
  <li><a href="/about/">About</a></li> <br>
  <li><a href="/contact/">Contact</a></li> <br>
</ul> <br>
 <br>
<script type="text/javascript" src="menu.js"></script>
在此示例中,我们将在我们希望出现的工具提示的所有元素上应用一个类(Hastooltip)的课程。我们将从每个元素的标题属性中获取将出现在工具提示中的信息:
>
<script type="text/javascript"> <br>
function saySomething(message) <br>
{ <br>
  alert(message); <br>
} <br>
saySomething('Hello world!'); <br>
</script>

>从我们在本章早期对浏览器事件的探索中,您可能已经意识到我们需要设置一些事件听众,以便让我们知道何时应该出现并消失。

>

工具提示在鼠标上鼠标在元素上时经典出现在固定位置,并在鼠标赶出时消失。 JavaScript工具提示的某些实现也会随着鼠标移动元素的移动而移动工具提示,但我个人觉得这很烦人。在此解决方案中,我们将重点介绍鼠标和鼠标之路事件:

<ul > <br>
  <li><a href="/">Home</a></li> <br>
  <li><a href="/about/">About</a></li> <br>
  <li><a href="/contact/">Contact</a></li> <br>
</ul> <br>
 <br>
<script type="text/javascript" src="menu.js"></script>

>我们已经编码了此脚本中的许多功能,包括第1章的addloadListener,从第5章开始使用JavaScript,GetElementsByAttribute,浏览文档对象模型以及我们在本章早些时候创建的AstactEventListener函数,因此代码的大部分是在Event evers Liester函数的:

<script type="text/javascript" src="menu.js"></script> <br>
 <br>
<noscript> <br>
  <ul> <br>
    <li><a href="/">Home</a></li> <br>
    <li><a href="/about/">About</a></li> <br>
    <li><a href="/contact/">Contact</a></li> <br>
  </ul> <br>
</noscript>
>在获得跨浏览器事件对象之后,并从基本事件目标元素到具有一类Hastooltip的一个元素,Showtip将进行创建工具提示(a div)。工具提示的内容是从目标元素的标题属性中获取的,并将其放入工具提示内的文本节点。 为了确保浏览器不会在我们增强的工具提示上显示其工具提示,然后清除了目标元素的标题 - 现在,浏览器无法显示为工具提示,因此它不会干扰我们刚刚创建的浏览器。不必担心删除标题引起的潜在可访问性问题:我们稍后再放回。

控制工具提示在Opera

中显示 即使我们将其设置为空字符串,

opera仍会显示原始标题。如果您希望避免在此浏览器中出现的工具提示,则必须使用optDefaultAction函数从称为“处理事件”的部分(本章的第一部分)停止使用鼠标的默认操作。请注意,这也会影响其他鼠标行为,例如超链接的状态条地址显示。 >为工具提示的样式提供钩子,我们将工具提示元素分配给基于目标元素的ID(targetIdToolTip)的ID,并设置一类工具提示。尽管这种方法允许通过CSS应用样式,但我们无法提前计算工具提示的位置,因此我们必须使用鼠标光标的坐标(如触发事件时所计算的)来定位工具提示(使用一些额外的像素来给它一些空间)。 >剩下的就是将工具提示元素附加到身体上,因此当我们鼠标鼠标匹配链接时,它将神奇地出现!有了一点CSS,它看起来像是图13.1,“鼠标上出现的动态生成的图层”。

>

脚本更智能:从头开始的质量JavaScript
图13.1。动态生成的图层,出现在鼠标

>将鼠标从元素移开时,我们将工具提示从文档中删除,并且它将消失:

>
<script type="text/javascript"> <br>
function saySomething(message) <br>
{ <br>
  alert(message); <br>
} <br>
saySomething('Hello world!'); <br>
</script>

之前,在Showtip中,我们创建了对工具提示元素作为目标元素属性的引用。完成此操作后,我们可以在此处删除它,而无需搜索整个DOM。在删除工具提示之前,我们会检索其内容并将其插入目标元素的标题,因此我们可以稍后再使用它。

>这些对象是否存在? 您应该检查在其他事件中创建的对象在尝试操纵它们之前实际上存在的对象,因为事件通常会失火,并且您不能保证它们会以设定的顺序出现。

讨论

>上面代码的一个问题是,如果目标元素靠近浏览器窗口的右侧或底部边缘,则该工具提示将被切断。为了避免这种情况,我们需要确保有足够的空间容纳工具提示,并相应地将其放置。 通过在每个维度中检查鼠标位置是否小于浏览器窗口尺寸减去工具提示大小,我们可以分辨出移动层以将其移动到屏幕上:

> 这个功能与以前的版本相同,直到我们插入工具提示元素为止。就在插入元素之前,我们将其可见性设置为“隐藏”。这意味着,当它放置在页面上时,该图层将占用与可见的相同空间,但用户不会在页面上看到它。这使我们能够测量工具提示的尺寸,然后重新定位它,而无需用户看到它以其原始位置闪烁。

为了检测图层是否在视口外显示,我们使用光标的位置相对于视口。从理论上讲,这可以通过使用clientx/clienty获得,但请记住:Safari给出了此属性的不正确值。取而代之的是,我们在CursorPosition内使用跨浏览器值并减去滚动位置(这等同于客户端/客户端)。使用我们在第7章中创建的getViewPortsize函数(使用Windows和帧配合使用的GetViewPortsize)的大小,然后,对于每个维度,我们检查光标位置是否加上图层的大小大于视口尺寸(减去scrollbars的津贴)。

>如果部分的一部分出现在视口外,我们将其从视口大小中减去其尺寸来定位;否则,它是使用光标位置正常定位的。

>

>要注意的唯一其他例外是​​,如果该图层通常以两个维度出现在视口外,则当我们垂直定位时,它会自动定位在光标上方。这样可以防止图层直接出现在光标顶部并触发鼠标out事件。它还可以防止目标元素完全被工具提示遮盖,这将阻止用户单击它。

>

>测量可见工具提示尺寸

为了测量工具提示的尺寸,必须首先将其附加到文档上。这将自动使其出现在页面上,因此为了防止用户看到它以错误的位置显示,我们需要将其隐藏。我们通过将其可见性设置为“隐藏”,直到我们完成了工具提示的位置为止。

> 我们无法在此处使用更熟悉的显示属性,因为完全没有呈现显示为“无”的对象,因此它们没有尺寸可以测量。 >按列进行排序表

表可以是信息的矿山,但前提是您可以正确理解它们。具有通过其不同列对表进行排序的能力,使用户可以以对它们有意义的方式查看数据,并最终为更多的理解提供了机会。

解决方案

开始,我们将使用语义上有意义的HTML表。这将为我们提供我们需要插入事件听众,注入额外元素的结构,并对我们的数据进行排序:

首先,我们需要在每个表标题单元格上设置事件侦听器。这些将聆听对我们的列的点击,并在单击的列上触发类别:> Mac的Internet Explorer 5

> Internet Explorer 5难以处理动态生成的表内容,因此我们必须专门将其排除在使任何表可排序的情况下。

>只有具有类交易的表格将变成可排序的表,因此InitStableable可导航DOM以在这些表中找到表标题单元格。找到它们后,每个标题单元格的内容都包裹在超链接中 - 这允许键盘用户选择一列来对表进行排序 - 并将事件侦听器设置在这些链接上,以监视单击事件,并在响应中执行sortcolumn。还设置了每个链接的标题属性,向用户提供有关单击链接时将发生的信息。

<script type="text/javascript"> <br>
function saySomething(message) <br>
{ <br>
  alert(message); <br>
} <br>
saySomething('Hello world!'); <br>
</script>
sortColumn功能相当冗长,这是因为它必须每次单击标题单元格时必须导航和重新排列整个表结构:

<script type="text/javascript"> <br>
function saySomething(message) <br>
{ <br>
  alert(message); <br>
} <br>
saySomething('Hello world!'); <br>
</script>

>在所有结构变量被定义后发生的第一个循环,当单击其中一个时,将每个桌子标题单元格设置为每个表标题单元的各个状态。不仅要维护类以识别当前对表的标题单元格,而且在每个单元格上维护了特殊的stordorder属性,以确定对该列的排序顺序。最初,将以降序排序列,但是如果连续两次单击标题单元格,则将更改排序顺序以反映上升序列。每个标题单元格记得它最近显示的排序顺序状态,并在重新选择其标题电池时将列返回到该状态。单击标题单元格的超链接标题还根据当前排序顺序重写,如果用户再次单击它,则排序顺序是什么。

>

第二个循环排列桌子体中包含的每个行。创建原始Tbody的副本是为了存储重新排序的表行,最初此副本为空。当扫描原始tbody中的每一行时,将我们要排序的列中的表单元格与副本中的行进行了比较。

为了找到表单元格的内容,我们使用函数getInternalText:>

<ul > <br>
  <li><a href="/">Home</a></li> <br>
  <li><a href="/about/">About</a></li> <br>
  <li><a href="/contact/">Contact</a></li> <br>
</ul> <br>
 <br>
<script type="text/javascript" src="menu.js"></script>
当SortColumn在副本中找到一排的表格单元格值“少”比我们扫描的副本“少”时,我们将扫描行的副本插入复制的Tbody中。对于按升序顺序的列,我们只需扭转以下比较:副本中的行的值必须“大于扫描行的”。
<script type="text/javascript" src="menu.js"></script> <br>
 <br>
<noscript> <br>
  <ul> <br>
    <li><a href="/">Home</a></li> <br>
    <li><a href="/about/">About</a></li> <br>
    <li><a href="/contact/">Contact</a></li> <br>
  </ul> <br>
</noscript>
。 但是,在进行比较之前,我们检查排序的表单元格的内容是否可以解释为整数或浮点。如果是这样,比较值将转换。这样可以确保对包含数字的列进行正确排序;字符串比较将产生与数字比较不同的结果。

>一旦我们所有原始行都被复制到新的tbody中,该元素就被用来替换旧的,我们有排序的表!

>

Using the sortableDescending and sortableAscending classes, which are assigned to the currently sorted table heading cells, we can use CSS to inform the user which column the table is sorted on, and how it is sorted, as shown in Figure 13.2, “A sortable table sorted in descending order on the fourth column” and Figure 13.3, “A sortable table sorted in ascending order on the second column”.

图13.2。一个可排序的表在第四列脚本更智能:从头开始的质量JavaScript
上以降序排序排序

图13.3。一个可排序的表在第二列上按上升顺序排序脚本更智能:从头开始的质量JavaScript

摘要
DHTML的两个主要支柱是事件的捕获,以及通过DOM的页面元素重组和创建。使用这些原则,可以捕获用户与页面交互的许多不同方式并使接口做出相应的响应。 通过JavaScript增强的Web应用程序的数量和质量可以看出,DHTML可以将新界面带入新接口的功能代表了创新JavaScript的最大增长领域之一。本章中显示的基础和基本示例使您了解它可以在用户浏览器中传递的功能。在以下各章中,我们将在构建一些非常有趣的接口。

这就是我们的样本:101基本技巧,技巧和骇客

。接下来是什么?

>将此示例下载为PDF,用于离线阅读。查看本书的目录,以查看其涵盖的内容。并查看其他人对这本书的看法 - 阅读

经常询问有关JavaScript的问题(常见问题解答)

JavaScript在Web开发中的重要性是什么?这是一种编程语言,可让您在网页上实现复杂的功能。当网页不仅显示静态信息(例如显示及时的内容更新,交互式映射,动画图形或滚动视频点盒)时,涉及JavaScript。这是标准网络技术的第三层,其中两个(HTML和CSS)在以前的文章中广泛使用。

>>我如何开始从划痕中学习JavaScript?

>

开始从Scratch中学习JavaScript,如果您看起来很艰难,但是如果您可以稍作管理,那么它可以使其较小地管理,从而降低了步骤,该步骤降低了步骤,该步骤降低了步骤。首先了解HTML和CSS的基础知识,因为它们构成了Web开发的基础。然后,您可以逐渐转到JavaScript基础知识,例如变量,数据类型,功能,循环和条件。练习是学习JavaScript的关键,因此请确保您定期编码。

>初学者在学习JavaScript时会遇到什么常见错误?

>初学者在学习JavaScript时会犯一些常见的错误,当时学习JavaScript不包括理解JavaScript和Java和Java之间的差异,没有足够的时间理解基础,并且没有足够的时间练习,并且没有足够的时间。 JavaScript是一种独特的语言,具有自己的概念和结构,重要的是要在继续进行更复杂的主题之前了解这些语言。经常实践和所学概念的应用对于掌握JavaScript至关重要。

>我可以在没有任何事先编程经验的情况下学习JavaScript吗?尽管具有编程背景可以使学习过程更容易,但这不是先决条件。 JavaScript通常被推荐为初学者的好母语,因为它宽容的语法和在网络开发中的广泛用法。

>

>从头开始学习JavaScript需要多长时间?

从scratch中学习JavaScript所需的时间可以很大程度上取决于您的先前经验,您可以在学习的时间上差异,并且可以实现知识,并且能够达到知识,并且可以实现深度的知识。平均而言,如果您每天从头开始并专门工作几个小时,您可以期望在几周到几个月内学习基础知识。

>

>学习JavaScript的最佳资源是什么? Codecademy,Udemy和FreecodeCamp等在线平台提供全面的课程。强烈建议使用诸如“雄辩的JavaScript”和“您不知道JS”之类的书。此外,Mozilla开发人员网络(MDN)在JavaScript上具有广泛的文档。

>如何在前端开发中使用JavaScript?

在前端开发中,JavaScript用于使网页页面动态和交互式。它可用于创建滑块,形式验证,弹出窗口等功能。它还允许您操纵文档对象模型(DOM),使您能够实时更改网页的内容和布局。

我可以将JavaScript用于后端开发吗?

是的,JavaScript可以用于后端开发。 Node.js是JavaScript运行时,可让您在服务器上运行JavaScript。使用node.js,您可以仅使用JavaScript。

构建整个Web应用程序。它们提供了JavaScript代码的结构,使构建大规模,可维护和可扩展的Web应用程序变得更加容易。示例包括react.js,angular.js和vue.js.

> JavaScript的未来是什么?随着React,Angular和Vue等框架的兴起,JavaScript变得越来越强大和多才多艺。此外,Node.js的开发将JavaScript的覆盖范围扩展到了服务器端,使其成为全栈语言。随着Web应用程序的复杂性不断增长,对熟练的JavaScript开发人员的需求可能会保持很高。

以上是脚本更智能:从头开始的质量JavaScript的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn