【javascript】JS+DOM实现图片库(改进版)

本文介绍了一种使用JavaScript和DOM实现的图片库,强调了平稳退化和代码分离。通过检查浏览器对DOM方法的支持,将事件处理函数绑定到元素,确保在JavaScript不可用时仍能正常浏览。同时,文章探讨了showPic函数的优化,包括对HTML结构假设的减少和键盘访问的支持,以及DOM Core和HTML-DOM的区别。
摘要由CSDN通过智能技术生成

一、它支持平稳退化吗

<li>
  <a href="images/fireworks.jpg" onclick="showPic(this); return false;" title="A fireworks display">Fireworks</a>
</li>

可以发现,在没有javascript的情况下,浏览器会沿着href属性给出的链接前进,虽然用户体验比用javascript的效果要逊色,但网页的基本功能未受到损害。即,它支持平稳退化。

二、它的javascript与HTML标签是分离的吗

<li>
  <a href="images/fireworks.jpg" onclick="showPic(this); return false;" title="A fireworks display">Fireworks</a>
</li>

很明显,onclick事件处理函数是直接插入到HTML中的,因此不是分离的。理想情况下,应该是在外部文件里完成加添onclick事件处理函数的工作。

首先需要把js代码移动HTML,但需要把js代码与HTML标签关联起来,可以分别给每个图片添加同一个class属性,但过于复杂。我们可以发现图片链接都包含在ul元素里,因此值需要给ul元素设置一个id。

		<ul id="imagegallery"> 
			<li>
				<a href="#" title="A fireworks display">Fireworks</a>
			</li>
			<li>
				<a href="images/coffee.jpg" title="A cup of coffee">Coffee</a>
			</li>
			<li>
				<a href="images/rose.jpg" title="A red rose">Rose</a>
			</li>
			<li>
				<a href="images/bigben.jpg" title="The famous clock">Big Ben</a>
			</li>
		</ul>

1.添加事件处理函数
需要编写一个函数关联到onclick事件上。
【函数任务】

  • 检查当前浏览器是否理解getElemenTagName
  • 检查当前浏览器是否理解getElementsByTagName
  • 检查当前页面是否存在一个id为imagegallery的元素
  • 遍历imagegalley元素中所有的链接
  • 设置onclick事件,让它有相关链接被点击时完成以下事件:把这个链接作为参数传递给showPic函数,并且取消链接被点击时的默认行为。

(1)检查点
首先,需要检查浏览器是否理解getElementsByTagName和getElementById的方法,此外,还需要检查是否存在id等于imagegalley的元素,如果不存在这个元素,那么函数将无需执行。

if(!document.getElementsByTagName) return false;
if(!document.getElementById) return false;
if(!document.getElementById("imagegallery")) return false;

(2)变量里有什么
使用变量gallery来保存图片库。
使用变量links来保存图片库的a标签

var gallery = document.getElementById("imagegallery");
var links = gallery.getElementsByTagName("a");

(3)遍历
接着,需要遍历处理links数组中的各个元素,可以使用for循环来完成。

for(var i=0;i<links.length;i++){

}

(4)改变行为
接下来,需要完成的操作是改变links数组中各个元素的行为。首先定义了一个匿名函数,它把links[i]元素的onclick事件处理函数指定为这个匿名函数,这个匿名函数的所有操作将在links[i]元素对应的链接被点击时执行。
传递给showPic函数的参数是this,this代表links[i],表示此时与onclick方法关联的那个元素。此外还需要禁用有关链接的默认行为。

links[i].onclick = function(){
	showPic(this);
	return false;
}

(5)完成javascript函数

for(var i=0;i<links.length;i++){
	links[i].onclick = function(){
		showPic(this);
		return false;
	}
}

2.共享onload事件
我们必须执行prepareGallery函数才能对onclick事件进行绑定,如果立即执行这个函数,它将无法工作,因为在HTML文档加载之前执行脚本DOM是不完整的。

应该让这个函数在网页加载完毕之后执行,网页加载完成之后会触发一个onload事件,我们需要把prepareGallery函数绑定在这个事件上。

window.onload = prepareGallery;

假设需要绑定两个函数,如果把它们逐一绑定到onload事件上,只有最后一个才被实际执行。

有一种解决方案:先创建一个匿名函数来容纳这两个函数,然后把这个匿名函数绑定到onload事件上。

window.onload = function(){
	firstFunction();
	secondFunction();
}

还有一个最佳解决方案:编写额外的代码,即addLoadEvent函数,它有一个参数,打算在页面加载完毕时执行的函数名。
【该函数要完成的操作】

  • 把现有的winow.onloa事件处理函数的值存入变量oldload
  • 如果在这个处理函数上没有绑定函数,就把新函数添加给它
  • 如果在这个处理函数上已经绑定函数,就把新函数追加到现有指令的末尾。
function addLoadEvent(func){
	var oldonload = window.onload;
	if (typeof window.onload != 'function'){
        window.onload = func;
	}else {
        window.onload = function(){
            oldonload();
            func();
            }
	}
}

