博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

DOM

Posted on 2013-07-20 21:09  Amy-lover  阅读(409)  评论(0编辑  收藏  举报

1、IE中DOM对象与原生js中DOM对象的不同

  IE中的所有DOM对象都是以COM对象的形式实现,因此IE中的DOM对象与原生js对象的行为差异性较大。

2、DOM的定义

  DOM将文档描述为一个由多层节点构成的结构,节点分为不同的类型,每种类的节点分别表示文档中不同的信息或标记。每个节点都有各自的特点、数据和方法。节点与节点之间存在某种关系,构成层次。页面结构则表示为一个特定节点为根节点的树形结构。

3、js共有12种节点类型,都继承自Node类型。因此所有节点类型都有共同的基本属性和方法。除了IE,都可以访问到Node类型。

4、所有节点的均有的属性,关系和操作

  4.1 基本属性

    4.1.1 nodeType:节点的类型

    4.1.2 nodeNamenodeValue:节点名称和节点值,其值取决于属性nodeType的值

    4.2 节点之间的关系

       4.2.1 childNodes属性:节点的所有直接子节点

    4.2.1.1 childNodes.length: 判断直接子节点的数量

    4.2.1.2 childNodes[0]:访问节点的某个直接子节点

    4.2.1.3 childNodes.item(0): 访问节点的某个直接子节点

       4.2.2 parentNode属性:节点的直接父节点

       4.2.3 firstChild属性:节点的第一个子节点

       4.2.4 lastChilid属性:节点的最后一个子节点

       4.2.5 previousSibling属性:紧挨节点的前一个兄弟节点

       4.2.6 nextSibling属性:紧挨节点的后一个兄弟节点

       4.2.7 ownerDocument属性:整个文档的文档节点,所有节点的根节点

  4.2.8 hasChildNodes()方法:判断节点是否包含子节点

    4.3 操作

       4.3.1 appendChild方法:在childNodes列表末尾添加节点

       4.3.2 insertBefore方法:在某个参照节点前添加节点,如果参照节点为null,那么insertBefore方法和appendChild方法执行相同的操作

       4.3.3 replaceChild方法:用新的节点替换掉中的某个节点,被替换的节点仍然在文档中,只是文档中已经没有它的位置了

       4.3.4 removeChild方法:移除某个节点

       4.3.5 cloneNode方法:复制节点,

       4.3.6 normalize方法:处理文档树中的文本节点

5 常见的8种节点

    5.1 Element类型

  5.2 Attr类型

    5.3 Text类型

    5.4 CDATASection类型

    5.5 Comment类型

    5.6 Document类型---9

    5.7 DocumentType类型---10

    5.8 DocumentFragment类型---11

   

一、基本属性
  属性1:nodeType,表示节点的类型,
  由于IE没有没有公开Node类型的构造函数,IE不识别12种类型的常量值,因此为了浏览器的兼容性,,尽量将nodeType属性与数字值进行比较

function f(){
    var p=document.getElementById("nt");
    if(p.nodeType==Node.ELEMENT_NODE||p.nodeType==1)
      alert("id为nt的节点的类型是元素");
}

  属性2:nodeNamenodeValue属性  

  对于属于元素类型的节点,nodeName的值是大写标签名,nodeValue的值是null

function f(){
    var p=document.getElementById("nt");
    if(p.nodeType==Node.ELEMENT_NODE||p.nodeType==1)
      {
        alert("id为nt的节点的类型是元素,该节点的nodeName属性为"+p.nodeName+" 其nodeValue的值为"+p.nodeValue);
//id为nt的节点的类型是元素,该节点的nodeName属性为P 其nodeValue的值为null
        }
}

 

二、节点之间的关系

  childNodes属性,保存一个NodeList对象,可以通过指定该对象的位置来访问节点的所有直接子节点,DOM结构的变化会自动反映到NodeList对象。可以通过中括号,或者item()方法访问,它还有一个属性length来判断直接子节点的数量  

<script type="text/javascript">
function f(){
    var p=document.getElementById("nt");
    if(p.nodeType==Node.ELEMENT_NODE||p.nodeType==1)
      {
        alert(p.childNodes[0].nodeType+"  and  "+p.childNodes.item(0).nodeValue);//3 and www
        }
}
</script>

  parentNode属性:指定文档中其直接父节点

  previousSibling属性和nextSibling属性:分别指向节点的前一个兄弟节点和后一个兄弟节点

  firstChild和lastChild属性:分别指向节点的第一个直接子节点和最后一个子节点

  ownerDocument属性:指向整个文档的文档节点,文档中所有的节点不必回溯,可以直接访问文档的最顶层(object HTMLDocument)

  hasChildNodes()方法:判断节点是否有子节点

三、操作节点

  3.1 appendChild方法:someNode.appendChild(newNode),返回值是newNode,所有直接子元素的末尾,添加一个直接子元素,成为childNodes列表中所有元素的父元素parentNode的lastChild。

  3.2 inserBefore方法:someNode.insertBefore(newNode,操作成功后,该参数成为newNode的同胞节点-previousSibling),两个参数:要插入的节点和参照的节点,返回值newNode,其中newNode是someNode的子元素。

  someNode.insertBefore(newNode,null),如果第二个参数是null,则newNode插入后成为someNode的lastChild,与appendChild方法一致

  3.3 replaceChild方法:someNode.replaceChild(newNode,要被替换掉的someNode的子节点),返回值是被替换掉的节点

  3.4 removeChild方法:someNode.removeChild(someNode的某一个要被移除的子节点),返回值被移除的someNode的子节点

上述四种方法的操作均针对someNode的子节点

  3.5 cloneNode方法:someNode.cloneNode(true/false),true是复制someNode及其整个子树,false只复制someNode,IE在复制节点时会复制节点的js属性,例如事件处理程序等,但其他浏览器不复制js属性

  3.6 normalize方法:处理文档树中的文本节点,由于解析器的实现或者DOM操作的原因,可能出现文本节点不包含文本,或者接连出现两个文本的情况,当某个节点调用该方法时,就会在改节点的后代节点中查找上述两种情况,空白文本删除,两个连在一起的,合并。

 -------------------------------------------------------常见的几种节点类型--1---------Element类型-----------------------------------------------

Element类型:用于表现HTML或者XML元素,提供对元素表签名、子节点、特性的访问

一、基本的一些属性值

  1.nodeType:1或者Node.ELEMNET_NODE

  2.nodeName:元素的表签名,HTML中是大写,XML中和源码中的实际标签一致,因此HTML中最好先利用方法toLowerCase(),将其转换大小写

  3.nodeValue:null

  4.parendNode:Document或者Element

  5.有属性tagName:其值等于nodeName

二、HTMLElement类型的特性值

    Element类型的子类型HTMLElement类型,所有的HTML元素均由HTMLElement类型或者HTMLElement的子类型表示,HTMLElement类型继承Element,并添加了一些新的属性,这些属性与元素的特性相对应

    2.1 id:元素在文档中的唯一标示符

    2.2 title:元素的附加说明信息,一般通过工具提示条显示

    2.3 lang:元素内容的语言代码(较为常用的语言代码:en/zh/fr=英语/中文/法语)

    2.4 dir:语言的方向(只有这两个取值:ltr/rtl=left-to-right/right-to-left)

    2.5 className:为元素指定的css类  

<!DOCTYPE html>
<head>
<meta charset="UTF-8">
</head>
<html>
<body>
<p>This is a paragraph.</p>
<p lang="fr" dir="rtl" id="my" title="message">Ceci est un paragrapheddddwwwwwwwwd.</p>
<!--在js中lang,dir,id等是DOM对象的属性,但是在html文档中,是元素的特性,元素的特性与DOM的属性是对应的-->
</body>
</html>

 

var div=document.getElementById("my");
alert(div.id);//my
alert(div.lang);//fr
alert(div.title);//message
alert(div.dir);//rtl
alert(div.className);//""

 

三、操作上述特性的方法

    3.1 getAttribute方法、setAttribute方法和removeAttribute方法。注意1,,不是getAttribute("className");注意2:;注意3:参数不区分大小写

    3.2 :直接利用属性名操作div.id="my";//设置alert(div.id)//获取

    3.3 attributes属性的getNamedItem,removeNamedItem,setNamedItem以及item方法

var id=element.attributes.getNamedItem("id").nodeValue;
var id=element.attributes["id"].nodeValue;
//尤其是在遍历元素的所有特性时,如果只需要返回指定的特性,利用每个特性节点的specified属性即可
var result=[];
for(var i=0;i<element.attributes.length;i++){
    if(element.attributes[i].specified){
        result.push(attributes[i].nodeName+"=\""+attributes[i].nodeValue+"\"");
    }
}
alert(result.join(" "));

 

    3.4 :3.1与3.2方案的区别:

    1 getAttribute("class")与div.className,

    2 可以通过getAttribute("my_attribute")获取自定义的特性值与div.my_attribute==null(ie9以下例外),

    3 div.style:利用属性名访问返回一个对象(object CSS2Properties)与div.getAttribute("style"):利用getAttribute方法返回css文本(background:#f36;)

    4 div.onclick,返回一个函数(function onclick(event){alert('amy');})与div.getAttribute("onclick")返回代码字符串(alert('amy');)

    通过js以编程的方式操作DOM时,一般用div.属性名,除非是自定义的特性值,一般不用getAttribute方法

          一个小问题:dir与align有什么区别?

四、Element类型的子节点(浏览器之间的差异性)

  4.1 Element类型的子节点一般通过childNodes属性,但是Element类型的子节点可以是Element类型的节点,也可以是Text类型的节点,还有可能是注释或者处理指令等,所以在获取childNodes时应该利用nodeType判定一下,例如下面的例子

<ul id="my">1
    <li>2</li>3
    <li>4</li>5
</ul>

 

var d=document.getElementById("my");
alert(d.childNodes.length);//ie返回2,火狐等其他浏览器返回5,因为火狐等会将li之间的空白认为是Text类型的节点

 

var d=document.getElementById("my");
for(var i=0;i<d.childNodes.length;i++){
    if(d.childNodes[i].nodeType==1){
        //如果是元素类型的节点执行什么操作
    }
}

 4.2 利用getElementsByTagName方法获取所有该标签名的后代

<ul id="my">
    <li>1-1
      <ul>
          <li>2-1</li>
          <li>2-2</li>
      </ul>
    </li>
    <li>1-2</li>
</ul>
var d=document.getElementById("my");
var dm=d.getElementsByTagName("li");
alert(dm.length);//4

  五、创建元素document.createElement("标签名"),html不区分大小写,xml区分大小写

   5.1 利用该方法创建时,已经为该元素指定了ownerDocument==HTMLDocument

  5.2 ie7以及更早的版本中,利用document.createElement()方法传递的参数为新元素指定属性,避免下列问题:

    1 不能设置动态创建的iframe元素的name特性var new_elemnet=document.createElement("<iframe name=\"my_frame\"></iframe>")

      2 不能通过表单的reset()方法重设动态创建的input元素var new_elemnet=document.createElement("<input type=\"checkbox\">")

      3 动态创建的type为reset的button元素,重设不了表单var new_elemnet=document.createElement("<button type=\"reset\"></button>")

    4 动态创建的name相同的一组单选按钮之间没有关系,var new_elemnet=document.createElement("<input type=\"radio\" name=\"choice\" value=\"1\"></input>")

      var new_elemnet=document.createElement("<input type=\"radio\" name=\"choice\" value=\"2\"></input>")

    但是在指定属性前需要进行浏览器的检测,因为只有ie7及更早版本支持(client.browser.ie&&client.browser.ie<=7)

六、attribute属性

 只有Element类型的节点有attribute属性,元素的每一个属性都是一个Attr节

------------------------------常见的几种节点类型--2---------Attr类型----------------------------------------------------

一、基本的一些属性值

  1.nodeType:2或者Node.ATTRIBUTE_NODE

  2.nodeName:特性的名称

  3.nodeValue:特性的值

  4.parendNode:null

  5.name:其值等于nodeName

  6.value:其值等于nodeValue

  7.specified:布尔值,用于检验特性是指定的还是默认的

  8.Attr节点在html中没有子节点,在xml中子节点为Text类型或者EntityReference

  9.虽然Attr也是节点,但是却不被认为是DOM文档书的一部分

二、Element类型节点的attributes属性中的每一个属性都是一个Attr节点,attributes属性是NamedNodeMap

  2.1 getNamedItem(name):返回nodeName为参数name的节点

  区别getAttributeNode()返回的是该特性的节点与上面的getNamedItem()方法一样

  getAttribute()获取到的是该名称相对应的特性值

  2.2 setNamedItem(Attr_node):返回nodeName为参数name的节点  或者setAttributeNode(Attr_node)

  2.3 removeNamedItem(name):返回nodeName为参数name的节点

  2.4 item(pos):返回nodeName为参数name的节点

  2.5 createAttribute():创建特性节点

var my_node=document.getElementById("my");
var new_dir=document.createAttribute("dir");//常见一个特性节点
new_dir.value="rtl";//为新的特性节点设置值
my_node.attributes.setNamedItem(new_dir);//将特性值添加到某个元素节点上
my_node.setAttributeNode(new_dir);//将特性值添加到某个元素节点上 alert(my_node.attributes.getNamedItem("dir").value);//获取新增特性的值
alert(my_node.attributes.item(0).value);
alert(my_node.attributes["id"].value);
alert(my_node.attributes[1].value);

  2.5 也可以利用getAttribute、setAttribute、removeAttribute方法来替代上面的方法

  2.6 注意attributes属性包含了元素节点所有的属性,包括指定的默认的,大约有100多个,所以我们可以利用attributes的specified属性来返回指定的属性,另外可以利用length属性来遍历

    2.6.1 element.attributes.specified

    2.6.2 element.attributes.length

-------------------------------------------------------常见的几种节点类型--3---------Text类型-----------------------------------------------------

一、基本的一些属性值

  1.nodeType:3或者Node.TEXT_NODE

  2.nodeName:#text

  3.nodeValue:所包含的文本

  4.parendNode:Element类型的节点

  5.data:其值等于nodeValue

  6.length:节点中字符的数目

二、Text节点的操作方法

  2.1 appendData(text)

  2.2 deleteData(offset,count)

  2.3 insertData(offset, text)

  2.4 replaceData(offset,count,text)

  2.5 splitText(offset):从offset位置将文本节点分为两个文本节点,

  2.6 substringData(offset,count):提取从offset开始到offset+count为止的字符串,与splitData的区别是:本方法仅仅算操作字符串,对原有文本节点没有影响

三、Text类型节点的创建和添加

  3.1 文本节点的创建、添加与规范化(normalize())

var new_text_node_01=document.createTextNode("hello world");
var new_text_node_02=document.createTextNode("!!!!!!");
var element_node=document.getElementById("my");
element_node.appendChild(new_text_node_01);
element_node.appendChild(new_text_node_02);
element_node.normalize();
alert(element_node.childNodes[0].data);

  3.2 文本节点的分割(splitText())

   文本的分割与文本的规范化是两个相反的过程,原本的文本节点包含从开始到指定位置的内容,新的文本节点包含剩下的内容,返回值是剩下的内容

 --------------------------------------常见的几种节点类型--4--------CDATASection类型-(只针对XML文档)-------------------------------------

一、基本的一些属性值

  1.nodeType:4或者Node.CDATA_SECTION_NODE

  2.nodeName:#cdata_section

  3.nodeValue:CDATA区域中的内容

  4.parendNode:Document或者Element类型的节点

   5. createCDataSection():只在XML文档中使用该方法创建CDATA区域

<div id="my"><![CDATA[this is a CADA section]]></div>四大主流的浏览器均不能解析这句话

-------------------------------------------------常见的几种节点类型--8--------Comment类型-(只针对XML文档)-------------------------------------

一、基本的一些属性值

  1.nodeType:8或者Node.COMMENT_NODE

  2.nodeName:#comment

  3.nodeValue:或者data表示注释的内容

  4.parendNode:Document或者Element类型的节点

 二、一些杂乱的点

  2.1 comment类型和text类型继承自一个基类,因此comment类型的节点除了没有splitText方法外,拥有Text类型节点的所有方法,包括data属性

  2.2 document.createComment()可以创建注释节点,但一般都不使用,因为注释对程序影响不大

  2.3 IE8及其以下版本将注释类型的节点当做了ELement类型的节点,可以使用document.getElementByTagName("!")来获取,注意利用该方法获取的还有文档类型的定义

alert(document.getElementsByTagName("!").item(0).data);


 

 ---------------------------常见的几种节点类型--9---------Document类型----------------------------------------------------

JS通过Document类型表示文档,document对象是HTMLDocument的一个实例,表示整个HTML页面,该对象也是window对象的一个属性,可以将其作为全局对象来访问

一、基本的一些属性值

  1.nodeType:9或者Node.DOCUMENT_NODE

  2.nodeName:#document

  3.nodeValue:null

  4.parendNode:null

  5.documentElement:始终指向HTML页面中的<html>元素

  6.childNodes:可以访问文档元素

  7 body:直接指向<body>元素,所有的浏览器都支持document.documentElement和document.body属性

  8 doctype:取得对<!DOCTYPE>标签的访问,注意浏览器之间的差异,但是IE将文档类型的声明,认为是Comment节点,所以document.doctype属性始终返回null,

    如果定义了文档类型的声明,火狐会利用document.firstChid或者document.childNodes[0]来访问

    safari、chrome和opera中,该节点并不出现在document.childNodes列表中

var html=document.documentElement;//获取对<html>的引用
alert(html.nodeName);//HTML
alert(document.doctype==document.childNodes[0]);//true

   9 URL:包含页面完整的URL,只可以获取,不可以设置

  10 domain:只包含页面的域名,可以设置,出于安全考虑,只能给domain属性设置URL的子域的值,不能设置为URL不包含的域

    注意1:如果一开始document.domain是松散的,就不能把它设置的紧绷的,例如,如果一开始是renren.com,那么就不能设置为blog.renren.com

    注意2:不同子域之间无法通过JS通信,因此我们将每个页面的document.domain设置为一样的值,它们之间就可以通信了

  11 referrer:保存着链接到当前页面的那个页面的URL,如果没有来源页面,referrer属性的值可能是空字符串,只可以获取,不可以设置

二、一些方法

  1 getElementById:参数ID与元素的id特性严格匹配,如果页面中有多个id特性为参数ID的元素,该方法只会返回第一个匹配元素

    注意:ie7以及更低版本中,该方法会返回name属性与参数ID匹配的表单元素,例如<input name="参数ID"><textarea name="参数ID"><button><select>,因此尽量避免表单元素的name特性与其他元素的id相同

  2 getElementByTagName:参数是元素的标签名,返回一个HTMLCollection对象(一个“动态”集合),可以使用[]或者item()方法来访问HTMLCollection对象中的项

var imgs=document.getElementsByTagName("img");
console.log(imgs.length);//输出获取到的页面中的img元素的个数
console.log(imgs[0].src);//利用[]获取页面中第一个img元素的src属性
console.log(imgs.item(0).src);//利用item()方法获取第一个img元素的src属性

 

     注意一:我们可以使用namedItem()方法从HTMLCollection对象中获取name属性为参数的项

<img src="my.gif" name="myImg" /><!--页面中有一个name属性为myImg的img元素-->
//首先我们使用document的getElementsByTagName方法获取到页面中的img元素
var imgs=document.getElementsByTagName("img");
//然后使用namedItem方法从imgs对象中获取到name属性与参数一致的项
var myImge=imgs.namedItem("myImg");
alert(myImge.src);

 

   对HTMLCollection对象的操作,我们可以向[]中传入数值或者字符串形式的索引值来访问其中的项,在后台,对数值索引就会调用item(n),而对字符串索引就会调用namedItem方法

  注意二:要取得文档中的所有元素,可以向getElementsByTagName方法传入"*",获取整个页面中的所有元素,按照顺序,第一项是html元素,第二项是head元素。。。依次类推,由于ie将注释也作为element,所以,会返回所有的注释节点

  3 getElementsByName方法:返回name属性与参数相符的所有元素,最常见的应用就是利用该方法获取单选按钮(一组单选按钮拥有相同的name特性)

<input type="radio" value="red" name="color" id="redColor"><label for="redColor">红色</label>
<input type="radio" value="green" name="color" id="greenColor"><label for="redColor">绿色</label>
<input type="radio" value="blue" name="color" id="blueColor"><label for="redColor">蓝色</label>
var colorRadio=document.getElementsByName("color");

  注意:这里不能再使用namedItem来取得HTMLCollection对象中的项了,因为这里获取到的元素集合,拥有相同的name特性,因此,该方法只会返回第一项

  4 write(),writeln()在页面呈现的过程中直接向页面输出内容,如果在页面加载完毕后调用上述方法,那么就会重新加载页面

  5 open()和close()方法:分别是打开和关闭网页输出流,如果在页面加载时使用了write或者writeln方法,就不需要使用open和close方法

三、一些特性

  1 特殊的集合:

    1 document.anchors:返回文档中所有带name特性的<a>元素

    2 document.forms:返回文档中所有的<form>元素

    3 document.images:返回文档中所有的<img>元素

    4 document.links:返回文档中所有的带href特性的<a>元素

  2 DOM一致性检测

    由于DOM分为多个级别,也包含多个部分,因此检测浏览器实现了DOM的哪些部分十分必要

    1 document.implementation.hasFeature():参数要检测的DOM功能的名称及其版本号

document.implementation.hasFeature("XML","1.0");//检测浏览器是否支持XML1.0版本的功能

  4  缺陷:有时该方法返回true并不意味着实现与规范一致,因此,我们建议使用DOM一致性检测的同时,使用能力检测

---------------------------常见的几种节点类型--10---------DocumentType类型----------------------------------------------------

DocumentType类型仅火狐,safari和opera支持,所以在此简单介绍,DocumentType包含着与文档的doctype有关的所有信息,由于IE不支持,所以document.doctype的值始终为null

一、基本的一些属性值

  1.nodeType:10或者Node.DOCUMENT_TYPE_NODE

  2.nodeName:doctype的名称

  3.nodeValue:null

  4.parendNode:document

  5.childNodes:不支持子节点

  6 document.doctype:取得对<!DOCTYPE>标签的访问,注意浏览器之间的差异,但是IE将文档类型的声明,认为是Comment(注释)节点,所以document.doctype属性始终返回null,

二、属性----只有name是有用的,表示文档类型的名称

console.log(document.doctype.name);
//HTML

 --------------------------常见的几种节点类型--11---------DocumentFragment类型----------------------------------------------------

在所有节点类型中,只有DocumentFrament在文档中没有对应的标记,DOM规定文档片段是一种“轻量级”的文档,可以包含和控制节点,但不会像完整的文档那样占用额外的资源

一、基本的一些属性值

  1.nodeType:11或者Node.DOCUMENT_FRAGMENT_NODE

  2.nodeName:#document-fragment

  3.nodeValue:null

  4.parendNode:null

二、方法

  1 createDocumentFrament()

  虽然不能将文档片段之间添加到文档中,但是可以将它作为一个“仓库”来保存将来可能会添加到文档中的节点,首先需要创建文档片段

var fragment=document.createDocumentFragment()

 

  2 文档片段继承了Node的所有方法,(回顾一下),appendChild,insertBefore,replaceChild,removeChild等

  3 将文档中的节点添加到文档片段中,那么就会从文档中移除该节点

var fragment=document.createDocumentFragment()
var my=document.getElementById("myList");
fragemnt.appendChild(my);//id为myList的节点就会从文档中移除,不再属于文档

  4 将文档片段中的内容添加到文档中,实际上文档片段本身永远不会成为文档的一部分,我们只是将其内容添加到文档中(应用场景:避免逐个添加节点,导致浏览器的反复渲染新信息,利用文档片段来保存要添加的节点内容,然后将其一次性的添加到文档中)

var fragment=document.createDocumentFragment();
var ul=document.getElementById("myList");
var li=null;
for(var i=0;i<3;i++){
  li=document.createElement("li");
  li.appendChild(document.createTextNode("item"+(i+1)));    
  fragment.appendChild(li);  //将生成的节点逐个添加到文档片段中
}
ul.appendChild(fragment);//一次性将文档片段添加到文档中,文档片段中的所有节点被转移到ul后,文档片段将其内容删除

 

--------------------------------------------------------------------DOM扩展-------------------------------------------------------------------------------

根据W3C对DOM的要求,浏览器可以自行为其添加属性和方法,以增强其功能,这就是DOM的扩展

  1 呈现模式:ie6开始区分标准模式和混杂模式,为此ie为document对象添加了compatMode属性,该属性的作用是表示浏览器处于什么模式

if(document.compatMode=="CSS1Compat"){
  alert("标准模式");  
}else{
  alert("混杂模式");  
}

 

另外,ie8又为document对象引入了documentMode属性,因为ie8有三种不同的呈现模式,分别是5:混杂模式(ie5);7:ie7仿真模式;8:ie8的标准模式

if(document.documentMode>7){
  alert("IE8标准模式");  
}else if(document.documentMode>5){
  alert("IE7仿真模式");  
}else{
 alert("IE5混杂模式");  
}

2 滚动

DOM规范没有就如何滚动页面区域这个问题作出规定,因此各种浏览器以不同的方式控制滚动,这些方法作为HTMLElement类型的扩展存在,因此可以在所有元素上使用,所有浏览器都支持的方法有scrollIntoView()

  2.1 scrollIntoView():滚动浏览器窗口或者容器元素,以便在视口中看到当前元素。如果参数是true,那么窗口会尽可能滚动到自身顶部与元素顶部平齐

<p>2</p>
<!--n多个p-->
<p>2</p>
<img src="IMG_20130302_140426.jpg.thumb.jpg" />
<p>2</p>
<!--n多个p-->
<p>2</p>
<div onclick="f()" style="width:100px; height:100px; border:1px solid #C03;"></div>
function f(){
    document.images[0].scrollIntoView(false);
}

 

  下面的几种方法只有safari和chrome浏览器实现

  2.2 scrollIntoViewIfNeeded():只在当前元素在视口不可见的情况下,才滚动浏览器窗口或者容器元素,最终让当前元素可见,如果参数为true,那么会尽量让元素在视口垂直居中显示

  2.3 scrollByLines(n):将元素内容滚动指定的行数高度,参数可以是正数也可以是负数

  2.4 scrollByPages(n):将元素的内容滚动指定的页面的高度,将页面主体滚动n页,可以是负数

3 children属性

ie浏览器对文本节点中空白符的解释与其他的浏览器不同,它不认为空格或者换行符为一个文本节点,因此children属性只包含元素类型的子节点

<ul id="d"><li>1</li><li>2</li>
</ul>
var i=document.getElementById("d");
alert(i.childNodes.length);//ie8及其以下返回2,ie9返回为3,火狐等返回3
alert(i.children.length);//ie返回都为2,火狐不支持该方法

 

4 ie的contains方法与火狐的compareDocumentPosition方法判断一个节点是否是另一个节点的后代

我们经常需要确定一个节点是否是另外一个节点的后代,为此ie引入了contains方法,可以让我们无须遍历DOM树就可以获知一个节点是否是另一个节点的后代

document.documentElement.contains(document.body);//true

 

火狐的compareDocumentPosition方法,会返回一个表示两个节点之间关系的位掩码,1:无关;2:居前;4:居后;8:包含;16:被包含,因此掩码16与ie的contains方法一致

alert(document.documentElement.compareDocumentPosition(document.body));//20,原因是居后的4+包含的16

 

5 操作内容

  5.1 插入文本ie的innerText属性和火狐的textContent属性

innerText属性可以操作元素中包含的所有文本内容,由浅入深,将子文档树中的所有文本拼接起来

<div id="d">
    <p>p<a href="#">a1</a>
    </p>
    <a href="#">a2</a>
</div>
var d=document.getElementById("d");
alert(d.innerText);
//pa1
//a2

使用该属性可以获取文本内容,也可以设置文本内容,使用该属性会移除先前存在的所有子节点,改变DOM子树,

var d=document.getElementById("d");
d.innerText="'hi,good morning jim&jhon!'";
alert(d.innerText);//'hi,good morning jim&jhon!'  

  注意:我们还可以使用该属性过滤掉html标签,方法就是

var d=document.getElementById("d");
d.innerText=d.innerText;

 为了确保跨浏览器兼容,我们通过

function getText(){
    return (typeof d.textContent=="string")?d.textContent:d.innerText;
}

   5.2 innerHTML属性

取信息时,innerHTML会返回当前元素的所有子节点的HTML表现,包括元素,注释以及文本节点,但是ie和opera会将标签大写返回,火狐等会以文档中指定的形式返回,包括空格和缩进

信息时,会创建新的DOM子树,替换当前元素的所有子节点

注意一:利用innerHTML插入的<script>元素只有ie支持其执行,但是也是有条件的,其一是指定defer特性,第二在<script>元素前面添加微软所谓的作用域元素,即前置一个作用域内元素,作用域内元素包括文本节点,或者一个隐藏的没有结束标签的元素

div.innerHTML="_<script defer></scr"+"ipt>";//下划线即为一个文本节点,但是考虑到页面显示,要移除
div.innerHTML="<div>&nbsp;</div><script defer></scr"+"ipt>";//div中包含一个空格,这个空格就是一个文本节点,考虑到页面显示,也需要移除
div.innerHTML="<input type=\"hidden\"><script defer></scr"+"ipt>";//由于input是隐藏的,不影响布局,因此多使用这种方法,

 

 注意二:在通过innerHTML属性写入<style>元素时也会遇到与插入<script>元素一样的问题,如果想在所有浏览器中都成功插入<style>元素,应该如下

//针对ie,火狐,opera
div.innerHTML="_<style type=\"text/css\">body{color:red;}</style>";
div.removeChild(div.firstChild);//移除文本节点,下划线

//针对safari和chrome
document.getElementByTagName("head")[0].appendChild(div.firstChild);
//将<style>插入到head元素中

总结:利用innerHTML向文档中插入HTML内容,都应该先对该HTML进行无害化处理,将所有的脚本节点和事件处理程序删除,这里ie8提供了window.toStaticHTML方法,由于目前只有ie8支持该方法进行无害化处理,所以我们应该先手工检查一下文本内容

  5.3 内存和性能问题

使用innerHTML和innerText替换子节点可能会导致浏览器的内存问题,尤其是ie,如果被删除的子树中的某个元素设置了事件处理程序,或者具有值为js对象的属性,那么该元素在删除后,元素与事件处理程序之间的绑定仍然存在于内存中,如果这种情况频繁出现,页面的内存数量就会增加,因此正像5.2中总结的一样,在删除或者插入以前都应该手动的移除所有的事件处理程序和js对象属性

使用innerHTML操作节点的优点:使用innerHTML比使用多次DOM操作先创建节点再添加节点效率要高,因为使用innerHTML,会创建一个HTML解析器,这个解析器是在浏览器级别的代码(通常是C++)基础上运行的,因此执行效率比执行js要快的多,不可避免,使用innerHTML解析器也会带来性能损失,因此需要合理控制innerHTML的使用次数,最好是先构建字符串,然后再一次性地将字符串赋值给innerHTML

  5.4 动态脚本:动态加载的脚本会在全局作用域中执行,与在全局作用域将代码字符串传递给eval是一样的

function loadScript(code){
    var script=document.createElement("script");
    script.type="text/javascript";
    try{
      script.appendChild(document.createTextNode(code));  
    }catch(ex){
      script.text=code;//ie将<script>视为一种特殊的元素,不允许子DOM访问其子节点,因此只能使用text属性来指向script代码
    }

 

   5.5 动态样式:两种方式,第一link,OK,第二style,ie将<style>视为一种特殊的元素,不允许子DOM访问其子节点,因此只能使用styleSheetcssText属性来指向style文本

 

//link
function loadLink(url){
   
    var link=document.createElement("link");
    link.rel="stylesheet";
    link.type="text/css";
    link.href=url;
    var head=document.getElemntsByTagName("head")[0];
    //只有添加到head才能保证在所有浏览器中的行为一致
    head.appendChild(link);
}

//style
function loadStyle(cssString){
    var style=document.createElement("style");
    style.type="text/css";
     try{
        style.appendChild(document.createTextNode(cssString));
    }catch(ex){
        style.styleSheet.cssText=cssString;//只针对ie
} var head=document..getElemntsByTagName("head")[0]; head.appendChild(style); } 

  5.6操作表格

  <table>元素拥有的属性和方法

    5.6.1 caption:保存着对<caption>元素的指针

    5.6.2 tBodies:是一个<tbody>元素的HTMLCollection

    5.6.3 tFoot:保存着对<tfoot>的指针

    5.6.4 tHead:保存着<thead>的指针

    5.6.5 rows:一个表格中所有的行的HTMLCollection

    5.6.6 createTHead():创建一个<thead>元素,将其放到表格中,返回引用

    5.6.7 createTFoot():创建<tfoot>元素,将其放到表格中,返回引用

    5.6.8 createCaption():创建<caption>元素,将其放到表格中,返回引用

    5.6.9 deleteTHead():删除<thead>元素

    5.6.10 deleteTFoot():删除<tfoot>元素

    5.6.11 deleteCaption():删除caption元素

    5.6.12 deleteRow(pos):删除指定位置的行

    5.6.13 insertRow(pos):向rows集合中的指定位置插入一行

  <tbody>拥有的属性和方法

    5.6.1 rows:保存着tbody元素中行的HTMLCollection

    5.6.2 deleteRow(pos):删除指定位置的行

    5.6.3 insertRow(pos):向rows集合中的指定位置插入一行,返回对新插入行的引用

    5.6.4 cells:保存着tr元素中单元格的HTMLCollection

    5.6.5 deleteCell(pos):删除指定位置的单元格

    5.6.6 insertCell(pos):向cells集合中的指定位置插入一个单元格,返回对新插入单元格的引用

var table=document.createElement("table");
table.border=1;
var tbody=document.createElement("tbody");
table.appendChild(tbody);
tbody.insertRow(0);//插入第一行
tbody.rows[0].insertCell(0);//在第一行插入第一个单元格
tbody.rows[0].cells[0].appendChild(document.createTextNode("单元格1-1"));//向第一行第一列的单元格中追加文本
tbody.rows[0].insertCell(1);//插入第一行的第二列
tbody.rows[0].cells[1].appendChild(document.createTextNode("单元格1-2"));//向第一行第二列的单元格中追加文本
tbody.insertRow(1);//插入第二行
tbody.rows[1].insertCell(0);//在第二行中插入第一列
tbody.rows[1].cells[0].appendChild(document.createTextNode("单元格2-1"));
tbody.rows[1].insertCell(1);//在第二行中插入第二列
tbody.rows[1].cells[1].appendChild(document.createTextNode("单元2-2"));
document.body.appendChild(table);