案例研究:图片库改进版

来源:互联网 发布:好用的网络同传软件 编辑:程序博客网 时间:2024/05/22 03:09
案例研究:图片库改进版
1、它支持平稳退化吗?
第一个问题:如果JavaScript功能被禁用,会怎样?
分析:在没有JavaScript“干扰”的情况下,浏览器将沿着href属性给出的链接前进,用户将看到一张新图片而不是“该页无法显示”之类的出错信息。
第二个问题:与在标记文档里调用JavaScript代码的方式有关:文档的结构与文档的行为分开了吗?换句话说,网页的行为层(JavaScript)是作用于其结构层(HTML)之上的,还是两种代码混杂在一起?
具体到图片库例子,答案是当然“混杂在一起了”。当初我是把onclick事件处理函数直接插入到标记文档里的
<a href=“images/bigben.jpg” onclick=“showPic(this);return false;”title=“The famous clock”>Big Ben</a>
理想情况下,应该在外部文件里完成添加onclick事件处理函数的工作,那样才能让票房文档没有“杂质”。
把JavaScript代码移出HTML文档不是难事,但为了让浏览器知道页面里都有哪些链接有着不一样的行为,我必须找到一种“挂钩”把JavaScript代码与HTML文档中的有关标记关联起来。


photo.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<title>Image Gallery</title>
<link rel = "stylesheet" href = "styles/layout.css" media = "screen"/>
</head>
<body>
<h1>Snapshots</h1>
<script type="text/javascript" src="scripts/showPic.js"></script>
<ul id="imagegallery">
<li>
<a href="images/keke1.jpg" title="A fireworks display">Firewoks</a>
</li>
<li>
<a href="images/keke2.jpg" title="A cup of black coffee">Coffee</a>
</li>
<li>
<a href="images/keke3.jpg" title="A red,red rose">Rose</a>
</li>
<li>
<a href="images/running.jpg" title="The famous clock">Big Ben</a>
</li>
<img id="placeholder" src="images/placeholder.jpg" alt = "my image gallery"/>
<p id="description">Choose an image.</p>
</ul>
</body>
</html>




showPic.js:


function showPic(whichpic)
{
var source = whichpic.getAttribute("href");
var placeholder = document.getElementById("placeholder");
placeholder.setAttribute("src", source);
var text = whichpic.getAttribute("title");
var description = document.getElementById("description");
description.firstChild.nodeValue = text;
}
function prepareGallery()
{
if(!document.getElementsByTagName) return false;
if(!document.getElementById) return false;
if(!document.getElementById("imagegallery")) return false;
var gallery = document.getElementById("imagegallery");
var links = gallery.getElementsByTagName("a");
for(var i=0; i < links.length; i++)
{
links[i].onclick = function()
{
showPic(this);
return false;
}
}
}




2、共享onload事件


我必须执行prepareGallery函数才能对onclick事件进行绑定。如果马上执行这个函数,它将无法完成其工作。因为此时HTML文档完成加载之前,DOM是不完整的。DOM不完整,准确性就无从谈起。
应该让这个函数在网页加载完毕之后立刻执行。网页加载完毕时会触发一个onload事件,这个事件与window对象相关联。为了让事态的发展不偏离计划,必须把prepareGallery函数绑定到这个事件上:
window.onload=prepareGallery;


这里有一个弹性最佳的解决方案———不管你打算在页面加载完毕时执行多少个函数,它都可以应付自如。这个方案需要额外编写一些代码,但好处是一旦有了那些代码,把函数绑定到window.onload事件就非常易行了。
这个函数的名字是addLoadEvent,它是由Simon Willison编写的,它只有一个参数:打算在页面加载完毕时执行的函数的名字。


上面的showPic.js成为下面这个样子:
unction showPic(whichpic)
{
var source = whichpic.getAttribute("href");
var placeholder = document.getElementById("placeholder");
placeholder.setAttribute("src", source);
var text = whichpic.getAttribute("title");
var description = document.getElementById("description");
description.firstChild.nodeValue = text;
}
function prepareGallery()
{
if(!document.getElementsByTagName) return false;
if(!document.getElementById) return false;
if(!document.getElementById("imagegallery")) return false;
var gallery = document.getElementById("imagegallery");
var links = gallery.getElementsByTagName("a");
for(var i=0; i < links.length; i++)
{
links[i].onclick = function()
{
showPic(this);
return false;
}
}
}




function addLoadEvent(func)
{
var oldonload = window.onload;
if(typeof window.onload != 'function')
{
window.onload = func;
}
else
{
window.onload = function()
{
oldonload();
func();
}
}
}


addLoadEvent(prepareGallery);




3、不要做太多的假设


