JavaScript 艺术之美(五)DOM之美

一月已经过半了,得加紧脚步,2018年充满挑战、紧张和刺激,虽然迷茫但会走得精彩。

零、文档对象模型DOM

当网页被加载时,浏览器会创建页面的文档对象模型(Document Object Model)。

一、文档:DOM中的“D”

当创建了一个网页并把它加载到web浏览器中时,DOM便根据这个网页创建出一个文档对象。

二、对象:DOM中的“O”

与某个特定对象相关联的变量被称为这个对象的属性,只能通过某个特定对象去调用的函数被称为这个对象的方法。
1. 用户自定义对象:由程序员自行创建的对象。
2. 内建对象:内建在JavaScript语言里的对象。
3. 宿主对象(host Object):由浏览器提供的对象。

  • window对象对应着浏览器窗口本身,这个对象的属性和方法通常统称为BOM(浏览器对象模型)
  • document对象主要功能是处理网页内容。

三、模型:DOM中的“M”

文档对象的树状模型,在这个树状模型中,网页中的元素与内容表现为一个个相互连接的节点。

四、节点(node)

DOM中的结点类型包括元素节点、文本节点及属性节点。

1.元素结点

诸如<body>,<p>,<li>等一系列标签,元素结点组成了文档模型的语义逻辑结构,
- 标签的名字就是元素的名字,
- 元素可以包含其他的的元素,
- <html>是整个节点树的根元素

2.文本结点

包含在元素节点中的内容部分,如<p>标签中的内容。

3.属性节点

元素节点的属性,用来对元素做出更具体的描述,所有的属性都被元素包含,如<a>标签的 href 属性与 title 属性等。

五、获取元素

DOM可通过元素id、标签名、类名来获取元素节点。

1.getElementById

该方法将返回一个与那个有着给定id属性值的元素节点对应的对象,是document对象特有的函数。
document.getElementById(id)
getElementById方法只有一个参数,要获得元素的id属性的值,这个id值必须放在单引号或双引号里:
document.getElementById("purchases");
这个调用将返回一个对象,这个对象对应着document对象里的一个独一无二的元素,该元素的html id属性值为purchases
typeof操作符可以告诉我们它的操作数是一个字符串、数值、函数、布尔值还是对象:
alert(typeof document.getElementById("purchases"));

2.getElementsByTagName

文档中的每一个元素都是一个对象,利用DOM提供的方法可以得到任何一个对象,getElemnetByTagName 方法返回一个对象数组,每个对象分别对应着文档里有着给定标签的一个元素,它的参数是标签的名字:
document.getElementsByTagName("li");
以上调用将返回一个对象数组,可以利用length属性查看这个数组的元素个数:
alert(document.getElementsByTagName("li").length);
这个数组里的每个元素都是一个对象,可通过循环语句和typeof操作符遍历该数组验证:

for (var i=0; i<document.getElementsByTagName("li").length; i++){
    alert(typeof document.getElementsByTagName("li")[i]);
}

可以把document.getElementsByTagName("li")赋值给一个变量:

var items = document.getElementsByTagName("li");
for (var i=0; i<items.length; i++){
    alert(typeof items[i]);
}

通配符("*"):getElementsByTagName允许把一个通配符作为它的参数,为了与乘法操作符有所区别,通配符必须放在引号内,下面代码将返回某份文档里共有多少个元素:
alert(document.getElementsByTagName("*").length);
下面代码返回id属性值是purchases的元素里的子元素个数:

var shopping = document.getElementById("purchases");
var items = shopping.getElementsByTagName("*");
alert(items.length);

3.getElementsByClassName

该方法让我们能通过class属性中的类名来访问元素,下面代码将返回一个数组,包含类名为“sale”的所有元素:
document.getElementsByClassName("sale");
该方法还可以查找带有多个类名的元素,在字符串参数中用空格分隔类名,下面代码将匹配包含类名为important 和sale的所有元素:
alert(document.getElementsByClassName("important sale").length);
下面函数可使getElementsByClassName适应新老浏览器:

// getElementsByClassName函数接收两个参数,node表示DOM树中的搜索起点,classname为要搜索的类名
function getElementsByClassName(node, classname) {
    if (node.getElementsByClassName) {
        //使用现有方法
        return node.getElementsByClassName(classname);
    } else {
        var results = new Array();
        var elems = node.getElementsByTagName("*");
        for (var i=0; i<elems.length; i++){
            if(elems[i].className.indexOf(classname) != -1){
                results[results.length] = elems[i];
            }
        }
        return results;
    }
}

如下面代码将获得id属性为purchases的元素下包含class属性“sale”的所有元素:

var shopping = document.getElementById("purchases");
var sales = shopping.getElementsByClassName(shopping, "sale");
alert(items.length);

六、获取和设置属性

得到需要的元素后,getAttribute方法可以获取它的各个属性,setAttribute方法则可以更改属性节点的值。

1.getAttribute

该方法只有一个参数——要查询的属性名字:
object.getAttribute(attribute)
该方法不属于document对象,只能通过元素节点对象调用,以下代码获取每个p元素的title属性:

var paras = document.getElementsByTagName("p");
for (var i=0; i<paras.length; i++) {
    alert(paras[i].getAttribute("title"));
}

运行结果:
有几个p元素就弹出几个包含title属性值的对话框,p元素里没有title属性则显示null或空白,可以使用if语句来提高可读性:

var paras = document.getElementsByTagName("p");
for (var i=0; i<paras.length; i++) {
    var title_text = paras[i].getAttribute("title");
    if (title_text !=null) {
    alert(title_text);
    }
}

if(something)与if(something !=ull)完全等价:

var paras = document.getElementsByTagName("p");
for (var i=0; i<paras.length; i++) {
    var title_text = paras[i].getAttribute("title");
    if (title_text) alert(title_text);
}

2.setAttribute

该方法允许对属性节点的值做出修改,也只能用于元素节点:
object.setAttribute(attribute,value)
下面代码把id是purchase的元素的title属性值设置为 a list of goods:

var shopping = document.getElementById("purchases");
shopping.setAttribute("title", "a list of goods");

可以利用getAttribute来证明是否发生变化:

var shopping = document.getElementById("purchases");
alert(shopping.getAttribute("title"));
shopping.setAttribute("title", "a list of goods");
alert(shopping.getAttribute("title"));

setAttribute做出的修改不会反映在文档本身的源代码里,这种表里不一的现象源自DOM的工作模式:
先加载文档的静态内容,再动态刷新,动态刷新不影响文档的静态内容,也就是说DOM对页面内容进行刷新却不需要在浏览器里刷新页面。