7 动态创建标记
7.1 本章内容
- 传统技术:document.write()和innerHTML属性
- 深入刨析DOM方法:createElement()、createTextNode()、appendChild()、insertBefore()
之前几章使用get方法获取文档特定元素节点,使用setAttributes方法(改变某个属性的值)、nodeValue(改变某个元素节点所包含的文本)之类来处理。
本章通过DOM方法,创建和修改现有元素。
7.2 一些传统方法
7.2.1 document.write()
document.write()方法可以向文档中写入HTML代码,但是只能在页面加载完成后执行,而且只能写入一次。
document.write("<h1>Hello World</h1>");
<html>
<head>
<title>Document.write()</title>
</head>
<body>
<h1>This is the original content</h1>
<script>
document.write("<h1>Hello World</h1>");
</script>
</body>
</html>
很大的缺点,违背行为和结构分离的原则。
XHTML中不允许使用document.write()方法。 使用中应该避免使用document.write()方法。
7.2.1 innerHTML属性
innerHTML属性可以获取或设置元素的innerHTML内容,可以直接写入HTML代码。
<div id="myDiv">
<p>This is <em>my</em> content</p>
</div>
对于innerHTML, id为myDiv元素只有一个子元素p内的全部
对DOM来说,元素节点div,存在属性节点id="myDiv"和子元素节点p。子元素节点p包含文本节点"This is “、元素节点em、文本节点 " content” 即DOM树。
总结来说,innerHTML像是一把大树,子元素是一大坨;DOM就像手术刀十分精细
innerHTML属性可以直接写入HTML代码,会覆盖原有的所容。
document.getElementById("myDiv").innerHTML = "<p>This is <em>my</em> new content</p>";
当需要插入大量HTML代码时,使用innerHTML属性会非常方便。
下面来看下DOM方法
7.3 DOM方法
DOM是文档的表示。DOM包含的信息与文档的信息一一对应,DOM可以获取DOM树上任意一个节点的细节
DOM不但可以获取文档内容,也可以创建和修改文档内容。 但是,setAttribute()方法只能修改元素的属性。在不使用浏览器时,看不到界面的变化
想在节点树上添加内容,就必须要插入新元素节点。
7.3.1 createElement()
创建test.html文件,在body标签中添加一个div元素。
<div id="myDiv"></div>
- 创建新的元素节点。
- 把新元素节点添加到文档树中。
window.onload = function() {
var para = document.createElement("p");
var info = "nodeName: "
info += para.nodeName; // nodeName: P
info += " nodeType: "
info += para.nodeType; // nodeType: 1
alert(info);
}
创建了一个新的元素节点para,取值为p的nodeName属性,nodeType属性为1。
7.3.2 appendChild()
appendChild()方法可以把一个元素节点添加到另一个元素节点的子节点列表中。
var para = document.createElement("p");
var testDiv = document.getElementById("myDiv");
testDiv.appendChild(para);
上述代码创建了一个新的元素节点para,并把它添加到id为myDiv的元素节点的子节点列表中。
7.3.3 createTextNode()
createTextNode()方法可以创建文本节点。
在上节创建了p元素节点,但是没有文本内容。
下面为p创建文本内容,然后将文本内容插入myDiv元素节点中。
var para = document.createElement("p");
var text = document.createTextNode("This is a new paragraph.");
para.appendChild(text);
var testDiv = document.getElementById("myDiv");
testDiv.appendChild(para);
7.3.4 一个更复杂的组合
实现html代码如下:
<div id="myDiv">
<p>This is <em>my</em> content</p>
</div>
window.onload = function() {
var para = document.createElement("p");
var text = document.createTextNode("This is");
para.appendChild(text);
var em = document.createElement("em");
var text2 = document.createTextNode(" my");
em.appendChild(text2);
para.appendChild(em);
var text3 = document.createTextNode(" content");
para.appendChild(text3);
var testDiv = document.getElementById("myDiv");
testDiv.appendChild(para);
}
7.4 重回图片库
跳过了,实现图片库的html代码如下:
<img id="placeholder" src="image/gallery.webp" alt="placeholder">
<p id="description">选择一个图片</p>
- 创建一个img元素节点,设置src属性为"image/gallery.webp",alt属性为"placeholder"。
- 创建一个p元素节点,设置id属性为"description"。
- 把img元素节点和p元素节点添加到文档树中。
window.onload = function() {
var img = document.createElement("img");
img.src = "image/gallery.webp";
img.alt = "placeholder";
var p = document.createElement("p");
p.id = "description";
p.innerHTML = "选择一个图片";
var placeholder = document.getElementById("placeholder");
var description = document.getElementById("description");
placeholder.body.appendChild(img);
placeholder.body.appendChild(p);
}
7.4.1 在已有元素前插入一个元素
insertBefore()方法可以把一个元素节点插入到另一个元素节点的子节点列表中,并指定插入位置。
在元素前插入元素需要知道三件事
- 目标元素
- 新元素
- 插入位置(父元素)
调用insertBefore()方法
parentElement.insertBefore(newElement, targetElement);
对于父元素,DOM中,元素节点的父元素必须是另一个元素节点。(属性节点和文本节点的子元素不允许是元素节点)
因此,在插入元素前,需要先获取父元素。
var img = document.createElement("img");
img.parentNode.insertBefore(placeholder, img);
获取img元素的父元素,并把placeholder元素插入到兄弟元素img之前。
7.4.2 在现有元素后插入一个元素
有了insertBefore()方法,我们希望有个insertAfter()方法,但是DOM没有提供。
7.4.2.1 编写insertAfter()方法
function insertAfter(newElement, targetElement)
思路:
- 将newElement插入到targetElement的之后
- 如果targetElement是最后一个子元素,则将newElement插入到父元素的子节点列表的最后。
- 如果targetElement不是最后一个子元素,则将newElement插入到targetElement的之前
首先,DOM的nextSibling属性可以获取某个元素节点的下一个兄弟元素节点。
function insertAfter(newElement, targetElement) {
var parent = targetElement.parentNode;
if (targetElement.nextSibling) {
parent.insertBefore(newElement, targetElement.nextSibling);
} else {
parent.appendChild(newElement);
}
}
解释:
- 获取目标元素的父元素
- 如果目标元素有下一个兄弟元素,则将新元素插入到下一个兄弟元素之前
- 如果目标元素没有下一个兄弟元素,则将新元素插入到父元素的子节点列表的最后。
7.4.2.2 使用insertAfter()方法
function preparePlaceholder() {
if (!document.getElementById) return false;
if (!document.createElement) return false;
if (!document.createTextNode) return false;
if (!document.getElementById("imageGallery")) return false;
var placeholder = document.createElement("img");
placeholder.src = "image/gallery.webp"; // placeholder.setAttribute("src", "image/gallery.webp");
placeholder.alt = "placeholder"; // placeholder.setAttribute("alt", "placeholder");
placeholder.id = "placeholder"; // placeholder.setAttribute("id", "placeholder");
var description = document.createElement("p");
description.id = "description"; // description.setAttribute("id", "description");
var descText = document.createTextNode("选择一个图片");
description.appendChild(descText);
var gallery = document.getElementById("imageGallery");
insertAfter(placeholder, gallery);
insertAfter(description, placeholder);
}
<body>
<h1>图片库</h1>
<ui id="imageGallery">
<li><a href="image/toWest/monkey.webp" title="悟空"><img src="image/toWest/monkey.webp" alt="悟空"></a></li>
</ui>
<!-- <img id="placeholder" src="image/gallery.webp" alt="placeholder"> 新增元素 -->
<!-- <p id="description">选择一个图片</p> 新增元素 -->
<script type="text/javascript" src="scripts/showPic.js"></script>
</body>
这里就把图片库的结构、样式和脚本彻底分开了。
那么,如何得到原来不属于初始页面的内容?
7.5 AJAX
AJAX(Asynchronous JavaScript and XML)是一种Web开发技术,它允许Web页面与服务器异步通信,实现Web页面的局部更新。
用户点击了某个链接,请求发送回服务器,服务器根据用户操作再返回新的页面。使用AJAX可以实现无刷新页面,即用户操作页面时,不用刷新页面,只更新局部内容。
7.5.1 XMLHttpRequest对象
XMLHttpRequest对象是AJAX的核心对象,它提供了异步请求的功能。XMLHttpRequest对象充当客户端和服务器之间的通信通道。
ajax.html文件如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>AJAX</title>
</head>
<body>
<div id="new"></div>
<script src="scripts/addLoadEvent.js"></script>
<script src="scripts/getHTTPObject.js"></script>
<script src="scripts/getNewContent.js"></script>
</body>
</html>
在scripts文件夹下,分别编写三个js文件:
- addLoadEvent.js:添加onload事件
- getHTTPObject.js:获取XMLHttpRequest对象
- getNewContent.js:获取新内容
为了模拟服务器响应,在ajax.html文件旁,创建example.txt文件,内容如下:
这是异步加载
模拟服务端脚本输出。
对getHTTPObject.js文件,如下:
function getHTTPObject() {
if (typeof XMLHttpRequest == "undefined") {
XMLHttpRequest = function() {
try {
return new ActiveXObject("Msxml2.XMLHTTP.6.0");}
catch (e) {}
try {
return new ActiveXObject("Microsoft.XMLHTTP");}
catch (e) {}
try {
return new ActiveXObject("Msxml2.XMLHTTP.3.0");}
}
return new XMLHttpRequest();
}
- 首先,判断浏览器是否支持XMLHttpRequest对象。
- 如果支持,则使用XMLHttpRequest对象。
- 如果不支持,则使用ActiveXObject对象。
- 如果都不支持,则返回false。
在获取XMLHttpRequest对象时
var request = getHTTPObject();
XMLHttpRequest对象提供了很多方法,比如open()、send()、setRequestHeader()等。
最有用的是open()方法,它用于设置请求的类型、URL和是否异步。
对于getNewContent.js文件,如下:
function getNewContent() {
var request = getHTTPObject();
if (request) {
request.open("GET", "example.txt", true);
request.onreadystatechange = function() {
if (request.readyState == 4 && request.status == 200) {
var para = document.createElement("p");
var text = document.createTextNode(request.responseText);
para.appendChild(text);
document.getElementById("new").appendChild(para);
}
};
request.send(null);
} else {
alert("Sorry, your browser does not support AJAX.");
}
}
- 首先,获取XMLHttpRequest对象。
- 如果对象存在,则使用open()方法设置请求的类型、URL和是否异步。
- 设置onreadystatechange事件处理函数,当请求状态改变时,调用该函数。
- 调用send()方法发送请求。
- 如果请求成功,则获取服务器响应,并创建新的元素节点和文本节点,并添加到id为new的元素节点的子节点列表中。
- 如果请求失败,则弹出提示信息。
服务器向XMLHttpRequest对象发回响应时,浏览器可能有许多属性可用,浏览器在不同节点更新readyState属性的值。
- 0:请求未初始化。
- 1:服务器连接已建立。
- 2:请求已接收。
- 3:表示正在交互
- 4:表示完成
访问服务器返回数据通过两个属性完成
- responseText:返回字符串形式的响应数据。
- responseXML:返回XML形式的响应数据。用于保存Content-Type: text/xml的响应数据。其实是DocumentFragment对象。
注意:
同源策略(Same-origin policy)是一种约定,它规定了AJAX请求只能从同一个源服务器发送。使用XMLHttpRequest对象时,只能访问与其所在HTML页面同源的资源,不能向其他域发送请求
有些浏览器限制ajax请求使用的协议
对于异步性,脚本在发送XMLHttpRequest对象时,任会继续执行,在脚本结束增加告警框,可能会先看到告警框提示内容,再看到新内容。
function getNewContent() {
var request = getHTTPObject();
if (request) {
request.open("GET", "example.txt", true);
request.onreadystatechange = function() {
if (request.readyState == 4 && request.status == 200) {
var para = document.createElement("p");
var text = document.createTextNode(request.responseText);
para.appendChild(text);
document.getElementById("new").appendChild(para);
}
};
request.send(null);
} else {
alert("Sorry, your browser does not support AJAX.");
}
alert("New content loaded.");
}
7.6 总结
本章介绍了DOM方法,创建和修改现有元素。
- createElement()方法可以创建新的元素节点。
- appendChild()方法可以把一个元素节点添加到另一个元素节点的子节点列表中。
- createTextNode()方法可以创建文本节点。
- insertBefore()方法可以把一个元素节点插入到另一个元素节点的子节点列表中,并指定插入位置。
- insertAfter()方法可以把一个元素节点插入到另一个元素节点的子节点列表中,并指定插入位置。
AJAX是一种Web开发技术,它允许Web页面与服务器异步通信,实现Web页面的局部更新。
XMLHttpRequest对象是AJAX的核心对象,它提供了异步请求的功能。XMLHttpRequest对象充当客户端和服务器之间的通信通道。