开发者社区> 异步社区> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

《JavaScript设计与开发新思维》——2.5 拼凑一些代码

简介: 现在有两个事件监听器。第一个监听window的load事件,该事件对于每个页面只发生一次,触发时调用init()函数。第二个监听器等待表单的提交,可能发生任意次(也可能一次都不发生)。每当该事件发生时,都调用validateForm()函数。定义该函数是渐进增强的最后一步。
+关注继续查看

本节书摘来自异步社区《JavaScript设计与开发新思维》一书中的第2章,第2.5节,作者:【美】Larry Ullman著,更多章节内容可以访问云栖社区“异步社区”公众号查看

2.5 拼凑一些代码

利用已经介绍过的一些基础知识,我们继续前进,开始接触JavaScript。当然,我不期望你已经了解JavaScript—这是本书的目的—但是下一个示例阐述了JavaScript的易理解性,并且为第2部分的材料(也即正规训练)提供一些背景知识。

2.5.1 开发基本功能
作为一个简单而实用的例子,我们来创建一个登录表单,然后用JavaScript进行验证。在稍后的章节中,你将学习如何为这个表单应用Ajax,但是在这时添加Ajax可能有点过于复杂。首先创建HTML表单,该表单有3个元素:一个电子邮件地址、一个密码和一个提交按钮。下面是最关键的HTML,存储在login.html文件中(图2.8)。
screenshot

<form action="login.php" method="post" id="loginForm**">
    <fieldset>
         <legend>Login</legend>
         <div><label for="email">Email Address</label>
<input type="email" name="email"
id="email" required></div>
         <div><label for="password">Password</label>
<input type="password" name="password"
id="password" required></div>
         <div><label for="submit"></label>**<input type=**"**submit**"
value="Login &rarr; " id="submit"></div>
    </fieldset>
</form>
<script src="js/login.js"></script>

为了简单起见,该页面上除了前述的表单之外,什么也没有。该页面还使用了一个基本的CSS文件以添加一些样式;你可以从本书对应网站上下载该文件(CSS文件将在整个可下载脚本的ch02文件夹中)。

上述表单将被提交给login.php。该脚本将进行如下工作:

  • 验证提交的电子邮件地址。
  • 验证提交的密码。
  • 确认提交的值与以前存储在数据库中的相符。
  • 如果匹配,发送一个cookie或者启动一个跟踪用户的会话。
  • 将用户重定向到欢迎页面。

如果你还不知道如何自己实现PHP和MySQL,在以后的章节中,你将看到这个表单的所有实际运行状况。这是基线功能,不管浏览器的JavaScript设置和能力如何,这些功能都有效。如果客户能够加载一个HTML页面,这个系统就很好。下一步是对其进行渐进增强。

2.5.2 添加JavaScript层次
在我们所举的特殊例子中,渐进增强意味着JavaScript将被用于在客户端验证表单数据,仅允许在数据通过时将表单提交给服务器(正如图1.4中的注册示例)。

首先要注意这个表单和没有绑定JavaScript的表单之间的唯一区别—每个元素都有name属性和id属性。name值在表单数据提交到服务器端PHP脚本时使用,而JavaScript将使用id属性值。从逻辑上说,这两个值对于每个元素来说都相同。页面上的每个元素(表单或者其他元素)都必须有唯一的id值。

这个渐进增强的页面还使用了一个外部JavaScript文件login. js。它应该包含在HTML页面中body结束标志之前:

<script src="js/login.js"></script>
现在,至少对于本书的这个阶段来说,这个文件的内容有些复杂。为了理解这个文件当中应该有什么样的JavaScript代码,你必须有事件处理的基本知识。

2.5.3 处理事件
正如第1章中所提到的,JavaScript是一种事件驱动语言,这意味着它仅在事件发生之后进行某些工作。事件的例子包括:

  • 网页加载;
  • 单击一个元素,如按钮或者链接;
  • 在表单元素中输入文本;
  • 将光标移动到一个元素上(也就是mouseover事件);
  • 将光标从一个元素上移开(也就是mouseout事件)。

为了让JavaScript验证一个HTML表单,你必须确定触发验证代码的事件。常用于表单验证的事件如下:

表单提交;
单击提交按钮(这也触发表单提交事件);
改变表单元素的值;
表单元素失去焦点时(不管值是否改变都触发)。
第8章“事件处理”更详细地讨论事件。现在,我们只是在提交的时候验证表单,为此,必须为表单添加一个事件监听器(Event listener)。事件监听器是一个在“这个事件”发生在“这个对象”上时调用的函数。每个对象,不管是整个浏览器窗口还是页面中的具体元素(不管是否为表单元素),都有能够触发的特定事件。被调用的函数通常是你自己定义的。对象、事件类型和函数的组合造成了多种多样的可能性。