如果需要把prepareGallery与onlad事件绑定,只需要一行代码。

addLoadEvent(prepareGallery);

三、不要做太多的假设
showPic函数负责完成两件事:一是找出id属性值为placeholder的图片并修改其src属性;二是找出id是description的元素并修改其第一个子元素的nodeValue属性。
第一件事实这个函数必须完成的任务,第二件事只是补充。因此,决定把检查工作分成两个步骤:主要placeholder图片存在,即使description元素不存在,切换新图片的操作也照常进行。

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("titile");
        var description = document.getElementById("description");
        description.firstChild.nodeValue = test;
	}
	return false;
}

改进后的showPic函数不在假设HTML文档里肯定有placeholder图片和description元素,即使文档里没有placeholder图片,也不会发生错误。

可是还有一个问题:如果把placeholder图片删除,那么将会出现,无论点击imagegalley清单里的哪个链接,都不会产生任何反应。这意味着脚本不能实现平稳退化。

问题在于prepareGallery函数做出了一个假设:showPic函数肯定正常返回,因此该函数取消了onclick事件的默认行为。

实际上,是否要返回false以取消onclick事件的默认行为,应该有showPic函数决定:如果图片切换成功,返回true,如果不成功,返回false。

因此,应该在返回前验证showPic函数的返回值,以便决定是否阻止默认行为

links[i].onclick = function(){
	return !showPic(this)
}

现在,如果showPic返回true,我们就返回false,浏览器就不会打开默认链接;如果showPic返回false,我们就认为图片没有更新,于是返回true以让默认行为发生。

四、优化

每个链接都有一个title属性,为检查其是否存在:

if (whichpic.getAttribute("title")){
	var text = whichpic.getAttribute("title");
}else{
	var text = "";
}

检查placeholder元素是否存在,切为一张图片,可以使用nodeName属性来检查:

if (placeholder.nodeName != "IMG") return false;

注意:nodeName属性总是返回一个大写字母的值,即使元素在HTML文档中是小写的。

检查description元素的第一个子元素是否为一个文本节点:

if (description.firstChild.nodeType == 3){
    description.firstChild.nodeValue = text;
		}

在增加了几项测试之后,showPic函数的代码变得更多了。在实际工作中, 需要自己决定是否需要这些检查。理想情况下,脚本不应该对HTML文档的结构和内容有太多假设

五、键盘访问
prepareGallery函数的核心代码是:

links[i].onclick = function(){
return !showPic(this);

当这个链接被点击时,showPic函数开始执行。
但用户还可以使用键盘来操作,有个onkeypress的事件处理函数,它是专门用来处理键盘事件的,按下键盘的任意键都会触发该事件。

为了让onkeypress事件与onclick事件触发同样的行为,可以把onclick事件的所有功能付给onkeypress。

links[i].onkeypress = links[i].onclick;

小心使用onkeypress:
使用这个事件处理函数很容易出问题,用户每按下一个按键都会触发它。绑定在onkeypress事件上的处理函数上返回的是false,那些只是用键盘访问的用户将永远无法离开当前链接
然而,使用Tab键移动到某个链接然后按下回车键的动作也会触发onclick事件,因为这里不只采用onclick事件处理函数。

六、DOM Core 和HTML-DOM

至此,在编写javascript代码时用到了以下几个DOM方法:
getElementById、getElementsByTagName、getAttribute、setAttribute
这些方法都是DOM Core的组成部分,支持DOM的任何一种程序设计语言都可以使用它们。

在使用javascript语言和DOM为HTML文件编写脚本时,还有许多属性可供选择。

HTML-DOM提供了一个forms对象。

document.getElementsTagName("forms")
可以简化为:document.forms

HTML-DOM还提供了许多描述HTML元素的属性,如src

element.getAttribute("src")
可以简化为:element.src

这些方法和属性可以相互替换,同样的操作可以使用DOM Core和HTML-DOM来实现。通常HTML-DOM会更加简短,但它们只能用来处理Web文档。

完整代码:
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>
		<ul id="imagegallery">
			<li>
				<a href="images/fireworks.jpg" title="A fireworks display">Fireworks 
				<img src="images/small_fireworks.jpg" alt= "Fireworks" />
				</a>	
			</li>
			<li>
				<a href="images/coffee.jpg" title="A cup of coffee">Coffee
				<img src="images/small_coffee.jpg" alt = "coffee" />
				</a>
			</li>
			<li>
				<a href="images/rose.jpg" title="A red rose">Rose
				<img src="images/small_rose.jpg" alt = "rose" />
				</a>
			</li>
			<li>
				<a href="images/bigben.jpg" title="The famous clock">Big Ben
				<img src="images/small_bigben.jpg" alt = "bigben" />
				</a>
			</li>
		</ul>
		<img id="placeholder" src="images/peng.jpg" alt="my peng" />
		<p id="description" >Choose an image.</p>
	<script type="text/javascript" src="scripts/myjs.js"></script>
	</body>
</html>

外部javascript:

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


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);
		}
	}
}

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;
}


addLoadEvent(prepareGallery);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值