我在showPic函数里发现的第一个问题是,我没有让它进行任何测试和检查。比如,我在代码里用到了id属性值等于palceholder和description的元素,但我并未对这些元素是否存在做任何检查。
改进后的showPic函数:
function showPic(whichpic)
{
if(!document.getElementById("placeholder")) return false;
var source = whichpic.getAttribute("href");
var placeholder = document.getElementById("placeholder");
placeholder.setAttribute("src", source);
if(document.getElementById("description"))
{
var text = whichpic.getAttribute("title");
var description = document.getElementById("description");
description.firstChild.nodeValue = text;
}
return true;
}
改进后的showPic()函数不再假设有关标记文档里肯定存在着palceholder图片和description元素,即使文档里没有palceholder图片,也不会发生任何JavaScript错误。






可是还有一个问题,如果把palceholder图片从标记文档里删掉并在浏览器里刷新这个页面,就会出现这种情况,无论点击imagegellery清单里的哪一个链接,都没有任何响应。这意味着我们的脚本不能平稳退化。此时,应该让浏览器打开那个被点击的链接,而不是让什么事情都不发生。


改进后的perpareGallery函数:
function prepareGallery()
{
if(!document.getElementsByTagName) return false;
if(!document.getElementById) return false;
if(!document.getElementById("imagegallery")) return false;
var gallery = document.getElementById("imagegallery");
var links = gallery.getElementsByTagName("a");
for(var i=0; i < links.length; i++)
{
links[i].onclick = function()
{
return !showPic(this);
}
}
}




4、优化
以上几个函数已经相当完善了,虽然它们的长度有所增加,但它们对标记的依赖和假设已经比原先少多了。
尽管如此,在showPic函数里仍存在一些需要处理的假设。
比如说,假设每个链接都有一个title属性:
var text = which pic.getAttribute(“title”);
为了检查title属性是否真的存在,可以测试它是不是等于null,
如果title属性存在,这个if表达式将被求值为true,如果title属性不存在,这个if表达式将被求值为false。
我们还可以引入更多的检查,比如说,假设description元素的第一个子元素(firstChild)是一个文本节点。我应该对此检查。可以利用nodeType属性来进行这项检查。还记得吗,文本节点的nodeType属性值等于3:
改进后的showPic函数:
function showPic(whichpic)
{
if(!document.getElementById("placeholder")) return false;
var source = whichpic.getAttribute("href");
var placeholder = document.getElementById("placeholder");
if(placeholder.nodeName!="IMG") return false;
placeholder.setAttribute("src", source);
if(document.getElementById("description"))
{
var text = whichpic.getAttribute("title") ? whichpic.getAttribute("title"):"";
var description = document.getElementById("description");
if(description.firstChild.nodeType == 3)
{
description.firstChild.nodeValue = text;
}
}
return true;
}






5、把JavaScript与CSS结合起来
把JavaScript代码从HTML文档里分离出去还带来另一个好处,在把内嵌型事件处理函数移出标记文档时,我在文档里为JavaScript代码留下了一个“挂钩”:
<ul id=“imagegallery”>
这个挂钩完全可以用在CSS样式表里。
改进后的photo.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<title>Image Gallery</title>
<link rel = "stylesheet" href = "styles/layout.css" type = "text/css" media = "screen"/>
</head>
<body>
<h1>Snapshots</h1>
<script type="text/javascript" src="scripts/showPic.js"></script>
<ul id="imagegallery">
<li>
<a href="images/keke1.jpg" title="A fireworks display">
<img src="images/thumbnail_fireworks.jpg" alt="Fireworks"/>
</a>
</li>
<li>
<a href="images/keke2.jpg" title="A cup of black coffee">
<img src="images/thumbnail_coffee.jpg" alt="Coffee"/>
</a>
</li>
<li>
<a href="images/keke3.jpg" title="A red,red rose">
<img src="images/thumbnail_rose.jpg" alt="Rose"/>
</a>
</li>
<li>
<a href="images/running.jpg" title="The famous clock">
<img src="images/thumbnail_bigben.jpg" alt="Big Ben"/>
</a>
</li>
<img id="placeholder" src="images/placeholder.jpg" alt = "my image gallery"/>
<p id="description">Choose an image.</p>
</ul>
</body>
</html>




改进后的layout.css:
body{
font-family: "Helvetica","Arial",serif;
color: #333;
background-color: #ccc;
margin: 1em 10%;
}
h1{
color:#333;
background-color: transparent;
}
a{
color: #c60;
background-color: transparent;
font-weight: bold;
text-decoration: none;
}
ul{
padding:0;
}
li{
float:left;
padding:1em;
list-style:none;
}
img{
display: block;
clear: both;
}


#imagegallery
{
list-style: none;
}
#imagegallery li
{
display: inline;
}
#imagegallery li a img
{
border:0;
}
0 0