JavaScript与DOM

JS单纯作为一门编程语言的话,其竞争力并没有多大。但是为什么JS是使用人数最多的语言呢?就是因为JS可以动态控制页面上的内容和行为。
这个feature便是JS中的DOM(document object model)。本文来探讨基础DOM:增删改查。

示例页面

为了展示功能和写法,需要一个基础页面,内容如下:

留意元素的额外属性,许多操作都是针对属性的
另外最后的button是测试的入口,点击button会调用外部脚本定义的doTest().
关于事件机制,会在另一文章中说明

查找元素是最基本的,其他的操作都得有了目标对象才能进行
DOM提供了许多种查找方式:

(1)获取特定对象
使用getElementById方法即可。比如
alert(document.getElementById(“newstyle”).innerHTML);
会输出First paragraph。

这里真正有趣的是document这个符号,没有在函数里出现过,这是什么呢?
按照传统语言的话讲,这是单件模式下整个html页面的指针。
因为是单件所以在任何地方都可以直接使用
因为是指针所以反映了实时状态的页面,并且一旦操作就会立刻反映到页面上
getElementById就是这个类的内置方法

(2)筛选符合条件的对象
getElementsByName(“order”)返回名字带有XXX的节点数组
name和id都可以指代元素,但是目前推荐的做法是使用id
id是唯一的,name可以重复。实际上name属于老式的元素标识方法,在form里还沿用。其他场合都应该用id

getElementsByTagName(“img”)返回tag是XXX的节点数组
getElementsByClassName(“caption”)返回属性里class=XXX的节点数组

还有两个主要跟CSS配合使用的
querySelector(“.caption”)返回符合CSS筛选的第一个元素
querySelectorAll(“input[name]”)返回符合CSS筛选的所有元素
至于筛选的规则,在CSS一文讲解。

(3)遍历
还有一种方式可以让开发者自己提供筛选器
var fnFilter = function(node) {return (node.type == "radio")? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP;};
var choices = document.createNodeIterator(document, NodeFilter.SHOW_ELEMENT, fnFilter, false);
var iter = choices.nextNode();
while (iter != null) {
    alert(iter.value);
    iter = choices.nextNode();
}
createNodeIterator从节点XX开始,一级筛选类型,二级筛选自己提供函数对象,然后返回结果。
注意返回的结果并不是数组,需要用上述写法调用nextNode来遍历

获取目标节点后,如何来修改呢?
(1)html标签之间的内容
这个非常简单,使用innerHTML属性即可。
比如可以这么写:
document.getElementById(“newstyle”).innerHTML = “new text”;
如果新插入的值也是html格式,那么浏览器会重新解析这部分内容,然后替换原有内容,实际相当于增和删了

(2)元素属性
这个也简单,使用.XXX即可。
document.getElementById(“icon”).src = “item_remove.png”;
动态替换了一张图片
也可以使用getAttribute/setAttribute处理,但是直接用属性名来的更快一点

对于自定义元素,先找dataset然后是属性名,比如
alert(document.getElementsByClassName(“caption”)[0].dataset.my_key);
输出123456

只要找到父节点和子节点,就可以删除
var fm1 = document.forms[0];
fm1.removeChild(fm1.childNodes[0]);
从document可以直接获取使用到的form,这是个简写形式
一个节点的子节点通过childNodes获取,0就是首个子节点

先使用createElement新建一个节点,然后初始化,最后加入文档的某个位置
var nNew = document.createElement(“p”);
nNew.id = “newpara”;
nNew.innerText = “notice:”;
var fm1 = document.forms[0];
fm1.appendChild(nNew);

这里使用了innerText不是innerHTML。如果是text则按照纯文本处理,如果是html则浏览器会创建解析器然后处理
这里还引发了另一个讨论。
每次使用appendChild都会立刻更新文档,如果变化比较大在效率会低
这种情况推荐先构造html语句,字符串形式的,然后使用innerHTML赋值,批量更新