DOM 编程
动态脚本
动态脚本就是在页面初始加载时不存在,之后又通过 DOM 包含的脚本。有两种方式通过 <script>
动态为网页添加脚本:引入外部文件和直接插入源代码。
引入外部文件
<script>
也是元素节点,可以通过 DOM 编程添加这个节点,并修改其 src
属性。
let script = document.createElement("script");
script.src = "foo.js";
document.body.appendChild(script);
注意:在将 <script>
元素添加到页面之前是不会下载外部文件的。除了可以添加到 body 中,也可以添加到 head 中。
将上述代码抽象为函数为:
function loadScript(url){
let script = document.createElement("script");
script.src = url;
document.body.appendChild(script);
}
直接插入源代码
在 HTML 中,除了可以引入外部文件外,还可以在 <script></script>
中直接添加 JavaScript 代码。其中的 JavaScript 代码也就是文本节点,因此可以通过 DOM 编程为 <script>
元素添加文本子节点。除此之外 <script>
元素还有 text 属性,可以添加 JavaScript 代码。因为 IE 多 <script>
属性加以限制,不允许访问其子节点,因此只能使用第二种方法。
//不支持IE
let script = document.createElement("script");
script.appendChild(document.createTextNode("function sayHi(){alter('hi');}"));
document.body.appendChild(script);
//支持IE,Safari3(不包含)以下版本不支持
let script = document.createElement("script");
script.text = "function sayHi(){alter('hi');}";
document.body.appendChild(script);
为了支持更多浏览器,抽象出一个跨浏览器的函数为:
function loadScript(code){
var script = document.createElement("script");
script.type = "text/javascript";
try{
script.appendChild(document.createTextNode(code));
} catch (ex){
script.text = code;
}
document.body.appendChild(script);
}
注意:通过 innerHTML 属性创建的 <script>
元素永远不会执行。浏览器会尽责地创建 <script>
元素,以及其中的脚本文件,但解析器会给这个 <script>
元素打上用不执行的标签。
动态样式
CSS 样式在 HTML 页面中可以通过两个元素加载。<link>
元素用于包含 CSS 外部文件,而 <style>
元素用于添加嵌入样式。与动态脚本类似,动态样式也是在页面初始加载时并不存在,而是在加载之后才添加到页面中的。
外部文件加载
<link>
元素典例:
<link rel="stylesheet" type="text/css" href="styles.css">
根据这个元素节点,主要就是修改其属性值,然后添加到文档中。
let link = document.createElement("link");
link.rel="stylesheet";
link.type="text/css";
link.href="styles.css";
let head=document.getElementsByTagName("head")[0];
head.appendChild(link);
抽象为函数为:
function loadStyles(url){
let link = document.createElement("link");
link.rel="stylesheet";
link.type="text/css";
link.href=url;
let head=document.getElementsByTagName("head")[0];
head.appendChild(link);
}
通过外部文件加载样式是一个异步过程。因此,样式的加载和正执行的 JavaScript 代码并没有先后顺序。
嵌入样式加载
嵌入样式加载就是为 <style>
元素添加文本子节点。将 CSS 样式添加为 <style>
元素的文本子节点即可。
let style = document.createElement("style");
style.appendChild(document.createTextNode("div{background-color:red}"));
let head=document.getElementsByTagName("head")[0];
head.appendChild(style);
抽象为函数为:
function loadStyleString(css){
let style = document.createElement("style");
style.appendChild(document.createTextNode(css));
let head=document.getElementsByTagName("head")[0];
head.appendChild(style);
}
操作表格
表格是 HTML 中最复杂的结构之一。通过 DOM 编程创建 <table>
元素,通常要涉及大量标签,包括表行、表元、表题、等等。若是使用先前所学的方法创建表格,则代码将相当繁琐并且不易于理解。为了方便创建表格,HTMLDOM 给 <table>
、<tbody>
、<tr>
元素添加了一些属性和方法。
<table> 元素
<table>
元素添加了以下属性和方法:
属性名 | 说明 |
---|---|
caption | 指向 <caption> 元素的指针(如果存在) |
tBodies | 包含 <tbody> 元素的 HTMLCollection |
tFoot | 指向 <tfoot> 元素(如果存在) |
tHead | 指向 <thead> 元素(如果存在) |
rows | 包含表示所有行的 HTMLCollection |
方法 | 参数 | 返回值 | 说明 |
---|---|---|---|
createThead() | 无 | 返回所创建的 <thead> 元素的引用 |
创建 <thead> 元素放到表格中 |
createTFoot() | 无 | 返回所创建的 <tfoog> 元素的引用 |
创建 <tfoot> 元素放入表格中 |
createCaption() | 无 | 返回所创建的 <caption> 元素的引用 |
创建 <caption> 元素放入表格中 |
deleteThead() | 无 | 无 | 删除 <thead> 元素 |
deleteTFoot() | 无 | 无 | 删除 <tfoot> 元素 |
deleteCaption() | 无 | 无 | 删除 <caption> 元素 |
deleteRow(pos) | 行号 pos | 无 | 删除指定位置的行 |
insertRow(pos) | 行号 pos | 无 | 在行集合中给定位置插入一行 |
<tbody> 元素
<tbody>
元素添加了以下属性和方法:
属性名 | 说明 |
---|---|
rows | 包含 <tbody> 元素中所有行的 HTMLCollection |
方法 | 参数 | 返回值 | 说明 |
---|---|---|---|
deleteRow(pos) | 行号 pos | 无 | 删除给定位置的行 |
insertRow(pos) | 行号 pos | 返回该行的引用 | 在行集合中的给定位置插入一行 |
<tr> 元素
<tr>
元素添加了以下属性和方法:
属性名 | 说明 |
---|---|
cells | 包含 <tr> 元素所有表元的 HTMLCollection |
方法 | 参数 | 返回值 | 说明 |
---|---|---|---|
deleteCell(pos) | 列号 pos | 无 | 删除给定位置的表元 |
insertCell(pos) | 列号 pos | 返回该表元的引用 | 在表元集合给定位置插入一个表元 |
使用上诉方法,抽象出一种向 tbody 插入表元的函数为:
function insertTable(row,pos,value){
let r;
if(tbody.rows.length<=row){
r=tbody.insertRow(row);
}else{
r=tbody.rows[row];
}
let cell=r.insertCell(pos);
cell.appendChild(document.createTextNode(value));
}
使用 NodeList
理解 NodeList 对象和相关的 NamedNodeMap、 HTMLCollection,是理解 DOM 编程的关键。这三个集合类型都是 ” 实时的 “ ,意味着文档结构的变化会实时地在它们身上反映出来。(得到或者创建的 NodeList 对象不只是当时状态的反映,而是之后再使用此变量时都是实时反馈,会由于其他变量的改变所影响)
根据这种特性,当遍历 NodeList 对象时,若在循环中影响了页面的布局,则很可能导致死循环。如下:
let divs = document.getElementByTagName("div");
for(let i=0;i<divs.length;++i){
let div = document.createElement("div");
document.body.appendChild(div);
}
因此,若不是为了运用这种 ” 实时性 “ ,则最好再初始化一个变量保存当时查询时的长度,然后用循环变量与这个变量进行比较。当然,若不想再初始化一个变量,也可以反向迭代集合,使得循环变量初始化为长度 - 1,然后与 0 比较。