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可以实现无刷新页面,即用户操作页面时,不用刷新页面,只更新局部内容。
to be continued…