JavaScript DOM 基础知识点

《JavaScript DOM 编程艺术 》 《JavaScript 高级程序设计》

平稳退化和渐进增强

在 JavaScript DOM 编程艺术一书中,个人认为,最核心的思想是作者提到的平稳退化和渐进增强。

所谓的平稳退化,就是让JS代码适应所有的用户,这是一个基础,不管用户处于什么环境,都要为用户提供最基本的可访问性。

而渐进增强则是为高级用户提供更好的体验效果,利用JS去包装原始的HTML数据,但前提是JS只是一个行为层,必须与结构层分离。

也就是说在平稳退化的基础上渐进增强,而渐进增强的结果一般都是符合平稳退化的。

DOM

JavaScript 主要由3部分组成,也就是 ECMAScript,DOM,BOM。

作为 JavaScript 的重要组成部分,DOM 的全称是 Document Object Model,即是文档对象模型。用类似于家谱的树形结构来表示 DOM 再适合不过了,而组成这个 DOM Tree 的就是节点。


节点——Node 类型

DOM1 定义了一个 Node 接口,该接口由 DOM 中所有的节点类型实现,而在 JavaScript 中,该接口作为 Node 类型实现,所有的节点类型都继承自 Node 类型。
Node 类型主要由四个属性,包括 nodeType、nodeName、nodeValue 和 childNodes。

nodeType 属性

所有节点都有一个 nodeType 属性,表示该节点的类型。

DOM 中定义了12中 Node 类型,其中主要有3种节点:元素节点、文本节点、文档节点。

元素节点的 nodeType 属性值为 Node.ELEMENT_NODE 或 1。

文本节点的 nodeType 属性值为 Node.TEXT_NODE 或 3。

文档节点的 nodeType 属性值为 Node.DOCUMENT_NODE 或 9。

注:为了跨浏览器,一般使用数值表示 nodeType 属性。

nodeName 属性和 nodeValue 属性

对于元素节点,nodeName 属性保存的是元素的标签名,nodeValue 属性始终为 null。

childNodes 属性

该属性中保存一个 NodeList 对象。
访问:someNode.childNodes[i]; 等价于 someNode.childNode.item(i);
注:空格、换行、制表,这些空白符会产生空白的文本节点!!!除了 IE9-
关于 NodeList 对象
NodeList 对象是一种类数组对象,并非 Array 的实例,并且根据 DOM 结构的变化自动变化。
NodeList 转化为数组的方法:(arguments 对象也是采用该方法)
function convert2Array(nodes){
    var array = null;
    try{
        //针对非IE浏览器
        array = Array.prototype.slice.call(nodes, 0);
    }
    //IE8-浏览器会捕获错误
    catch(e){
        array = new Array();
        for(var i = 0, len = nodes.length ; i < len ; i ++){
            array.push(nodes[i]);
        }
    }
    return array;
}

parentNode 属性、previousSibling 属性、nextSibling 属性、firstChild 属性、lastChild 属性 和 hasChildNodes() 方法

appendChild() 方法、insertBefore() 方法、replaceChild() 方法 和 removeChild() 方法

/*
原有的 html 结构:
<div id="a">
    <div id="b"></div>
</div>
*/

var a = document.getElementById("a");
//若已经创造了新的节点 c
var newNode = a.appendChild(c);
alert(newNode == c); //true

/*
此时 html 结构为
<div id="a">
    <div id="b"></div>
    <div id="c"></div>
</div>
*/
//若新插入的节点已存在,appendChild 则会改变原来的位置为当前位置

var newNode = a.insertBefore(d,b);
alert(newNode == d); //true

/*
此时 html 结构为
<div id="a">
    <div id="d"></div>
    <div id="b"></div>
    <div id="c"></div>
</div>
*/

var newNode = a.replace(e,d);
alert(newNode == e); //tue

/*
此时 html 结构为
<div id="a">
    <div id="e"></div>
    <div id="b"></div>
    <div id="c"></div>
</div>
*/

var removeNode = a.removeChild(e);
alert(removeNode == e);//true

/*
此时 html 结构为
<div id="a">
    <div id="b"></div>
    <div id="c"></div>
</div>
*/

自定义 insertAfter() 方法

DOM 中没有提供 insertAfter() 方法,但我们可以自己定义:
function insertAfter(newNode, targetNode){
    var parent = targetNode.parent;
    if(parent.lastChild == targetNode){
        parent.appendChild(newNode);
    }
    else{
        parent.insertBefore(newNode, targetNode.previousSibling);
    }
}

文档节点——Document 类型

JavaScript 通过 Document 类型表示文档,其子类 HTMLDocument 在浏览器中的一个实例对象是 document。

nodeType 值为 9
nodeName 值为 "#document"
nodeValue 值为 null
parentNode 值为 null

document 对象