为了观察表单的提交事件,我们首先要获得对表单本身的引用。使用 document 对象的 getElement-ById()方法是一种简单而可靠的方式。document对象代表整个HTML内容:从html开始标记到head和body等元素。

Document对象有一个getElementById()方法,它以ID名称为参数,返回对应元素的引用,返回值可以赋值给一个变量供以后使用:

var loginForm = document.getElementById('loginForm');
此时,只要有一个元素(毫无疑问可以是任何类型)的id值为loginForm, loginForm变量将是对该元素的引用。第9章更加详细地研究DOM操纵,但是getElementById()方法非常重要且很容易使用,所以值得在本章里介绍。

有了对表单的引用,就可以用下列代码添加事件监听器:

_element_.on_event _= _function_;
例如:

loginForm.onsubmit = validateForm;
下文的补充说明中将更详细地解释这种语法,但是这一代码行只是说明在loginForm元素遇到一个提交事件时,将调用validate-Form()函数。注意,该函数的名称用在这一赋值语句的右侧,没有引号,结尾也没有圆括号。下面这两种写法都不正确:

loginForm.onsubmit = 'validateForm'; // NO!
loginForm.onsubmit = validateForm(); // NO!

理论上,下一步应该是定义validate-Form()函数,这个函数执行实际的表单验证。遗憾的是,需要先执行另一个步骤。

我将对此加以解释。

从一个服务器请求文档时,客户将按照顺序接受文档的数据。对于HTML页面,这意味着浏览器首先接收DOCTYPE,然后是html开始标记、head标记和head的内容,接着是文件体及其内容,以此类推,直到文档结束。当浏览器遇到对其他必须下载的素材的引用时,就必须相应地进行下载,这些素材包括CSS文件、图像和其他媒体、JavaScript、Flash等。就DOM操纵来说,这一过程很重要,因为浏览器在完全了解HTML 页面(图2.9)之前无法表现DOM。对于JavaScript,这意味着在浏览器加载页面的 HTML 之前,你无法安全地使用 document. getElementById()。

screenshot

知道何时能够安全地引用DOM元素的最可靠方法是确认浏览器完全加载了整个页面。当然,这是一个事件,可以设置事件监听器,观察事件的发生:

window.onload = init;
提示: 当JavaSript放在靠近文档结尾处时,网站的加载似乎更快,这是因为浏览器在等待JavaScript加载时必须暂停HTML的渲染。

注意: 我打算简化浏览器下载和加载网页的过程,以表达关键的要点。如果你对此过程感到好奇,在网上搜索就能找到很多细节。

对象事件属性

第1章中曾经提到,对象是一个特殊的变量类型,具有预先定义的属性(也就是它自己的内部变量)和方法(即函数)。对象记法(或者圆点)语法用于访问对象的属性和方法。loginForm.onsubmit = validateForm这样的代码将validateForm()函数赋给loginForm对象的onsubmit属性。这似乎有些奇怪,但是这和将数值赋值给一个变量的概念相同: var num = 2; 但在事件监听器的情况下,变量是对象的一个属性,赋给的值是一个函数:稍微复杂一些,但是原理相同。 loginForm对象有一个onsubmit属性,因为loginForm代表一个或者多个触发提交事件的表单元素。这段代码不能用于一个链接,因为链接没有onsubmit属性(但是链接有onclick属性)。引用基于事件的对象属性时,全部使用小写字母:onsubmit而不是onSubmit。 对于上述赋值语句,函数必须与这个事件相关联;因此函数的名称在语句的右侧提供。你不能在函数名称上加引号,这样它将变成一个字符串值而不是函数。你也不能使用functionName()的形式,带上圆括号表示一次实际的函数调用。

这段代码表明,window对象触发加载事件时应该调用init()函数。然后,init()函数可以将事件监听器添加到表单,因为这时进行DOM引用是安全的:

function init() {
    var loginForm = document.getElementById('loginForm');
   loginForm.onsubmit = validateForm;
}

第 7 章“创建函数”介绍自定义函数所必须了解的内容,但是函数的基础知识实际上很简单。首先,使用function关键字,后面跟上函数的名称和圆括号。(init函数的调用很常见,init是Initialize(初始化)的缩写,该函数用于初始化一些必要的JavaScript和浏览器行为。)该函数的实际代码出现在大括号之间,代表着函数调用时将会执行的任务。

作为附加的保护措施,我们在这里添加对象检测,这样表单的事件监听器将仅在浏览器支持document.getElement-ById()的方法下才被添加:

function init() {
     if (document && document.getElementById) {
          var loginForm = document.getElementById('loginForm');
          loginForm.onsubmit = validateForm;
     }
}

