本文详细介绍JavaScript中动态DOM操作的核心技术,包括通过DOM接口动态创建和插入外部脚本与内联代码,解决旧版IE兼容性问题。同时讲解动态样式的加载机制及异步特性,并深入解析利用HTML DOM属性与方法构建表格的完整流程,涵盖节点集合的动态特性及避免死循环的最佳实践。
动态脚本的创建与执行
动态脚本
在网页开发中,利用<script>元素是插入JavaScript代码的常见方式。这通常分为两种路径:一是通过src属性引用外部JS文件,二是直接在元素内部编写JS代码。所谓动态脚本,指的是该脚本在初始页面加载阶段并不存在,而是在后续运行过程中,通过操作DOM节点来动态插入到页面中的脚本。与处理HTML元素类似,实现动态脚本也有两种主要手段:引入外部文件或直接写入JavaScript代码片段。
动态加载的外部JavaScript代码可以在插入页面后立刻执行,参考以下示例:
var script = document.createElement("script");
script.type = "text/javascript";
script.src = "demo.js";
document.body.appendChild(script);

从运行结果可以看出,上述代码在<body>元素内部成功生成了一个<script>节点:
<script type="text/javascript" src="demo.js"></script>
需要特别注意的是,在最后一行代码将<script>元素追加到页面之前,浏览器并不会下载外部脚本文件。
另一种指定JavaScript代码的方式是采用行内嵌入模式,例如:
var script = document.createElement("script");
script.type = "text/javascript";
script.appendChild(document.createTextNode("function fn1(){alert('hello wolrd!')} fn1();"));
document.body.appendChild(script);

上述代码执行后,会在<body>元素内部插入一段JavaScript代码:
<script type="text/javascript">
function fn1(){alert('hello wolrd!')} fn1();
</script>
执行上述代码后,浏览器会弹出提示框,显示“hello world!”文本。
在Firefox、Safari、Chrome和Opera等现代浏览器中,上述DOM操作代码可以正常运行。然而,在旧版本的IE浏览器中,这些代码会引发错误。旧版IE将<script>元素视为特殊节点,禁止通过DOM访问其子节点。不过,可以通过<script>元素的text属性来指定JavaScript代码,例如:
var script = document.createElement("script");
script.type = "text/javascript";
script.text("function fn1(){alert('hello wolrd!')} fn1();");
document.body.appendChild(script);
按照上述方式修改代码后,该脚本在IE、Firefox、Safari 3.0、Chrome和Opera浏览器中均可正常运行。对于Safari 3.0之前的浏览器,虽然无法正确识别text属性,但可以通过文本节点来指定代码。因此,若需兼容旧版本浏览器,代码应编写如下:
var script = document.createElement("script");
script.type = "text/javascript";
var code = "function fn1(){alert('hello wolrd!')} fn1();";
try{
script.appendChild(document.createTextNode(code));
}catch(e){
script.text = code;
}
上述代码首先尝试使用标准的DOM文本节点方法,因为除旧版IE外,其他主流浏览器均支持此方式。若该行代码抛出异常,则表明当前为旧版IE浏览器,此时必须改用text属性。
我们可以将动态添加脚本的逻辑封装到一个函数中,通过传入不同参数来动态加载不同的脚本资源。
function loadScript(code){
var script = document.createElement("script");
script.type = "text/javascript";
try{
script.appendChild(document.createTextNode(code));
}catch(e){
script.text = code;
}
document.body.appendChild(script);
}
调用该函数的示例如下:
loadScript("function fn1(){alert('hello wolrd!')}");
通过这种方式加载的代码将在全局作用域中执行,且在脚本执行完毕后立即可用。实际上,这种执行方式与在全局作用域中将相同字符串传递给eval()函数的效果一致。
动态样式的加载与兼容
动态样式
通常,HTML页面中包含CSS样式的元素主要有两个:一个是<link>元素,用于引入外部样式文件;另一个是<style>元素,用于定义嵌入式样式。与动态脚本类似,动态样式是指在页面初始加载时并不存在,而是在页面加载完成后通过脚本动态添加到页面中的样式规则。示例如下:
var link = document.createElement("link");
link.rel = "stylesheet"
link.type = "text/css";
link.href = "styles.css";
var head = document.getElementsByTagName("head")[0];