documentElement 属性:取得 <html> 元素。document.documentElement;
body 属性:取得 <body> 元素。document.body;
title 属性:可读写文档的标题。document.title;
URL 属性:只读页面完整的URL。document.URL; 相当于 window.location; 或 location.href;
domain 属性:可读写域名,但设值时有限制,若 URL 中含子域名,则只能设为该 URL 的高层域名。document.domain;
referrer 属性:只读页面的来源,即是链接到当前页面的那个页面的 URL,所以可能值为 null。document.referrer;
查找元素:
getElementById() 方法:
按照元素的 id 值返回一个元素节点的对象

注:按照平稳退化渐进增强的原则,使用前做出判断,如

if(!document.getElementById){
    return false;
}
var link = document.getElementById("a");
注意:在 IE8- 中不区分 id 的大小写,其他会区分。在 IE7- 中,会匹配表单中的 name 属性,所以表单的 name 和 id 不要设相同的值。

getElementsByTagName
按照元素的标签名返回一个 HTMLCollection 对象,类似于 NodeList
var links = document.getElementsByTagName("a");
for(var i = 0 ; i < links.length ; i ++){
    alert(links[i].title);
}

getElementsByClassName

HTML5 DOM 中新增的一个方法,按照元素的 class 值返回一个 HTMLCollection 对象,可查找带有多个类名的元素,且类名顺序不会有影响

var links = document.getElementsByClassName("link item");
alert(links.length);


其他 HTMLCollection 对象:
document.anchors :返回所有带 name 属性的 <a>
document.links :返回所有带 href 属性的 <a>
document.forms :返回所有 <form> 元素节点
document.images :返回所有 <img> 元素节点


元素节点——Element 类型

元素节点在 HTML 中就是各种标签,比如 <p>

nodeType 值为:1
nodeName 值为:元素的标签名
nodeValue 值为:null
注:nodeName 值通常为大写,所以比较的时候最好使用 toLowerCase() 方法进行处理。

常用属性:id、title、className

属性操作

getAttribute
返回查询的属性的值
if(!document.getElementById){
    return false;
}
var link = document.getElementById("item");
alert(link.getAttribute("src"));
link.getAttribute("src") 相当于 link.src,也就是直接采用 DOM 对象直接访问。
setAttribute
设置属性的值
var links = document.getElementsByTagName("a");
for(var i = 0 ; i < links.length ; i ++){
    links[i].setAttribute("title","title"+i);
}

links[i].setAttibute("title","title"+i) 相当于 links[i].title = "title" + i;

removeAttribute

移除属性的值

var link = document.getElementById("item");
link.removeAttribute("title");
注:IE6- 不支持

创建元素——document.ceateElement()

返回创建的新元素的对象。
注:对象创建后并不会在 DOM 树中,必须将其添加进去,如 appendChild 等。
IE7- 动态创建元素存在的问题:
1)动态创建的 <iframe> 无法设置 name 属性。
2)动态创建的 <input> 无法使用 reset() 方法。
3)动态创建的 <button> type 值为 reset 的,无法重设表单。
4)动态创建的单选按钮,即使 name 值一样,它们之间没有关系。
上述问题解决方法如下:
if(client.browser.ie && client.browser.ie <= 7){
    var iframe = document.createElement("<iframe name=\"myframe\"></iframe>");
    var input = document.createElement("<input type=\"checkbox\" />");
    var button = document.createElement("<button type=\"reset\"></button>");
    var radio1 = document.createElement("<input type=\"radio\" name=\"choice\" value=\"1\" />");
    var radio2 = document.createElement("<input type=\"radio\" name=\"choice\" value=\"2\" />");
}
注:其他浏览器不支持此写法,所以要检测浏览器。

文本节点——Text 类型

纯文本内容。
nodeType 值为:3
nodeName 值为:“#text”
nodeValue 值为:文本内容
没有子结点!

length 属性:保存节点中字节的数目

创建文本节点 document.createTextNode()

返回新创建的文本节点
若一个元素中创建了多个文本节点,则这些文本节点的显示会连在一起,但是实际却不是一个节点。可以使用 normalize() 方法将这些文本节点连接为一个节点。
var p = document.getElementById("text");
var txt1 = document.createTextNode("hello ");
var txt2 = document.createTextNode("word!");
p.appendChild(txt1);
p.appendChild(txt2);
alert(p.childNodes.length); //2
p.normalize();
alert(p.childNodes.length); //1

文档片段——DocumentFragment 类型

文档片段可以包含和控制节点,但不会占用资源,也就是文档片段中的节点并不会存在 DOM 树中。利用这点,我们在动态创建节点的时候可以利用文档片段来优化性能。
文档片段的创建:document.createDocumentFragment()
var fragment = document.createDocumentFragment();
var ul = document.getElementById("list");
var li = null;
for(var i = 0 ; i < 5 ; i ++){
    li = document.createElement("li");
    li.appendChild(document.createTextNode("item"+i));
    fragment.appendChild(li);
}
ul.appendChild(fragment);
避免了 for 循环中一直为 ul 添加子节点而造成页面的反复渲染。


发布了22 篇原创文章 · 获赞 4 · 访问量 3万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章