现在有两个事件监听器。第一个监听window的load事件,该事件对于每个页面只发生一次,触发时调用init()函数。第二个监听器等待表单的提交,可能发生任意次(也可能一次都不发生)。每当该事件发生时,都调用validateForm()函数。定义该函数是渐进增强的最后一步。

注意: 实际上,浏览器对document对象和getElementById()方法的支持已经超过10年之久,所以对象检测的这种特殊用法实际上并没有必要。

2.5.4 执行验证
validateForm()函数应该验证表单数据并返回表示数据有效性的一个布尔值。如果函数返回true(真),就允许表单提交给服务器端脚本。如果函数返回false(假),那么表单的提交将被阻止。

该函数的外壳如下:

function validateForm() {
}

现在是执行基本验证的时候了,这些验证发生在上述的外壳中。对于电子邮件地址和密码,验证应该检查是否存在某个值(确认电子邮件地址格式有效是可能的,但是需要许多代码)。对于文本输入,可以检查其长度完成简单的验证(也就是证明输入了任意的内容)。这一切从获得每个输入域的引用开始,仍然使用getElementById():

var email = document.getElementById('email');
var password = document.getElementById('password');

提示: 记住,如果网页使用HTML5,而浏览器支持HTML5,将会应用自动化的客户端验证(如前面的插图所示)。

这时,每个变量是对应的表单元素的一个引用。引用变量的value属性就能找到元素的当前值:如email.value和password.value。因为两者都是文本元素,value属性都为一个字符串值,甚至可能是一个空字符串。JavaScript中的所有字符串都有length属性,存储该串中的字符数量。因此,email.value.length是输入到电子邮件输入域的字符数量,然后,可以根据字符数量创建一条简单的条件语句:

if ( (email.value.length > 0) && (password.value.length > 0) ) {
     return true;
} else {
     return false;
}

注意: 检查元素值的长度对于文本输入域是有效的,其他类型的元素以不同的方式验证。

这里使用的是一个简单的验证例程。除非两个表单元素中都输入了一些内容,否则表单就不会提交给服务器端脚本。但是,除了阻止表单提交以外,用户还应该知道错误的发生。可以用更高级的方式提醒用户,但是现在一个警告框可能就足够了(图2.10和图2.11):

if ( (email.value.length > 0) && (password.value.length > 0) ) 
{
     return true;
} else {
     alert('Please complete the form! ');
     return false;
}

screenshot

注意: 客户端验证对于最终用户来说很方便,服务器端验证始终是必要的。

你现在有了一个简单、渐进增强、无干扰的JavaScript,在HTML表单发送到服务器之前进行验证。下面的代码块展示了汇总后的所有代码,以及说明关键部分的一些注释。该脚本有三个顶级的(也就是非嵌套的)组件:

validateForm()函数的定义;
init()函数的定义;
将init()函数注册为window.onload事件监听器。
注意: 因为服务器端脚本login.php尚未编写,在表单通过验证时,浏览器试图访问不存在的文件,你将会看到服务器错误。

但是,出于技术性的原因,这3个组件编写的顺序没有关系,我选择以这种顺序编码是因为:

validateForm()在被init()函数引用之前定义。
init()函数在被赋予window.onload属性之前定义。
同样,这种顺序也不是必需的,但是这对于编码的结构有逻辑上的意义。每个函数也以如下代码开始:

'use strict';
使用这一行代码的原因在“引用严格模式”补充说明中加以解释。

// login.js
// Function called when the form is submitted.
// Function validates the form data and returns a Boolean value.
function validateForm() {
    'use strict';
    // Get references to the form elements:
    var email = document.getElementById('email');
    var password = document.getElementById('password');
    // Validate!
    if ( (email.value.length > 0) && (password.value.length > 
0) ) {
         return true;
    } else {
         alert('Please complete the form! ');
         return false;
    }
} // End of validateForm() function.
// Function called when the window has been loaded.
// Function needs to add an event listener to the form.
function init() {
    'use strict';
    // Confirm that document.getElementById() can be used:
    if (document && document.getElementById) {
         var loginForm = document.getElementById('loginForm');
         loginForm.onsubmit = validateForm;
    }
} // End of init() function.
// Assign an event listener to the window's load event:
window.onload = init;

引用严格模式