上述代码在所有主流浏览器中均可正常运行。需要注意的是,<link>元素必须添加到<head>元素中,而非<body>元素中,以确保在所有浏览器中的行为保持一致。
另外需注意,加载外部样式文件的过程是异步的,这意味着加载样式与执行JavaScript代码之间没有固定的先后顺序。
另一种定义样式的方式是使用<style>元素来包含嵌入式CSS样式。示例代码如下:
var style = document.createElement("style");
style.type = "text/css";
style.appendChild(document.createTextNode("body{background:#f00;}"));
var head = document.getElementsByTagName("head")[0];
head.appendChild(link);
执行上述代码后,可以在<head>元素中动态添加以下节点:
<style type="text/css">
background:#f00;
</style>
上述代码在Firefox、Safari、Chrome和Opera浏览器中运行正常,但在旧版IE浏览器中会报错。旧版IE将<style>元素视为特殊节点,不允许访问其子节点。解决旧版IE问题的方法是访问元素的styleSheet属性,该属性包含一个cssText属性,可用于接收CSS代码。示例如下:
var style = document.createElement("style");
style.type = "text/css";
try{
style.appendChild(document.createTextNode("body{background:#f00;}"));
}catch(e){
style.styleSheet.cssText = "body{background:#f00;}";
}
同样地,我们可以将动态添加样式的逻辑封装到一个函数中,通过不同参数动态加载不同的样式表。
function loadStyle(code){
var style = document.createElement("style");
style.type = "text/css";
try{
style.appendChild(document.createTextNode(code));
}catch(e){
style.styleSheet.cssText = code;
}
var head = document.getElementsByTagName("head")[0];
head.appendChild(style);
}
JavaScript表格的动态构建
JavaScript对表格的操作
在JavaScript中,为了便于构建表格,HTML DOM为<table>、<tbody>和<tr>元素提供了一系列属性和方法。
表格的<table>元素的属性和方法包括:
caption:保存<caption>元素引用的指针。 tBodies:包含<tbody>元素的HTMLCollection。 tFoot:保存<tfoot>元素引用的指针。 tHead:保存<thead>元素引用的指针。 rows:包含表格中所有行的HTMLCollection。 createTHead():创建<thead>元素,将其插入表格并返回引用。 createTFoot():创建<tfoot>元素,将其插入表格并返回引用。 createCaption():创建<caption>元素,将其插入表格并返回引用。 deleteTHead():删除<thead>元素。 deleteTFoot():删除<tfoot>元素。 deleteCaption():删除<caption>元素。 deleteRow(pos):删除指定位置的表格行。 insertRow(pos):向rows集合中指定位置插入一行。
表格的<tbody>元素的属性和方法包括:
rows:保存<tbody>元素中行的HTMLCollection。 deleteRow(pos):删除指定位置的表格行。 insertRow(pos):向rows集合中指定位置插入一行。
表格的<tr>元素的属性和方法包括:
cells:保存<tr>元素中单元格的HTMLCollection。 deleteCell(pos):删除指定位置的单元格。 insertCell(pos):向cells集合中指定位置插入一个单元格,并返回新插入单元格的引用。
利用上述属性和方法,可以轻松地使用JavaScript创建表格,示例代码如下:
//创建表格
vatabldocument.createElement("table");
table.borde1;
table.widt"100%";
//创建tbody
vatboddocument.createElement("tbody");
table.appendChild(tbody);
//创建第一个表格行
tbody.insertRow(0);
tbody.rows[0].insertCell(0);
tbody.rows[0].cells[0].appendChild(document.createTextNode("单元1-1"));
tbody.rows[0].insertCell(1);
tbody.rows[0].cells[1].appendChild(document.createTextNode("单元2-1"));
//创建第二个表格行
tbody.insertRow(1);
tbody.rows[1].insertCell(0);
tbody.rows[1].cells[0].appendChild(document.createTextNode("单元1-2"));
tbody.rows[1].insertCell(1);
tbody.rows[1].cells[1].appendChild(document.createTextNode("单元2-2"));
//将表格添加到文档中
document.body.appendChild(table)
使用上述代码可以在页面中动态创建一个表格。在创建表格行时,通过<tbody>元素调用insertCell()方法,并传入参数0(表示插入行的位置)。执行该行代码后,会自动创建一个表格行,并将其插入到<tbody>元素的第0个位置,此时可通过tbody.rows[0]引用新插入的行。
创建单元格的方式与创建表格行类似。通过<tr>元素调用insertCell()方法,并传入要放置单元格的位置。随后,可通过tbody.rows[0].cells[0]引用新插入的单元格。
NodeList的动态特性与注意事项
关于NodeList
理解NodeList、NamedNodeMap和HTMLCollection是从整体上掌握DOM的关键。这三个集合都是动态的,即每当文档结构发生变化时,它们始终保存最新的信息。从本质上讲,所有的NodeList对象都是在访问DOM文档时实时运行的查询。例如,以下代码会导致死循环:
var divs = document.getElementsByTagName("div");
for(var i = 0; i < divs.length; i++){
var div = document.createElement("div");
document.body.appendChild(div);
}
上述代码首先获取所有<div>元素的HTMLCollection,并保存在一个变量中。由于该集合是动态的,因此只要有新的<div>被添加到页面中,新的<div>元素就会被自动添加到该集合中。这导致div.length的值不断变化,每次循环都会在页面中添加一个<div>元素,length值也随之递增。这使得i < divs.length条件永远无法成立,从而导致死循环。
若需迭代一个NodeList,建议将length属性初始化为第二个变量,并将迭代器与该变量进行比较,例如:
var divs = document.getElementsByTagName("div");
for(var i = 0,len = divs.length; i < len; i++){
var div = document.createElement("div");
document.body.appendChild(div);
}
由于len中保存了divs.length在循环开始时的快照,因此可以避免死循环的发生。
更多示例:
function sAlert(str){
var msgw,msgh,bordercolor;
msgw=400;//提示窗口的宽度
msgh=100;//提示窗口的高度
titleheight=25 //提示窗口标题高度
bordercolor="#c51100";//提示窗口的边框颜色
titlecolor="#c51100";//提示窗口的标题颜色
var sWidth,sHeight;
sWidth=screen.width;
sHeight=screen.height;
var bgObj=document.createElement("div");
bgObj.setAttribute('id','bgDiv');
bgObj.style.position="absolute";
bgObj.style.top="0";
bgObj.style.background="#cccccc";
bgObj.style.filter="progid:DXImageTransform.Microsoft.Alpha(style=3,opacity=25,finishOpacity=75";
bgObj.style.opacity="0.6";
bgObj.style.left="0";
bgObj.style.width=sWidth + "px";
bgObj.style.height=sHeight + "px";
bgObj.style.zIndex = "10000";
document.body.appendChild(bgObj);
var msgObj=document.createElement("div")
msgObj.setAttribute("id","msgDiv");
msgObj.setAttribute("align","center");
msgObj.style.background="white";
msgObj.style.border="1px solid " + bordercolor;
msgObj.style.position = "absolute";
msgObj.style.left = "50%";
msgObj.style.top = "50%";
msgObj.style.font="12px/1.6em Verdana, Geneva, Arial, Helvetica, sans-serif";
msgObj.style.marginLeft = "-225px" ;
msgObj.style.marginTop = -75+document.documentElement.scrollTop+"px";
msgObj.style.width = msgw + "px";
msgObj.style.height =msgh + "px";
msgObj.style.textAlign = "center";
msgObj.style.lineHeight ="25px";
msgObj.style.zIndex = "10001";
msgObj.style.position = "absolute";
var box=document.getElementById(str);
var title=document.createElement("h4");
title.setAttribute("id","msgTitle");
title.setAttribute("align","right");
title.style.margin="0";
title.style.padding="3px";
title.style.background=bordercolor;
title.style.filter="progid:DXImageTransform.Microsoft.Alpha(startX=20, startY=20, finishX=100, finishY=100,style=1,opacity=75,finishOpacity=100);";
title.style.opacity="0.75";
title.style.border="1px solid " + bordercolor;
title.style.height="18px";
title.style.font="12px Verdana, Geneva, Arial, Helvetica, sans-serif";
title.style.color="white";
title.style.cursor="pointer";
title.onmousedown=function(){startDrag(this,'msgDiv')};
title.onmouseup=function(){stopDrag(this,'msgDiv')};
title.onmousemove=function(){drag('msgDiv')};
var closer=document.createElement("div");
closer.onclick=function(){
CloseReturn();
document.body.appendChild(box);
box.style.display = "none";
document.body.removeChild(bgObj);
document.getElementById("msgDiv").removeChild(title);
document.body.removeChild(msgObj);
};
closer.innerHTML="确定";
document.body.appendChild(msgObj);
document.getElementById("msgDiv").appendChild(title);
document.getElementById("msgTitle").appendChild(closer);
box.style.display="inline";
document.getElementById("msgDiv").appendChild(box);
ShowReturn();
}
html dom树:
