本节书摘来自异步社区《JavaScript精粹(修订版)》一书中的第1章,第1.5节,作者:【英】Edwards, J. , 【澳】Adams, C.著,更多章节内容可以访问云栖社区“异步社区”公众号查看
1.5 内容和行为的隔离(谨慎地编码)
将内容从行为中分离,意味着按照网页的结构分离出不同的层次来。Jeffrey Zeldman曾经将Web开发形容为“三条腿的板凳”1,分别是内容(HTML)、表示(CSS)、行为(JavaScript),他不仅指出三者在功能上的不同,同时也表明他认为这三者应该被互相隔离开来。
好的隔离方式将使得网站更容易维护,也更容易被理解和使用,同时对于老的或者支持特性较少的浏览器也能够提供相应的访问方式。
方 法
以下是一种极端情况,正好与理想的行为和内容互相分离的方法南辕北辙,也可以直接在事件处理属性中写入内嵌的代码。但这会把页面搞得一团糟,应该极力避免:
<div id="content"
onmouseover="this.style.borderColor='red'"
onmouseout="this.style.borderColor='black'">
可以把完成这些工作的代码写成一个函数:
<div id="content"
onmouseover="changeBorder('red')"
onmouseout="changeBorder('black')">
定义一个函数来做这件事可以将大量的代码集中到一个单独的JavaScript文件中:
文件:separate-content-behaviors.js (excerpt)
function changeBorder(element, to)
{
element.style.borderColor = to;
}
不过更好的方法是完全不使用内嵌的事件处理,而使用DOM(文档对象模型)来将事件处理绑定到HTML文档的元素中。DOM是一种标准的编程接口,它使得像JavaScript这样的语言可以直接访问HTML文档的内容,这也消除了出现在HTML文档中的JavaScript代码。HTML代码如下:
<div id="content">
JavaScript代码如下:
文件: separate-content-behaviors.js
function changeBorder(element, to)
{
element.style.borderColor = to;
}
var contentDiv = document.getElementById('content');
contentDiv.onmouseover = function()
{
changeBorder('this');
};
contentDiv.onmouseout = function()
{
changeBorder('this');
};
这种方法允许增加、删除或者修改事件处理,而无需编辑HTML,而且,因为文档本身完全不依赖于这些脚本,所以那些不支持JavaScript的浏览器将丝毫不受影响。这种方法同时也增加了复用性,如果需要,也可以将相同的函数绑定到其他元素上,同样也不需要编辑HTML。
这种方法让我们拥有了通过DOM访问元素的能力,第5章将深入探讨DOM。
隔离的优点
通过将内容和行为分隔开来,不仅使代码具有更广泛的适用性,同时这种分而治之的思考方式也将带来好处。因为HTML和JavaScript完全分离,当我们检视HTML代码的时候,不会忘记这个页面需要显示的核心内容,而这些内容应当不依赖于任何脚本。
Andy Clark把这种方式叫做Web标准甜点2,这是一种有趣的类比,这种比喻方式认为一个好的网站设计应该是这样的:当看过去时,应该看到组成整个甜点的不同层次。这种方式的反面是水果蛋糕,您无法看到蛋糕的不同组成部分。您所能看到的就是搞不清什么材料的一块整个的蛋糕。
讨 论
当把事件处理和如下的元素绑定起来的时候,需要注意,只有在那个元素实际存在的时候才能那么做。如果把处理脚本放到页面的head区,浏览器会报告发生错误,然后拒绝执行代码,因为content div在这个位置还没有被浏览器解读显示,而JavaScript却已经先被处理了。
最直接的方法是把代码放到load事件处理中。这种方式最保险,因为load事件只有在整个页面已经完全载入的时候才会被激发:
window.onload = function()
{
var contentDiv = document.getElementById('content');
┆
};
或者更清楚一点,多写一点代码:
window.onload = init;
function init()
{
var contentDiv = document.getElementById('content');
┆
}
不过使用load事件的问题是,在整个页面中只能使用一次;如果有两个或者更多的脚本需要通过load事件来执行,那么每个脚本都会改写对load事件的处理。解决方法是对load事件采用更好的响应方式,1.8节将继续探讨这个问题。