JavaScript自己的严格模式和已经讨论过的浏览器严格模式不同,是在你所写的代码中强制更严格的JavaScript行为的一种方式。严格模式在ECMAScript 5中加入,通过在JavaScript中放置如下字符串引用: 'use strict'; 这一行代码在每个脚本开始可以使用一次,但是正如你在本书中所看到的,用作每个函数的第一行更为可靠。 引用严格模式时,JavaScript将与非严格模式中的执行方式略有不同,一般来说,严格模式将: 导致可能有问题的代码生成错误; 改进安全性和性能; 对将在该语言的未来标准中被删除的代码提出警告。 简而言之,严格模式强制你编写更好的代码,这是一件非常非常好的事情。 如果你希望了解严格模式强制形成的变化细节,可以在网络上搜索,但是在现阶段的学习中对你没有太多意义。

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
《JavaScript设计与开发新思维》——2.6 窃取这段JavaScript
习惯于查看其他人的JavaScript并不是为了窃取它(但是“查看这段JavaScript”不像本小节的标题那么招摇),而是为了启发自己。你无疑会遇见超出你的理解力的代码、过时的代码和与本书倡导的方法相悖的代码。但是通过研究其他人的工作,你将对这种重要编程语言的范围、能力和历史有更好的认识。
1304 0
《JavaScript设计与开发新思维》——第1章 (重新)介绍JavaScript 1.1 什么是JavaScript
今天的JavaScript是一种被误解的编程语言,从JavaScript所能做到的,到它不能做到的,再到JavaScript不是什么(JavaScript不是Java),关于这种当今Web的核心技术有许多的混淆。
1751 0
《JavaScript设计与开发新思维》——1.2 JavaScript的历史
JavaScript是ECMAScript(发音为ECK-MA-Script)的一个实现,ECMAScript是一个不为人知的标准国际脚本语言(ECMA是欧洲计算机制造商协会英文名称European Computer Manufacturers Association的缩写)。
1209 0
《JavaScript设计与开发新思维》——1.5 为什么说JavaScript是一种好语言
最后,JavaScript是一种好语言还有一个原因:其他人几乎肯定能理解你所要完成的工作。当然,对于所有已经确立地位的语言来说这一点都成立,但是对于JavaScript,可能由于代码始终公开,聪明的程序员们更倾向于分享这些思路。通常,聪明的程序员还从这些漂亮的代码中建立公共程序库或者框架。
1192 0
《JavaScript设计与开发新思维》——1.6 JavaScript版本和浏览器支持
我们已经说明过,JavaScript的核心来自于ECMAScript,ECMAScript在2009年推出了最新的第5版。JavaScript的当前版本是基于ECMAScript 5的1.8.5版本,于2010年7月推出。
1495 0
《JavaScript设计与开发新思维》——1.7 JavaScript编程目标
开始一次新的尝试时,不管是第一次学习JavaScript还是为了学习更好、更现代的JavaScript技术,都应该设定一些目标。网站的目的当然是为了让客户(使用Web浏览器的最终用户)查看和使用。如果访问者无法使用一个网站,你作为Web开发人员的工作就失败了。
1385 0
《JavaScript设计与开发新思维》——1.8 小结
本节书摘来自异步社区《JavaScript设计与开发新思维》一书中的第1章,第1.8节,作者:【美】Larry Ullman著,更多章节内容可以访问云栖社区“异步社区”公众号查看
1173 0
《JavaScript设计与开发新思维》——第2章JavaScript 2.1 选择DOCTYPE
希望你已经了解了所有这些选项,但是如果你不了解或者只知道这里讲述的这一些,那也是可以理解的。真正的目标并不只是创建通过验证规程的(X)HTML页面,而是使这些页面在浏览器中的外观和功能都正确,这也就是DOCTYPE起作用的地方:Web浏览器将根据DOCTYPE选择操作模式。
1353 0
《JavaScript设计与开发新思维》——2.3 为HTML添加JavaScript
在HTML页面中直接出现而不存在单独文件中的小段JavaScript仍然很常见。但是由于JavaScript代码变得更加复杂,或者在网站上的多个页面中重复,使用外部文件就更有意义,文件中的JavaScript代码更加容易维护。
1501 0
《JavaScript设计与开发新思维》——2.4 关键的开发方法
渐进增强(progressive enhancement)在2003年第一次提出,直至今天仍在采用。渐进增强站到了功能退化的反面:功能退化从想要得到的功能开始,在完整功能不受支持的情况下提供备用内容,而渐进增强从最小功能的一个基线开始,然后在此基础上改进—增强用户体验—添加仅在客户支持时有效的“丰富”功能(图2.7)。
1422 0
+关注
异步社区
异步社区(www.epubit.com)是人民邮电出版社旗下IT专业图书旗舰社区,也是国内领先的IT专业图书社区,致力于优质学习内容的出版和分享,实现了纸书电子书的同步上架,于2015年8月上线运营。公众号【异步图书】,每日赠送异步新书。
12049
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
低代码开发师(初级)实战教程
立即下载
阿里巴巴DevOps 最佳实践手册
立即下载
冬季实战营第三期:MySQL数据库进阶实战
立即下载