HTML标记负责创建网页结构,而JavaScript则用来改变细节,同时JS也能通过动态创建新元素,修改旧元素来改变网页结构.
传统方法
在将文本节点插入到文档中时,在过去经常用到document.write和innerHTML两种方法:
(1)document.write方法
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>动态创建标记</title>
<script src="动态创建标记.js"></script>
</head>
<body>
<script type="text/javascript">
document.write("<p>用document.write()方法插入文本</p>");
</script>
</body>
</html>
结果:
用document.write()方法插入文本
document.write最大的缺点是它违背了 “ 行为应该与表现分离 ”的原则。即使把document.write语句挪到文档外,也需要用< scripte >标签来调用。
(1)document.innerHTML()方法
innerHTML会返回element的所有文本节点,也就是标签之间的所有文本,支持读写,另外值得注意的是:一旦使用innerHTML属性插入,它就会将element的文本节点全部替换为要插入的内容.所以要结合DOM方法精细的处理标记.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>动态创建标记</title>
<script src="test.js"></script>
</head>
<body>
<div id="test"></div>
</body>
</html>
window.onload=function()
{
var test=document.getElementById("test");
test.innerHTML="<p> 使用innerHTML插入文本节点</p>";//写入
alert(test.innerHTML);//读取
}
innerHTML比document.write更有使用价值,但是和.write一样,只对HTML标记有效,对于其他的标记语言(XHTML)将不再收到支持.
DOM方法
DOM添加节点的步骤无外乎3步:创建节点,设置节点样式,添加至DOM树中,以下是步骤中用到的方法:
1. createTextNode, createelement, appendChild.方法:
创建一个元素节点,在元素节点内部用innerHTML插入文本,弹出test的文本:
window.onload=function()
{
var test=document.getElementById("test");
var para=document.createElement("p");//创建一个p类型的元素节点
para.innerHTML="插入一个元素节点,内部插入文本";
test.appendChild(para);
alert(test.innerHTML);
}
结果如下:
创建一个元素节点,在元素节点内部用createTextNode插入文本节点,弹出test的文本:
window.onload=function()
{
var test=document.getElementById("test");
var para=document.createElement("p");//创建一个p类型的元素节点
var txt=document.createTextNode("用createTextNode创建文本节点,并添加在para上");
para.appendChild(txt);
test.appendChild(para);
alert(test.innerHTML);
}
可以看到使用innerHTML似乎更加简洁,但是别忘了,innerHTML只对HTML标记有用,而DOM方法对所有的标记有效,为了确保网页的稳定性,建议使用DOM标准的createTextNode:
练习:
要在body的div标签内插入如下所示的片段:
<body>
<div id="test"></div>
</body>
</html>
<div>This is<img src=""><p>image</p></div>
片段的结构图如下
我们将按照如下步骤进行:
(1)创建div元素节点
(2)创建This is文本节点
(3)创建img元素节点,设置src属性
(4)创建p元素节点
(5)创建image文本节点
(6)将子节点插入到div节点
(7)按ID查找test节点,片段插入节点树
window.onload=function()
{
var division=document.createElement("div");
var txt1=document.createTextNode("This is");
var image=document.createElement("img");
image.href="picture.jpg";
var para=document.createElement("p");
var txt2=document.createTextNode("image");
para.appendChild(txt2);
division.appendChild(txt1);
division.appendChild(image);
division.appendChild(para);
var div=document.getElementById("test");
div.appendChild(division);
alert(div.innerHTML);
}
appendChild是将元素添加在节点树的末尾,有优先次序的问题值得注意。想要插入在指定位置,我们还需要用到insertBefore和insertAfter方法
2. insertBefore和insertAfter方法
我们可以用insertBefore和insertAfter方法将节点插入到指定位置之前或者之后,这里我们重新回到图片库来解析这两个方法的使用。在此之前,我们发现,HTML标记里的最后一行:
<img id="placeholder" src="images/7.png" height="300" width="400" alt="my image gallery"/>
<p id="description">Choose a image</p>
提供挂钩仅仅是为了JavaScript的showPic函数服务的,如果我们让JavaScript动态的创建标记那再好不过,我们现在创建一个preparePlaceHolder函数来生成这两个节点:
function preparePlaceHolder()
{
var placeholder=document.createElement("img");
placeholder.setAttribute("id","placeholder");
placeholder.setAttribute("src","images/7.png");
placeholder.setAttribute("alt","This is my photoGallery");
placeholder.setAttribute("height","300");
placeholder.setAttribute("width","400");
var description=document.createElement("p");
description.setAttribute("id","description");
var txt=document.createTextNode("Choose an image");
description.appendChild(txt);
document.body.appendChild(placeholder);
document.body.appendChild(description);
}
值得注意的是整函数的最后两行,我们直接用DOM提供的属性body来添加appendChild,将两个子元素节点添加在末尾。但是这只是一个巧合,body的末尾恰好就是这两个元素的位置。我们现在想使用 insertBefore和insertAfter方法来插入节点。
(1) parent.insertBefore(newElement,targetElement)
把一个新元素插入到一个旧元素的前面,他们互为兄弟节点,元素节点不允许插入在属性节点和文本节点之后:
var photoGallery=document.getElementById("photoGallery");
photoGallery.parentNode.insertBefore(placeholder,photoGallery);
photoGallery.parentNode.insertBefore(description,photoGallery);
这里使用了parentNode方法来获取目标节点的父元素,是一种通用的方法,把placeholder作为photoGallery的兄弟元素插入到photoGallery之前。description作为photoGallery的兄弟元素插入到photoGallery之前:
(2)insertAfter(newElement,targetElement)
效果似乎还不错,但是这不是我们想要实现的,我们想把placeholder和description插入到photoGallery之后,这个时候我们想设计一个函数insertAfter来在指定元素后面插入兄弟元素:
function insertAfter(newElement,targetElement)
{
var parent=targetElement.parentNode;//获取目标的父节点
if(parent.lastChild==targetElement)
{
parent.appendChild(newElement);
}
else
{
parent.insertBefore(newElement,targetElement.nextSibling);
}
}
这里用到的几个新方法属性:
(1)获取子节点数组中的最后一个节点parent.lastChild
(2)获取元素节点的右兄弟节点nextSibling(使用前要判断是否有右兄弟节点)
这样一来我们就能使用insertAfter属性方法了:
//photoGallery.parentNode.insertBefore(placeholder,photoGallery);
//photoGallery.parentNode.insertBefore(description,photoGallery);
insertAfter(placeholder,photoGallery);
insertAfter(description,placeholder);
对于insertAfter方法,虽然不存在于DOM标准中,但是确实通用的,因为我们用DOM方法编写,具有普适意义,我们完全有必要掌握编写方法。
最后我们给preparePlaceHolder方法向后兼容,检验一些DOM方法功能是否可用:
function preparePlaceHolder()
{
if(!document.createTextNode) return false;
if(!document.createElement) return false;
if(!document.getElementById) return false;
if(!document.getElementById("photoGallery")) return false;
var placeholder=document.createElement("img");
placeholder.setAttribute("id","placeholder");
placeholder.setAttribute("src","images/7.png");
placeholder.setAttribute("alt","This is my photoGallery");
placeholder.setAttribute("height","300");
placeholder.setAttribute("width","400");
var description=document.createElement("p");
description.setAttribute("id","description");
var txt=document.createTextNode("Choose an image");
description.appendChild(txt);
var photoGallery=document.getElementById("photoGallery");
//photoGallery.parentNode.insertBefore(placeholder,photoGallery);
//photoGallery.parentNode.insertBefore(description,photoGallery);
insertAfter(placeholder,photoGallery);
insertAfter(description,placeholder);
}
最后版本的图片库就设置完毕了,这个图片库虽说功能不算是齐全,但是对提高网页的可访问性和可用性,考虑了如下问题:平稳退化,向后兼容,分离JavaScript,同时也考虑一些优化,键盘访问属性,结合CSS等等,这对今后的网页优化有十分重要的启发意义.以下是链接:
图片库最终版