Javascript DOM 编程艺术(第二版)读书笔记——DOM基础

1.DOM是什么

D=document(文档)

O=object(对象)

M=Model(模型)

DOM又称节点树

一些术语:

parent(父)   child(子)   sibling(兄弟)   node(节点)  

element node(元素节点)   text node(文本节点)   

2.获取元素

1.getElementById(与typeof操作符)

//getElementById 与 typeof
//typeof操作符可以告诉我们它的操作数是一个字符串、数值、函数、布尔值还是对象
//getElementById会返回一个对象,且该调用只能有一个参数(id参数,且必须放在单引号或双引号里)
alert(typeof  document.getElementById("test")  );

注意,这里的Element是没有“s”结尾的!后面两个才有!

按照书上的测试我们只能得出“document.getElementById("test")”的类型是一个对象,但实际上可以更进一步探讨这是个什么对象(是document对象么?): 

alert( document.getElementById("test-id") );

输出的结果是object HTMLDivElement,这明显不是document对象,至于这个对象和document有何不同,和DOM有什么关系,以后再说(查文档)。

同时我也注意到,将这个方法返回的对象赋值给一个变量,该变量的类型将和右值类型相同:

var test_id = document.getElementById("test-id");
alert( test_id );
//输出的结果也是object HTMLDivElement

 另外,我发现文档中称HTMLDivElement为“接口”而不是对象!为什么呢?后面要时刻注意对象、接口是什么东西,参考文章有:123

2.getElementByTagName

//getElementsByTagName
//只接受标签名作为参数
//返回一个对象数组(数组),每个对象分别对应document对象中的一个tag元素;所以我们可以使用数组对象的属性,比如length alert( document.getElementsByTagName("li").length );

我得先看看这个返回的是什么:

alert( document.getElementsByTagName("p") );
//输出object HTMLCollection

3.getElementsByClassName

//getElementsByClassName
//以空格来同时指定多个类名——由于返回的只有一个特殊的对象,理所当然的,这里返回的是同时具有testClass、testClassTwo类的标签。
//只接受类名为参数
alert( document.getElementsByClassName("testClass testClassTwo").length );

同样的,我得先知道这个方法返回的是什么东西——这里返回的不是真正意义上的“数组”:

alert( document.getElementsByClassName("test-class") );
//输出的结果是HTMLCollection,这个对象不是Array(数组)而是一个特殊的对象数组,他也有“.length”这个方法,即返回集合中子元素的数目

标记一下,为什么不是返回数组而是返回一个新定义的对象数组?肯定有原因。

这里要注意,这个方法在IE8以下是无法使用的,我们必须借助“getElementsByTagName”来定义这个函数才能在老版本浏览器中使用,具体的方法见这篇文章,有些函数还看不懂,不知道这个实现的原理,以后要回头看懂它。P42

4.返回的类型是什么,是一个很重要的问题。

  var test_id = document.getElementById("test-id");
  var test_items = test_id.getElementsByTagName("*");
  alert(test_items.length);
  //输出该id下有多少个标签

这段代码将正确地输出id为“test-id”下有多少个标签,之所以能这样,是因为“getElementById”返回的是一个document的实例,所以第二行可以对“test_id”使用“getElementsByTagName”这个方法;同样地,因为“getElementsByTagName”返回的是一个特殊的对象,这个对象有“length”这个方法,所以我们才能在alert里面正确地输出。

如果我们把第一行和第二行反过来用,比如“某些标签里面的id=test-id的标签有几个?”,就会出错了(这是个伪命题,直接找id就好了,不需要找“某些标签里面的id”)——首先就是“getElementsByTagName”返回的对象是没有“getElem....”这种方法的,其它的就更不用说了。

同样地还能这么用:

var test_id = document.getElementById("test-id");
var test_items = test_id.getElementsByClassName("test-class");
alert(test_items.length);
//输出该id下有多少个“test-class”类的标签

要意识到,文档中的每一个元素都是一个对象,DOM对这些不同的对象都定义了不同的一整套的方法和属性;

