javascript 动态创建标记的几种方法
学习JavaScript DOM编程艺术一书所做的一些笔记。
1、
传统技术document.write和innerHTML实现动态创建标记
document.write 可以方便地把字符串插入到文档里,样例如下。
test.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Test</title>
</head>
<body>
<script>
document.write("<p>This is inserted.</p>");
</script>
<div id="testdiv">
<p>This is <em>my</em> content.</p>
</div>
<script type="text/javascript" src="scripts/example.js"></script>
</body>
</html>
example.js:
window.onload = function() {
var testdiv = document.getElementById("testdiv");
alert(testdiv.innerHTML);
}
特点:
- js和html代码混杂在一起,是一种很不好的做法。
- innerHTML属性在处理数据时很粗放,毫无细节可言。
- 以上二者相比较,后者至少可以实现js分离。
2、
DOM方法createElement、createTextNode、appendChild和insertBefore动态创建标记
通过以下图片库的实现,理解这几个DOM方法是怎么使用的。
gallery.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Image Gallery</title>
<link rel="stylesheet" href="styles/layout.css" media="screen" />
<script type="text/javascript" src="scripts/showPic.js"></script>
</head>
<body>
<h1>Snapshots</h1>
<!--
<ul>
<li><a href="images/fireworks.jpg" οnclick="showPic(this); return false;" title="A fireworks display">Fireworks</a></li>
<li><a href="images/coffee.jpg" οnclick="showPic(this); return false;" title="A cup of back coffee">Coffee</a></li>
<li><a href="images/rose.jpg" οnclick="showPic(this); return false;" title="A red,red rose">Rose</a></li>
<li><a href="images/bigben.jpg" οnclick="showPic(this); return false;" title="A famous clock">Big Ben</a></li>
</ul>
-->
<ul id="imagegallery">
<li><a href="images/fireworks.jpg" title="A fireworks display">Fireworks</a></li>
<li><a href="images/coffee.jpg" title="A cup of back coffee">Coffee</a></li>
<li><a href="images/rose.jpg" title="A red,red rose">Rose</a></li>
<li><a href="images/bigben.jpg" title="A famous clock">Big Ben</a></li>
</ul>
<!--
<img id="placeholder" src="images/placeholder.gif" alt="my image gallery" />
<p id="description">Choose an image.</p>
-->
</body>
</html>
showPic.js:
function addLoadEvent(func) {
var oldonload = window.onload;
if (typeof window.onload != 'function') {
window.onload = func;
} else {
window.onload = function() {
oldonload();
func();
}
}
}
// 自定义实现的insertAfter函数,因为js中只提供了insertBefore函数
function insertAfter(newElement,targetElement) {
var parent = targetElement.parentNode;
if (parent.lastChild == targetElement) {
parent.appendChild(newElement);
} else {
parent.insertBefore(newElement,targetElement.nextSibling);
}
}
// 通过该函数实现将原在html代码中展示图片和图片描述所使用的锚点,改为在js中动态去生成
// 实现了js和html代码的完全分离
function preparePlaceholder() {
// 首先是标签可用性检查
if (!document.createElement) return false;
if (!document.createTextNode) return false;
if (!document.getElementById) return false;
if (!document.getElementById("imagegallery")) return false;
// 创建一个元素节点img,并设置好它的各种属性
var placeholder = document.createElement("img");
placeholder.setAttribute("id","placeholder");
placeholder.setAttribute("src","images/placeholder.gif");
placeholder.setAttribute("alt","my image gallery");
// 创建一个元素节点p
var description = document.createElement("p");
description.setAttribute("id","description");
// 创建了一个文本节点desctext,并在下一步中将其添加为description的子节点
var desctext = document.createTextNode("Choose an image");
description.appendChild(desctext);
// 找到图片库的元素id,然后把展示图片和说明文字使用的两个锚点放在其后
var gallery = document.getElementById("imagegallery");
insertAfter(placeholder,gallery);
insertAfter(description,placeholder);
}
// 通过该函数将js与html分离,且在该函数中做出了多处优化设计
function prepareGallery() {
// 检查当前浏览器是否理解getElementsByTagName
if (!document.getElementsByTagName) return false;
// 检查当前浏览器是否理解getElementsById
if (!document.getElementById) return false;
// 检查当前网页是否存在一个id为imagegallery的元素
if (!document.getElementById("imagegallery")) return false;
var gallery = document.getElementById("imagegallery");
var links = gallery.getElementsByTagName("a");
// 遍历imagegallery元素中的所有链接
for ( var i=0; i<links.length; i++) {
// 设置onclick事件,让它在有关链接被点击时完成以下操作:
// 把这个链接作为参数传递给showPic函数
// 取消链接被点击时的默认行为,不让浏览器打开这个链接。而同时在showPic函数调用失败时,又允许链接点击行为的平稳退化。
links[i].onclick = function() {
return showPic(this) ? false : true;
}
// 将键盘操作都视同为点击操作
links[i].onkeypress = links[i].onclick;
}
}
function showPic(whichpic) {
// 检查当前网页是否存在一个id为placeholder的元素
if (!document.getElementById("placeholder")) return false;
var source = whichpic.getAttribute("href");
var placeholder = document.getElementById("placeholder");
// 检查placeholder元素的nodeName是否为IMG
if (placeholder.nodeName != "IMG") return false;
placeholder.setAttribute("src",source);
// 检查description元素是否存在
if (document.getElementById("description")) {
// 检查title属性是否存在,利用三元操作符为找不到title属性时text变量的值为空字符串
var text = whichpic.getAttribute("title") ? whichpic.getAttribute("title") : "";
var description = document.getElementById("description");
// 检查description元素的第一个子元素节点nodeType是否是文本节点
if (description.firstChild.nodeType == 3) {
description.firstChild.nodeValue = text;
}
}
return true;
}
// 触发浏览器加载页面后需要执行的js函数
addLoadEvent(preparePlaceholder);
addLoadEvent(prepareGallery);
3、Ajax方法实现动态创建标记
Ajax是一种异步加载页面的技术,其核心就是XMLHttpRequest对象,这个对象充当着浏览器和服务器之间的中间人的角色。以往的请求都是由浏览器发出,而js可以通过这个对象自己发送请求,同时也自己处理响应。
目前不同浏览器实现XMLHttpRequest对象的方式不太一样,为了保证跨浏览器,需要做一些兼容性设计。
从以下例子中,理解怎么使用该方法。在本样例中,先创建了一个XMLHttpRequest对象,然后从一个文本文件中获取了一段内容,在浏览器页面中进行展示。
ajax.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Ajax</title>
</head>
<body>
<div id="new"></div>
<script src="scripts/getHTTPObject.js"></script>
<script src="scripts/getNewContent.js"></script>
</body>
</html>
example.txt
This was loaded asynchronously!
getHTTPObject.js
function getHTTPObject() {
if (typeof XMLHttpRequest == "undefined")
XMLHttpRequest = function () {
try { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); }
catch (e) {}
try { return new ActiveXObject("Msxml2.XMLHTTP.3.0"); }
catch (e) {}
try { return new ActiveXObject("Msxml2.XMLHTTP"); }
catch (e) {}
return false;
}
return new XMLHttpRequest();
}
getNewContent.js
function addLoadEvent(func) {
var oldonload = window.onload;
if (typeof window.onload != 'function') {
window.onload = func;
} else {
window.onload = function() {
oldonload();
func();
}
}
}
function getNewContent() {
var request = getHTTPObject();
if (request) {
request.open( "GET", "example.txt", true);
// onreadystatechange会在服务器给XMLRequest对象送回响应的时候被触发执行
// 注意如果不是定义一个匿名处理函数,而是引用一个已定义的函数,则不要在函数名后加括号。
// 因为加括号表示立即调用函数,而在此只想把函数自身的引用赋值给 onreadystatechange事件。
request.onreadystatechange = function() {
// readyState有5个可能的值,分别是0表示未初始化,1表示正在加载,2表示加载完毕,3表示正在交互,4表示完成
if (request.readyState == 4) {
var para = document.createElement("p");
// 服务器返回的数据可以通过两个属性进行访问,一个是 responseText,另一个是 responseXML
// responseXML保存的是Content-Type头部中指定为"text/xml"的数据,其实是一个 DocumentFragment对象,可以使用DOM方法处理。
var txt = document.createTextNode(request.responseText);
alert(request.responseXML);
para.appendChild(txt);
document.getElementById('new').appendChild(para);
}
};
request.send(null);
} else {
alert('Sorry, your browser doesn\'t support XMLHttpRequest');
}
}
addLoadEvent(getNewContent);
注:在使用Ajax时千万要注意同源策略。使用XMLHttpRequest对象发送的请求只能访问与其所在的HTML处于同一个域中的数据,不能向其他域发送请求。此外chome浏览器限制了Ajax使用file协议从自己的硬盘里加载文件,所以上面的代码在chome中会报错如下:
getNewContent.js:32 Failed to load file:///D:/work/gallery/example.txt: Cross origin requests are only supported for protocol schemes: http
注:因为原书出版时间较早,使用的例子已经不满足新版本浏览器的安全要求,以上样例中的使用方法在ie11中同样被禁用。了解即可,也可以手动打开下浏览器对js脚本的相关限制以便于观察效果。