getElementById返回一个对象,该对象对应文档里一个特定的元素节点。

getElementsByClassName、getElementsByTagName返回一个对象数组,它们分别对应文档里的一组特定的元素节点——因为你一次只能改一个元素,所以你如果想借这个操作修改这个数组里某个具体元素的值,你就必须加下标!比如getElementsByClassName("p")[1](这里只是强调下标,实际上不一定是这么写的,真正的写法见下面的例子)之类。

5.childNodes属性

前面分别是获取某个id的元素、获取某个标签、获取某个类的元素,现在这个是获取任何一个元素的所有子元素:

3.获取和设置属性

1.getAttribute(获取)

//getAttribute
//为了方便,我只写body里的内容。
    <div id="test-id">
        <p title="oneTitle">hello word1</p>
            <h1 class="test-class">
                <p>1</p> 
                <p>2</p> 
            </h1>
        <p title="twoTitle">hello word3</p>
        <p>hello word4</p>
    </div>
    <script>
        var test_items = document.getElementsByTagName("p");
        for(var i = 0 ; i < test_items.length ; i++){
            alert( test_items[i].getAttribute("title") );
        }
    </script> 
//输出的结果依次为:oneTitle、null、null、twoTitle、null

学到这,我注意到:DOM分支下之所以有那么多的对象或者说是接口,其实都是为了针对不同抽象层级的操作而诞生的。比如,文档树里的各个节点的层级,我们操作的目标往往是各个节点的属性。因为不需要获取这个节点本身,所以这里的getAttribute不是document对象的一个方法——它只专注于实现属性相关的操作,所以被独立出来,所以我们这里可以看到,要想调用getAttribute,不能通过document对象调用,而是和其“联用”,即先获取到你想更改的标签的数组(第一行代码),然后再调用节点抽象层级的对象的方法getAttribute(第二行script代码——顺带一说,这里的节点抽象层级的对象其实就是指前面提到的HTMLCollection)。

上面一段的可以简单概括为:getAttribute方法是属于HTMLCollection对象的,而HTMLCollection对象是由document对象中的getElementsByTagName等方法返回的结果。

其次,要注意到上面这段代码的输出中有“null”,在Javascript里,null的意思是“没有值”。(个别浏览器会在输出null对话框的时候输出空白对话框)

2.setAttribute(设置)

//setAttribute
//为了方便,只给出body内的代码
<div id="test-id">
        <p title="oneTitle">hello word1</p>
            <h1 class="test-class">
                <p>1</p> 
                <p>2</p> 
            </h1>
        <p title="twoTitle">hello word3</p>
        <p>hello word4</p>
    </div>
    <script>
        var test_id = document.getElementById("test-id");
        alert( test_id.getAttribute("title") );
        test_id.setAttribute("title","test-title");
        //测试是否修改了
        alert( test_id.getAttribute("title") );  
</script>

 setAttribute实际操作是这样的:

1.当对象属性值为null时(可能有点奇怪,但就是这样:属性没设置就相当于属性不存在,而属性不存在就是属性=null),先创建这个属性,然后设置它的值。

2.当属性的值存在时,覆盖掉它。

通过setAttribute对文档做出修改后,浏览器的开发者模式看到的源代码中属性的值并没有改变——其做出的修改不会反映在文档本身的源代码里,是“表里不一”的,这种思想源自DOM的工作模式:先加载文档的静态内容,再动态刷新,动态刷新不影响文档的静态内容。这也是DOM的真正威力:对页面内容进行刷新却不需要在浏览器里刷新页面。——————仔细想想,这是一连串的影响造成的。浏览器解析步骤的开始就是下载HTML文档,生成文档树,然后再渲染CSS、JS,如果JS改了HTML文档,那么浏览器就需要从头开始,也就是整个页面都要重新渲染一次,而这个代价出现的原因居然是修改某个属性值?所以干脆变成“动态刷新”。

原文地址:https://www.cnblogs.com/wuduojia/p/8379454.html