客户端检测:
(一)能力检测
能力检测目的是识别浏览器的能力。
在编写代码之前先检测特定浏览器的能力。例如,脚本在调用某个函数之前,可能要先检测该函数是否存在。
(二)怪癖检测
怪癖实际上是浏览器实现中存在的bug。怪癖检测通常涉及到运行一小段代码,然后确定浏览器是否存在某个怪癖。
(三)用户代理检测
通过检测用户代理字符串来识别浏览器。
DOM
(一)节点层次
在HTML页面中,文档元素使用都是<html>元素。在XML中,没有预定义的元素,因此任何元素都可能成为文档元素。
每一段标记都可以通过树中的一个节点来表示:HTML元素通过元素节点表示,特性通过特性节点表示,文档类型通过文档类型节点表示,而注释则通过注释节点表示。
总共有12种节点类型,这些类型都继承自一个基类型。
1.Node类型
Javascript中的所有节点类型都继承自Node类型,因此所有节点类型都共享着相同的基本属性和方法。
每个节点都有一个nodeType属性,用于表明节点的类型。
12个数值常亮来表示节点类型:
1 == Node.ELEMENT_NODE
2 == Node.ATTRIBUTE_NODE
3 == Node.TEXT_NODE
4 == Node.CDATA_SECTION_NODE
5 == Node.ENTITY_REFERENCE_NODE
6 == Node.ENTITY_NODE
7 == Node.PROCESSING_INSTRUCTION_NODE
8 == Node.COMMENT_NODE
9 == Node.DOCUMENT_NODE
10 == Node.DOCUMENT_TYPE_NODE
11 == Node.DOCUMENT_FRAGMENT_NODE
12 == Node.NOTATION_NODE
父节点的firstChild的值指向childNodes列表中的第一个节点;父节点的lastChild的值指向其childNodes列表中的最后一个节点。
someNode.firstChild 的值始终等于 someNode.childNodes[0]
someNode.lastChild 的值始终等于 someNode.childNodes[someNode.childNodes.length-1]
在只有一个子节点的情况下:
firstChild 和 lastChild 指向同一个节点。该节点的nextSibling和previousSibling都为null。
如果没有子节点:
firstChild 和 lastChild 的值均为null。
- hasChildNodes()方法:
这个方法在节点包含一个或多个子节点的情况下返回true。这比查询childNodes列表的length属性更简单。
- ownerDocument属性
该属性指向表示整个文档的文档节点。通过这个属性,可以不必再节点层次中通过层层回溯到达顶端,而是可以直接访问文档节点。
1)操作节点
- appendChild(要插入节点) 方法:用于向childNodes列表的末尾添加一个节点。
- insertBefore(要插入的节点 , 作为参照的节点) 方法:把节点放在childNodes列表中某个特定的位置上
- replaceChild(要插入的节点 , 要替换的节点) 方法:要替换的节点将由个方法返回并从文档树中被移除
- removeChild(要移除的节点) 方法:被移除的节点将成为方法的返回值。
这个四个方法操作的都是某个节点的子节点,也就是说要使用这几个方法必须先取得父节点。
- cloneNode(是否执行深复制) 方法:用于创建调用个方法的节点的一个完全相同的副本
cloneNode(true):表示执行深复制,复制节点及其整个子节点树。
cloneNode(false):表示浅复制,只复制节点本身。复制后的节点副本属于文档所有,但并没有为它指定父节点。
- normalize() 方法:处理文档树中的文本节点。
处理文本节点不包含文本(则删除该节点),或者接连出现两个文本节点的情况(合并为一个文本节点)。
2.Document类型
JavaScript通过Document类型表示文档。在浏览器中,document对象是HTMLDocument的一个势力,表示整个HTML页面。而且,document对象时window对象的一个属性,因此可以将其作为全局对象来访问。
Document节点具有下列特征:
nodeType 的值为 9 ;
nodeName 的值为 “#document”;
nodeValue 的值为 null;
parentNode 的值为 null;
ownerDocument 的值为 null;
其子节点可能是一个DocumentType(最多一个)、Element(最多一个)、ProcessiongInstruction 或 Comment。
2.1 Document(文档)的子节点
两个内置的访问Document子节点的快捷方式:
1)documentElement属性:该属性始终指向HTML页面中的<html>元素
2)通过childNodes列表访问文档元素
var html = document.documentElement; //取得对<html>的引用 var body = document.body; //取得对<body>的引用 var doctype = document.doctype;//取得对<!DOCTYPE>的引用
所有浏览器都支持document.documentElement和document.body属性。
不同的浏览器对document.doctype 的支持差别很大。
2.2 文档信息
作为HTMLDocument的一个实例,document对象还有一些标准的Document对象所没有的属性。这些属性提供了document对象所表现的网页的一些信息。
1) title属性:取得<title>元素文本
取得<title>元素的文本---显示在浏览器窗口的标题栏或者标签页上。通过这个属性可以取得当前页面的标题,也可以修改当前页面的标题并反映在浏览器的标题栏中。
2)URL属性:地址栏中显示的UTL
3)domain属性:只包含页面的域名
4)referrer属性:保存着链接到当前页面的那个页面的URL。在没有来源页面的情况下,referer属性中可能包含空字符串。
var url = document.URL; // http://localhost:8080/ForView/ var domain = document.domain; //localhost var referrer = document.referrer; //null
2.3 查找元素
取得元素的操作可以使用docume对象的几个方法来完成
1)getElementById("要取得元素的ID"):
若不存在带有相应的ID的元素,则返回null。严格匹配,区分大小写。
如果页面中有多个元素的ID相同,getElementById()只返回文档中第一次出现的元素。
2)getElementByTagName("要取得元素的标签名"):
方法的返回的是包含零个或多个元素的NodeList。在HTML文档中,这个方法的会返回一个HTMLCollection对象,作为一个“动态”集合,该对象鱼NodeList非常类似。
取得HTMLCollection对象中的项的方法:可以使用方括号语法或item()方法来访问HTMLCollection对象中的项。
取得HTMLCollection对象中元素的数量:通过length属性取得。
2.4 特殊集合
这些特殊集合都是HTMLCollection 对象,包括:
document.anchors :包含文档中所有带 name 特性的<a>元素;
document.forms :包含文档中所有的<form>元素,与document.getElementByTagName("form")得到的结果相同。
document.images :包含文档中所有的<img>元素,与document.getElementsByTagName("img")得到的结果相同。
document.links :包含文档中所有带 href 属性的<a>元素。
2.5 文档写入
将输出流写入到网页中,4个方法:
1) write("要写入到输出流中的文本"):会原样写入
2) writeln("要写入到输出流中的文本"):会在字符串的末尾添加一个换行符(\n)
3)open()
4)close()
3.Element类型
除了Document类型,Element类型就算是Web编程中最常用的类型了。Element类型用于表现XML或HTML元素,提供了对元素标签名、子节点及特性的访问。
Element节点具有以下特征:
nodeType 的值为 1 ;
nodeName 的值为元素的标签名;
nodeValue 的值为 null ;
parentNode 可能是Document 或 Element ;
其子节点可能是Element、Text、Comment、ProcessingInstruction、CDATASection 或 EntityReference。
要访问元素的标签名,可以使用nodeName属性,也可以使用tagName属性。
window.οnlοad=function(){ var div = document.getElementById("myDiv"); alert(div.tagName); //DIV alert(div.nodeName); //DIV }
这里元素的标签名是div,其ID为myDiv。在HTML中,标签名始终都以全部大写表示;而在XML中,标签则始终会与源代码中的保持一致。
如果不确定自己的脚本将会在HTML还是XML文档中执行,最好是在比较值钱将标签名转换为相同的大小写形式,如下格式:
if(element.tagName.toLowerCase()=="div"){ //在此执行某些操作 }
3.1 HTML 元素
所有HTML元素都由HTMLElement类型表示。每个HTML元素都存在下列标准特性:
1)id :元素在文档中的唯一标识符
2)title :有关元素的附加说明信息,一般通过工具提示条显示出来。
3) lang :元素内容的语言代码,很少使用。
4)dir :语言的方向,值为“ltr”(left-to-right,从左至右)或 “rtl”
5)className :与元素的class特性对应,元素指定的css类
<div id="myDiv" class="bd" title="Body text" lang="en" dir="ltr" my_special_attribute="hello!">
Some text
</div>
window.οnlοad=function(){ var div = document.getElementById("myDiv"); alert(div.id+"\n"+ //myDiv div.lang+"\n"+ //en div.className+"\n"+ //bd div.title+"\n"+ //Body text div.dir); //ltr }
<body> <script type="text/javascript"> var div=null; function setValues(){ if(div==null){ div = div.getElementById("myDiv"); } div.id = "someotherId"; div.title = "some other text"; div.dir = "rtl"; div.lang = "fr"; div.className = "ft"; } function getValues(){ if(div==null){ div= document.getElementById("myDiv"); } alert(div.id+"\n"+div.title+"\n"+div.className+"\n"+div.dir+"\n"+div.lang) } </script> <div id="myDiv" class="bd" title="Body text" lang="en" dir="ltr" my_special_attribute="hello!"> Some text </div> <input type="button" value="Get Values" οnclick="getValues()" /> <input type="button" value="Set Values" οnclick="setValues()" /> </body>
3.2 取得特性和设置特性
操作特性的DOM方法主要有三个,分别是getAttribute()、setAttribute() 和 removeAttribute()。
- getAttribute()
(1)传递给getAttribute()的特性名域实际的特性名相同。要想得到class特性值,应该传入“class”而不是“className”,只有在通过对象属性访问特性时才用。如果给定名称的特性不存在,getAttribute()返回null。
alert(div.getAttribute("id")+"\n"+div.getAttribute("class")); //myDiv,bd alert(div.id+"\n"+div.className); //myDiv,bd
(2)通过getAttribute()方法也可以取得自定义特性的值。例如:
<div id="myDiv" my_special_attribute="hello!"> </div>
获取自定义特性 my_special_attribute的值:
div= document.getElementById("myDiv");
alert(div.getAttribute("my_special_attribute"));
(3)有两类特殊的属性:style 和 onclick
style:通过getAttribute()访问,style特性值是CSS文本;通过style属性访问返回一个对象
<p id="p1" style="background-color:green">Some text</p> var p=document.getElementById("p1"); alert(p.getAttribute("style")); //BACKGROUND-COLOR:green alert(p.style); //返回一个对象
onclick:通过getAttribute()访问,返回onclick等于的字符串;通过onclick属性访问返回一个函数。
<input id="input1" type="button" value="Get Values" οnclick="getValues()" /> function getValues(){ var input1 = document.getElementById("input1"); alert(input1.getAttribute("onclick")); //getValues() alert(input1.onclick); //返回结果如下图 }
因此,开发人员不经常使用getAttribute(),而只使用对象的属性。只有在取得自定义特性值得情况下,才会使用getAttribute()方法。
- setAttribute(“要设置的特性名” , "要设置的值")
如果特性已经存在,setAttribute()会以指定的值替换现有的值;如果特性不存在,setAttribute()则创建该属性并设置相应的值。
var div=null; function setValues(){ if(div==null){ div = document.getElementById("myDiv"); } div.setAttribute("id","someOtherId"); div.setAttribute("class","ft"); } function getValues(){ if(div==null){ div = document.getElementById("myDiv"); } alert(div.id+","+div.className); }
像下面这样为DOM元素添加一个自定义的属性,该属性不会自动成为元素的特性。
div.mycolor = "red"; alert(div.getAttribute("mycolor")); //null(IE可以取得其值)
使用setAttribute()则可以
div.setAttribute("sport","basketball"); alert(div.getAttribute("sport")); //basketball
推荐通过属性来设置特性。
- removeAttribute(“要清除的特性”)
用于彻底删除元素的特性。不仅会清除特性的值,还会从元素中完全删除特性。
3.3 attributes 属性
Element类型是使用attributes 属性的唯一一个DOM节点类型。attributes属性中包含一个NamedNodeMap,与NodeList类似,也是一个“动态”的集合。元素的每一个特性都由一个Attr节点表示,每个节点都保存在NamedNodeMap对象中。
NamedNodeMap对象拥有下列方法:
- getNamedItem(name) :返回nodeName属性等于name的节点;
- removeNamedItem(name) :从列表中移除nodeName属性等于name的节点;
- setNamedItem(node) :向列表中添加节点,以节点的nodeName属性为索引;
- item(pos) :返回位于数字pos位置处的节点。
attribute属性中包含一系列节点,每个节点的nodeName就是特性的名称,而节点的nodeValue就是特性的值。
例如:要取得元素的id特性:
function getValues(){ var div = document.getElementById("myDiv"); var id0 = div.attributes.getNamedItem("id").nodeValue; var id1 = div.attributes.getNamedItem("title").nodeValue; var id2 = div.attributes["class"].nodeValue; div.attributes["id"].nodeValue = "someOtherId"; alert(id0); //myDiv alert(div.id); //someotherId } <div id="myDiv" title="some text" class="bp" lang="en" dir="ltr"> some text </div>
<input type="button" value="GetAttribute" οnclick="getValues()" />
例如:遍历元素的特性,使用attributes属性,要求输出结果为name=“value” name=“value”这样的字符串
<script> function getValues(){ var div = document.getElementById("myDiv"); alert(getAllValues(div)); } function getAllValues(element){ var paris = new Array(); var attrName,attrValue,i,len; for(i=0,len=element.attributes.length;i<len;i++){ attrName = element.attributes[i].nodeName; attrValue = element.attributes[i].nodeValue; paris.push(attrName +"=\" "+attrValue+"\" "); } return paris.join(" "); } </script> <div id="myDiv" title="some text" class="bp" lang="en" dir="ltr"> some text </div> <input type="button" value="GetAttribute" οnclick="getValues()" />
3.4 创建元素 document.createElement()方法
使用document.createElement(“要创建元素的标签名”) 方法可以创建新元素。在使用createElement()方法创建信元素的同时,也为新元素设置了owerDocument属性。还可以操作元素的特性,为它添加更多子节点,以及执行其他操作。
window.onload = function(){ var div = document.createElement("div"); div.id = "myNewDiv"; div.className = "box"; alert(getAllValues(div)); } function getAllValues(element){ var paris = new Array(); var attrName,attrValue,i,len; for(i=0,len=element.attributes.length;i<len;i++){ attrName = element.attributes[i].nodeName; attrValue = element.attributes[i].nodeValue; paris.push(attrName +"=\" "+attrValue+"\" "); } return paris.join(" "); }
在新元素上设置这些特性只是给他们赋予了相应的信息。由于新元素尚未被添加到文档树中,因此设置这些特性不会影响浏览器的显示。
把新元素添加到文档树,可以使用appendChild()、insertBefore() 或 replaceChild() 方法。
- appendChild()
<style> .box{ width:32px; height:32px; background:red; } </style> <script> function createNewElement(){ var div = document.createElement("div"); div.id = "myNewDiv"; div.className = "box"; document.body.appendChild(div); } </script> <div id="myDiv" title="some text" class="bp" lang="en" dir="ltr">some text</div> <input type="button" value="Create Element" οnclick="createNewElement()" />
3.5元素的子节点
元素可以有任意数目的子节点和后代节点。子节点有可能是元素、文本节点、注释或处理指令。
<ul id="myList"> <li>item1</li> <li>item2</li> <li>item3</li> </ul> //获取ul的子节点 function getItems(){ var ul = document.getElementById("myList"); var len = ul.childNodes.length; for(var i=0;i<len;i++){ alert(ul.childNodes[i].nodeName); } }
取得<ul>中所有<li>元素,可使用下列代码:
var ul = document.getElementById("myList"); var items = ul.getElementsByTagName("li");
4. Text 类型
文本节点有Text类型表示。纯文本中可以包含转义后的HTML字符,但不能包含HTML代码。Text节点具有以下特征:
nodeType 值为3;
nodeName 的值为 “#text”;
nodeValue 的值为节点所包含的文本;
parentNode 是一个 Element;
不支持子节点(或者说没有子节点);
可以通过nodeValue属性或data属性访问Text节点中包含的文本,这两个属性中包含的值相同。对nodeValue的修改也会通过data放映出来,反之亦然。
操作节点中的文本的方法:
appendData(text) :将text添加到节点的末尾
deleteData(offset,count): 从offset指定的位置开始删除count个字符。
insertData(offset,text): 从offset指定的位置插入text。
replaceData(offset,count,text) :用text替换从offset指定的位置开始到offset+count为止处的文本
splitText(offset):从offset指定的位置将当前文本节点分成两个文本节点。
substringData(offset, count):提取从offset指定的位置开始到offset+count为止处理的字符串。
length属性:保存着节点中字符的数目。nodeValue.length == data.length
使用下面代码来访问这些文本子节点:element.firstChild 或者Element.childNodes[0]
- 没有内容,也就没有文本节点
<div id="myDiv" ></div> var div = document.getElementById("myDiv"); alert(div.firstChild); //null
- 有空格,因而只有一个文本节点
<div id="myDiv" > </div> var div = document.getElementById("myDiv"); alert(div.firstChild); //[object Text] alert(div.firstChild.length); //1 ;有几个空格长度就是几
- 有内容,因而有一个文本节点
<div id="myDiv" >Hello</div> var div = document.getElementById("myDiv"); alert(div.firstChild); //[object Text] alert(div.firstChild.length); //5
修改文本节点:element.childNode[0].nodeValue = “text”
<div id="myDiv" > </div> var div = document.getElementById("myDiv"); div.firstChild.nodeValue="Some <strong>other</strong> message"; document.write(div.childNodes[0].nodeValue); //Some <strong>other</strong> message
4.1 创建文本节点 document.createTextNode()
例:新建一个div,为其添加文本节点,并将元素添加到文档的<body>里
window.onload = function(){ var element = document.createElement("div"); var textNode1 = document.createTextNode("<strong>Hello</strong> world"); element.appendChild(textNode1); document.body.appendChild(element); }
例:每个元素只有一个文本子节点。如果两个文本节点时相邻的同胞节点,那么这两个节点中的文本就会连起来。
window.onload = function(){ var element = document.createElement("div"); var textNode1 = document.createTextNode("<strong>Hello</strong> world"); element.appendChild(textNode1); var textNode2 = document.createTextNode("Yoyo"); element.appendChild(textNode2); document.body.appendChild(element); //<strong>Hello</strong> worldYoyo }
4.2 规范化文本节点:使用normalize()
如果在一个包含两个或多个文本节点的父元素上调用normalize()方法,则会将所有文本节点合并成一个节点,结果节点的nodeValue等于合并前每个文本节点的nodeValue值拼接起来的值。
window.onload = function(){ var element = document.createElement("div"); var textNode1 = document.createTextNode("<strong>Hello</strong> world"); element.appendChild(textNode1); var textNode2 = document.createTextNode("Yoyo"); element.appendChild(textNode2); document.body.appendChild(element); //<strong>Hello</strong> worldYoyo alert(element.childNodes.length); //2 element.normalize(); alert(element.childNodes.length); //1 alert(element.firstChild.nodeValue); //<strong>Hello</strong> worldYoyo }
规范化之后,length为1.
4.3 分割文本节点
Text 类型提供了一个作用于normalize()相反的方法:splitText().
window.onload = function(){ var element = document.createElement("div"); var textNode1 = document.createTextNode("Hello world"); element.appendChild(textNode1); document.body.appendChild(element); var newNode = element.firstChild.splitText(5); //从位置5开始分割 alert(element.firstChild.nodeValue); //"Hello" alert(newNode.nodeValue); //" world" alert(element.childNodes.length); //2 }
5.Comment类型
注释在DOM中是通过Comment类型来表示的,Comment节点具有下列特征:
nodeType 的值为 8;
nodeName 的值为 “#comment”;
nodeValue 的值是注释的内容;
parentNode 可能是Document 或 Elelement;
不支持子节点或者说没有子节点。
Comment类型与Text类型继承自相同的基类,因此它拥有除splitText()之外的所有字符串操作的方法。与Text类型相似,也可以通过nodeValue 或 data 属性来取得注释的内容。
<body> <script type="text/javascript"> function getValues(){ var div = document.getElementById("myDiv"); var newComment = document.createComment("A Comment"); div.appendChild(newComment); var comment1 = div.childNodes[0]; var comment2 = div.childNodes[1]; alert(comment1.nodeName+":"+comment1.data); //#comment:This is A Comment alert(comment2.nodeName+":"+comment2.data); //#comment:A comment } </script> <div id="myDiv" class="bd"> <!--This is A Comment--> </div> <input id="input1" type="button" value="Get Values" οnclick="getValues()" /> </body>
- 开发人员很少会创建和访问注释节点,因为注释结点对算法鲜有影响。
- 浏览器不会识别位于</html>标签后面的注释。
6. CDATASection类型
CDATASection 类型只针对基于XML的文档,表示的是CDATA区域。与Comment类似,CDATASection 类型继承自Text 类型,因此拥有除splitText()之外的所有字符串操作的方法。
CDATASection节点具有下列特征:
nodeType 的值为 4;
nodeName 的值为“#cdata-section”;
parentNode 可能是Document 或 Element;
不支持子节点即没有子节点。
在真正的XML文档中,可以使用document.createCDataSection()来创建CDATA区域,只需要为其传入节点的内容即可。
7. DocumentType 类型
DocumentType 类型在Web浏览器中并不常用,Firefox和Chrome支持它,IE不支持。DocumentType包含着与文档的doctype有关的所有信息,它具有下列特征:
nodeType 的值为 10;
nodeName 的值为 doctype 的名称;
nodeValue 的值为 null;
parentNode 是Document;
不支持子节点,没有子节点。
DOM1级描述了DocumentType对象的3个属性:name,entities 和 notations。
name:表示文档类型的名称(html、XHTML);
entities:是由文档类型描述的实体的NamedNodeMap对象;
notations:是由文档类型描述的符号的NamedNodeMap对象。
alert(document.doctype.name); //html
8. DocumentFragment 类型
在所有的节点类型中,只有DocumentFragment 在文档中没有对应的标记。DOM规定文档片段是一种“轻量级”的文档,可以包含和控制节点,但不会像完整的文档那样占用额外的资源。DocumentFragment节点具有下列特征:
nodeType 的值为 11;
nodeName 的值为"#document-fragment";
nodeValue 的值为 null;
parentNode 的值为 null;
子节点可以是Element、ProcessingInstruction、Comment、Text、CDATASection 或 EntityReference。
可以通过appendChild()或insertBefore()将文档片段中内容添加到文档中。只会将文档片段的所有子节点添加到相应位置上;文档片段永远不会成为文档树的一部分。
<body> <script type="text/javascript"> function getValues(){ 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);
alert(fragment.childNodes.length); //0 } </script> <ul id="myList"></ul> <input id="input1" type="button" value="Get Values" οnclick="getValues()" /> </body>
此时文档片段的所有子节点都被删除并转移到<ul>元素中。
9. Attr 类型
元素的特性在DOM中以Attr类型来表示。从技术角度讲,特性就是存在于元素的attributes属性的节点。特性节点具有下列特性:
nodeType 的值为 11;
nodeName 的值是特性的名字;
nodeValue 的值是特性的值;
parentNode 的值为 null;
在HTML中不支持(没有)子节点;
在XHTML中子节点可以是Text 或 EntityReference。
尽管它们也是节点,但特性却不被认为是DOM文档树的一部分。开发人员最常用的是getAttribute()、setAttribute() 和 removeAttribute()方法,很少直接引用特性节点。
- Attr 对象有3个属性:name、value 和 specified。
name 是特性名称,与 nodeName 的值相同。
value 是特性的值,与 nodeValue 的值相同。
specified 是一个布尔值,用以区别特性是代码中指定的,还是默认的。
- document.createAttribute() 创建新的特性节点
<body> <script type="text/javascript"> function getValues(){ var attr = document.createAttribute("align"); attr.value="right"; var p = document.getElementById("myText"); p.setAttributeNode(attr); alert(p.attributes["align"].value);//right alert(p.getAttributeNode("align").value);//right alert(p.getAttribute("align")); //right } </script> <p id="myText">Hello</p> <input id="input1" type="button" value="Get Values" οnclick="getValues()" /> </body>
可以通过下列任何方式访问该特性:
attributes属性、getAttributeNode()方法以及getAttribute()方法。其中:
attributes属性 和 getAttributeNode() 都会返回对应特性的Attr节点;
getAttribute() 则只返回特性的值。
(二)DOM操作技术
1.动态脚本
跟操作HTML元素一样,创建动态脚本也有两种方式:插入外部文件 和 直接插入JavaScript代码。
1)插入外部文件
- 动态加载的外部JavaScript文件能够立即运行,比如下面的<script>元素:
<script type="text/javascript" src="util.js"></script>
- 创建这个节点的DOM代码:封装成函数
function loadScript(url){ var script = document.createElement("script"); script.type = "text/javascript"; script.src = url; document.body.appendChild(script); } loadScript("client.js");
加载完成后,就可以在叶明中的其他地方使用这个脚本了。问题只有一个:怎么知道脚本加载完成了呢?答案见后续 《事件》的学习。
2)直接插入JavaScript代码
<script type="text/javascript"> function sayHi(){ alert("hi"); } sayHi(); </script>
使用DOM操作,插入如上效果的javascript:
<script> function loadScriptString(code){ var script = document.createElement("script"); script.type = "text/javascript"; try{ script.appendChild(document.createTextNode(code)); }catch(ex){ script.text = code; } document.body.appendChild(script); } loadScriptString("function sayHi(){alert('hi');}"); sayHi(); </script>
try...catch的使用:首先尝试用标准的DOM文本节点方法,因为除了IE(在IE中会导致抛出错误),所有浏览器都支持这种方式。如果这行代码抛出了错误,说明是IE,于是就必须使用text属性了。
2.动态样式
能够把CSS样式包含到HTML页面中的元素有两个:
<link>元素用于包含来自外部的文件;
<style>元素用于指定嵌入的样式。
与动态脚本类似,所谓动态样式是指在页面刚加载时不存在的样式;动态样式是在页面加载完成后动态添加到页面中的。
1)以<link>元素为例:
<link rel="stylesheet" type="text/css" href="styles.css">
使用DOM代码动态创建这个元素:
<body> <script> function loadCSS(url){ var link = document.createElement("link"); link.rel = "stylesheet"; link.type = "text/css"; link.href = url; var head = document.getElementsByTagName("head")[0]; head.appendChild(link); } loadCSS("styles.css"); </script> <p id="myText">Hello</p> <input id="input1" type="button" value="loadCSS" οnclick="loadCSS()" /> </body>
2)使用<style>元素来包含嵌入式CSS
<style type="text/css"> #myList{ font-size:larger; color:red; } </style>
相应的,使用DOM操作
<body> <script> function loadStyleString(css){ var style = document.createElement("style"); style.type = "text/css"; try{ style.appendChild(document.createTextNode(css)); }catch(ex){ style.styleSheets.cssText = css; } var head = document.getElementsByName("head")[0]; head.appendChild(style); } loadStyleString("#myText{font-size:larger;color:red;}"); </script> <p id="myText">Hello</p> <input id="input1" type="button" value="loadStyleString" οnclick="loadStyleString()" /> </body>
注意:不要设置style.rel="stylesheet";
3. 操作表格
创建下面的HTML表格:
<table border="1" width="100%"> <tbody> <tr> <td>Cell 1,1</td> <td>Cell 1,2</td> </tr> <tr> <td>Cell 2,1</td> <td>Cell 2,2</td> </tr> </tbody> </table>
使用核心DOM方法创建这些元素:
<script> function createTable(){ var table = document.createElement("table"); table.border = 1; table.width = "100%"; var tbody = document.createElement("tbody"); table.appendChild(tbody); //创建第一行 var row1 = document.createElement("tr"); tbody.appendChild(row1); var cell1_1 = document.createElement("td"); cell1_1.appendChild(document.createTextNode("Cell 1,1")); row1.appendChild(cell1_1); var cell1_2 = document.createElement("td"); cell1_2.appendChild(document.createTextNode("Cell 1,2")); row1.appendChild(cell1_2); //创建第二行 var row2 = document.createElement("tr"); tbody.appendChild(row2); var cell2_1 = document.createElement("td"); cell2_1.appendChild(document.createTextNode("Cell 2,1")); row2.appendChild(cell2_1); var cell2_2 = document.createElement("td"); cell2_2.appendChild(document.createTextNode("Cell 2,2")); row2.appendChild(cell2_2); document.body.appendChild(table); } </script> <input type="button" value="CreateTable" οnclick="createTable()"/> </body>
显然DOM代码很长。
HTMLDOM为<table>、<tbody>和<tr>元素添加了一些属性和方法。
- 为<table>元素添加的属性和方法如下:
属性:
caption :保存着对<caption>元素(如果有)的指针。
tBodies:是一个<tbody>元素的HTMLCollection。
tFoot:保存着对<tfoot>元素(如果有)的指针。
tHead:保存着对<thead>元素(如果有)的指针。
rows:是表格中所有行的HTMLCollection。
方法:
createTHead( ):创建<thead>元素,将其放到表格中,返回引用。
createTFoot( ):创建<tfoot>元素,将其放到表格中,返回引用。
createCaption( ):创建<thead>元素,将其放到表格中,返回引用。
deleteTHead( ):删除<thead>元素。
deleteTFoot( ):删除<tfoot>元素。
deleteCaption( ):删除<caption>元素。
deleteRow( pos):删除指定位置的行。
insertRow( pos):向 rows 集合中的指定位置插入一行。
- 为<tbody>元素添加的属性和方法如下:
属性:
rows:保存着<tbody>元素中行的HTMLCollection。
方法:
deleteRow( pos):删除指定位置的行。
insertRow( pos):向rows集合中的指定位置插入一行,返回对新插入行的引用。
- 为<tr>元素添加的属性和方法如下:
属性:
cells:保存着<tr>元素中单元格的HTMLCollection。
方法:
deleteCell( pos):删除指定位置的单元格。
insertCell( pos):向cells集合中的指定位置插入一个单元格,返回对新插入单元格的引用。
使用这些属性和方法,可以极大地减少创建表格所需的代码数量。重写上面的代码:
function createTableSimple(){ var table = document.createElement("table"); table.border="1"; table.width="100%"; var tbody = document.createElement("tbody"); table.appendChild(tbody); //创建第一行 tbody.insertRow(0); var cell1 = tbody.rows[0].insertCell(0); cell1.appendChild(document.createTextNode("Cell 1,1")); var cell2 = tbody.rows[0].insertCell(1); cell2.appendChild(document.createTextNode("Cell 1,2")); //创建第二行 var row2 = tbody.insertRow(1); var cell3 = row2.insertCell(0); cell3.appendChild(document.createTextNode("Cell 2,1")); var cell4 = row2.insertCell(1); cell4.appendChild(document.createTextNode("Cell 2,2")); document.body.appendChild(table); }
4.使用NodeList
理解NodeList及其“近亲”NamedNodeMap 和 HTMLCollection,是从整体上透彻理解DOM关键所在。着个三个集合都是“动态的”,每当文档结构发生变化时,它们都会得到更新。
所有NodeList对象都是在访问DOM文档时实时运行的查询。例如下面代码会导致无限循环:
var divs = document.getElementsByTagName("div"), i, div; for(i=0;i<divs.length;i++){ div = document.createElement("div"); document.body.appendChild(div); }
第一行代码会取得文档中所有<div>元素的HTMLCollection。由于这个集合是“动态的”,因此只要有新<div>元素被添加到页面中,这个元素也会被添加到该集合中。浏览器不会将创建的所有集合都保存在一个列表中,而是在下一次访问集合时再更新集合。
解决办法:使用length属性初始化第二个变量,然后将迭代器与该变量进行比较。
var divs = document.getElementsByTagName("div"), i, div, len; for(i=0,len=divs.length;i<len;i++){ div = document.createElement("div"); document.body.appendChild(div);
alert(document.getElementsByTagName("div").length); //最新的div数量 }
DOM2 和 DOM3
DOM1 级:主要定义的是HTML和XML文档的底层架构。
DOM2 级和 DOM3 级则在这个结构的基础上引入了更过的交互能力,也支持了更高级的XML特性。
为此,DOM2 和 DOM3 级分为许多模块,分别描述了DOM的某个非常具体的子集。这些模块如下:
DOM2 级核心 :DOM Level 2 Core 在1级核心基础上构建,为节点添加了更多方法和属性。
DOM2 级视图: DOM Level 2 Views 为文档定义了基于样式信息的不同视图。
DOM2 级事件: DOM Level 2 Events 说明了如何使用事件与DOM文档交互。
DOM2 级样式: DOM Level 2 Style 定义了如何以编程方式访问和改变CSS样式信息。
DOM2 级遍历和范围: DOM Level 2 Traversal and Range 引入遍历DOM文档和选择其特定部分的新接口。
DOM2 级HTML: DOM Level 2 HTML 在1级 HTML基础上构建,添加了更多属性、方法和新接口。
DOM2 级和 DOM3 级的目的在于扩展DOM API,以满足操作XML的所有需求,同时提供更好的错误处理及特征检测能力。
- 检测浏览器是否支持这些DOM模块:document.implementation.hasFeature()
function inspectDOM(){ var supportsDOM2Core = document.implementation.hasFeature("Core","2.0"); var supportsDOM3Core = document.implementation.hasFeature("Core","3.0"); var supportsDOM3HTML = document.implementation.hasFeature("HTML","2.0"); var supportsDOM2Views = document.implementation.hasFeature("Views","2.0"); var supportsDOM2XML = document.implementation.hasFeature("XML","2.0"); alert("supportsDOM2Core:"+supportsDOM2Core); alert("supportsDOM3Core:"+supportsDOM3Core); alert("supportsDOM3HTML:"+supportsDOM3HTML); alert("supportsDOM2Views:"+supportsDOM2Views); alert("supportsDOM2XML:"+supportsDOM2XML); }
(一)DOM 变化
1.针对XML命名空间的变化
从技术上说,HTML不支持XML命名空间,但XHTML支持XML命名空间。因此本节给出的都是XHTML的示例。
- 命名空间要使用xmlns特性来指定,XHTML的命名空间为"http://www.w3.org/1999/xhtml"
<html xmlns="http://www.w3.org/1999/xhtml">
- 要想明确地为XML命名空间创建前缀,可以使用xmlns后跟冒号,再后跟前缀 xmlns:xhtml="http://www.w3.org/1999/xhtml"
<xhtml:html xmlns:xhtml="http://www.w3.org/1999/xhtml">
<xhtml:head>
<xhtml:title>Example XHTML page</xhtml:title>
</xhtml:head>
<xhtml:body>
Hello world!
</xhtml:body>
</xhtml:html>
在只基于一种语言编写XML文档的情况下,命名空间实际上也没有什么用。但是,在混合使用两种语言的情况下,命名空间的用处就非常大了。
- 混合了XHTML 和SVG 语言的文档:
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Example XHTML page</title>
</head>
<body>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 100 100" style="width:100%;height:100%">
<rect x="0" y="0" width="100" height="100" style="filled:red"/>
</svg>
</body>
</html>
这样<svg>元素的所有子元素,以及这些元素的所有特性,都被认为属于http://www.w3.org/2000/svg 命名空间。
1)Node类型的变化
在DOM2 级中,Node类型包含下列特定于命名空间的属性:
localName:不带命名空间前缀的节点名称。
namespaceURI:命名空间URI或者null(未指定时)
prefix:命名空间前缀或者null(未指定时)
当节点使用了命名空间前缀时,其nodeName等于prefix+“:”+localName。
<html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Example XHTML page</title> <script type="text/javascript"><![CDATA[ function getElementInfo(){ var html = document.documentElement; var svg = document.getElementsByTagNameNS("http://www.w3.org/2000/svg","svg")[0]; alert("html.namespaceURI:"+html.namespaceURI);//"http://www.w3.org/1999/xhtml" alert("html.localName:"+html.localName); //html alert("html.prefix:"+html.prefix); //null alert("svg.namespaceURI:"+svg.namespaceURI);// "http://www.w3.org/2000/svg" alert("svg.localName:"+svg.localName); //svg alert("svg.prefix:"+svg.prefix); //s } ]]></script> </head> <body> <s:svg xmlns:s="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 100 100" style="width:20%; height:20%" οnclick="getElementInfo()"> <s:rect x="0" y="0" width="100" height="100" style="fill:red" /> </s:svg> </body> </html>
DOM3 级在此基础上更进一步,又引入了下列与命名空间有关的方法。
isDefaultNamespace(namespaceURI):在指定的namespaceURI是当前节点的默认命名空间的情况下返回true。
lookupNamespaceURI(prefix):返回给定prefix的命名空间。
lookupPrefix(namespaceURI):返回给定namespaceURI的前缀。
alert(document.body.isDefaultNamespace("http://www.w3.org/1999/xhtml")); //true alert(svg.lookupPrefix("http://www.w3.org/2000/svg")); //s alert(svg.lookupNamespaceURI("s")); //"http://www.w3.org/2000/svg"
用途:在取得了一个节点,但不知道该节点与文档其他元素之间关系的情况下,这些方法是很有用的。
2)Document类型的变化
DOM2 级中的Document类型也发生了变化,包含下列与命名空间有关的方法。
createElementNS(namespaceURI,tagName):使用给定的tagName创建一个属于命名空间namespaceURI的新元素。
createAttributeNS(namespaceURI,attributeName):使用给定的attributeName创建一个属于命名空间namespaceURI的新特性。
getElementsByTagNameNS(namespaceURI,tagName):返回属于命名空间namespaceURI的tagName元素的NodeList。
3)Element 类型的变化
getAttributeNS(namespaceURI,localName):取得属于命名空间namespaceURI 且名为localName的特性。
getAttributeNodeNS(namespaceURI,localName):取得属于命名空间namespaceURI且名为localName的特性节点。
getElementByTagNameNS(namespaceURI,tagName):返回属于命名空间namespaceURI的tagName元素的NodeList。
hasAttributeNS(namespaceURI,localName):确定当前元素是否有一个名为localName的特性,而且该特性的命名空间是namespaceURI。“DOM2 级核心”也增加了一个hasAttribute()方法,用于不考虑命名空间的情况。
removeAttributeNS(namespaceURI,localName):删除属于命名空间namespaceURI 且名为 localName 的特性。
setAttributeNS(namespaceURI,qualifiedName,value):设置属于命名空间namespaceURI 且名为 qualifiedName 的特性的值为 value。
setAttitudeNodeNS(attNode):设置属于命名空间namespaceURI的特性节点。
4)NamedNodeMap 类型的变化
getNamedItemNS(namespaceURI,localName):取得属于命名空间namespaceURI 且名为 localName 的项。
removeNamedItemNS(namespaceURI,localName):删除属于命名空间namespaceURI 且名为 localName 的项。
setNamedItemNS(node):添加node,这个节点已经事先指定了命名空间信息。
(二)样式
2.1 访问元素的样式
任何支持style特性的HTML元素在Javascript中都有一个对应的style属性。这个style对象是CSSStyleDeclaration的实例,包含着通过HTML的style特性制定的所有样式信息,但不包含与外部样式表或嵌入样式表经层叠而来的样式。
对于使用短划线(background-image)的CSS属性名,必须将其转换成驼峰大小写形式,才能通过Javascript来访问。
访问格式如下:
多数情况下,都可以通过简单地额转换属性名的格式来实现转换。其中一个不能直接转化的CSS属性是float,因为float是Javascript中的保留字,因此不能用作属性名。“DOM2 级样式” 规范规定样式对象上相对应的属性名应该是cssFloat;FireFox、Chrome都支持这个属性。而IE支持的则是styleFloat。
<body> <input type="button" value="Get" οnclick="setStyle()"> <div id="mydiv">Hello</div> <script type="text/javascript"> function setStyle(){ var div=document.getElementById("mydiv"); div.style.backgroundColor="green"; div.style.width="50px"; div.style.height="50px"; div.style.styleFloat="right"; //for IE div.style.cssFloat="right"; //for not IE } </script> </body>
- DOM 样式属性和方法
“DOM2 级样式”规范还未style 对象定义了一些属性和方法,这些属性和方法在提供元素的style特性值得同事,也可以修改样式。
- 属性:
cssText:访问style特性中的CSS代码。
length:应用给元素的CSS属性的数量。
parentRule:表示CSS信息的CSSRule对象。
- 方法:
getPropertyCSSValue(propertyName):返回包含给定属性值得CSSValue对象。
getPropertyPriority(propertyName):如果给定的属性使用了!important设置,则返回“important”;否则,返回空字符串。
getPropertyValue(propertyName):返回给定属性的字符串值。
item(index):返回给定位置的CSS属性的名称。
removeProperty(propertyName):从样式中删除给定属性。
setProperty(propertyName,value,priority):将给定属性设置为相应的值,并加上优先权标志(“important”或一个空字符串)。
cssText属性:
在读模式下,cssText返回浏览器对style特性中CSS代码的内部表示。
在写模式下,给cssText赋值会重写整个style特性的值。
var div=document.getElementById("mydiv"); div.style.cssText = "width:50px;height:50px;background-color:green"; alert(div.style.cssText);
用途:设置cssText 是为元素应用多项变化最快捷的方式,因为可以一次性地应用所有变化。
length 属性:
length 属性的目的,就是将其与item()方法配套使用,以便迭代在元素中定义的CSS属性。可以使用方括号语法来代替item()来取得给定位置的CSS属性。
function setStyle(){ var div=document.getElementById("mydiv"); div.style.cssText = "width:50px;height:50px;background-color:green"; var prop,value; for(var i=0,len=div.style.length;i<len;i++){ prop = div.style.item(i); //或者 div.style[i] value = div.style.getPropertyValue(prop); document.write(prop+" : "+value+"<br/>"); } }
结果显示:
removeProperty()方法:
使用这个方法移除一个属性,意味着将会为该属性应用默认的样式。在不确定某个给定的CSS属性拥有什么默认值的情况下,就可以使用这个方法。只要移除相应的属性,就可以为元素应用默认值。
div.style.removeProperty("width");
2.2 计算的样式
因为style对象不包含哪些从其他样式表层叠而来并影响到当前元素的样式信息,所以“DOM2 级样式” 增强了 document.defaultView,提供了getComputedStyle()方法。
document.defaultView.getComputedStyle()
2.3 元素大小
1)偏移量
function getOffset(){ var div = document.getElementById("content"); alert(div.offsetWidth); //获取元素的宽度 alert(div.offsetHeight); //获取元素的高度 alert(div.offsetLeft); //元素左外边框到父元素的左内边框之间的像素距离 alert(div.offsetTop); //元素上外边框到父元素的上内边框之间的像素距离 }
注意:element.offsetParent 是包含element的对象。
例子:取得元素的左和上偏移量的函数:
<script> function getElementLeft(element){ var actualLeft = element.offsetLeft; var current = element.offsetParent; //取得父元素 while(current!=null){ actualLeft += current.offsetLeft; current = current.offsetParent; } return actualLeft; } function getElementTop(element){ var actualTop = element.offsetTop; var current = element.offsetParent; while(current!=null){ actualTop += current.offsetTop; current = current.offsetParent; } return actualTop; } function getActualTopLeft(){ var div = document.getElementById("content"); var actualTop = getElementTop(div); var actualLeft = getElementLeft(div); alert(actualTop+" ; "+ actualLeft); } </script> <div id="content" style="background-color:red; border:1 solid black"> </div> <input id="myButton" type="button" value="simple" οnclick="getActualTopLeft()">
2)客户区大小
元素的客户区大小(Client dimension),指的是元素内容及其内边距所占据的空间大小。
- clientWidth 属性:元素内容区宽度 + 左右内边距宽度
- clientHeight 属性:元素内容高度 + 上下内边距高度
客户区大小就是元素内部的空间大小,因此滚动条占用的空间不计算在内。
用途:确定浏览器视口的大小。
例子:取得浏览器视口大小的函数
function getViewport(){ if(document.compatMode=="BackCompat"){ return { width:document.body.clientWidth, height:document.body.clientHeight }; }else{ return { width:document.documentElement.clientWidth, height:document.documentElement.clientHeight, }; } }
function showViewport(){ var s = getViewport(); alert("width:"+s.width+";height:"+s.height); }
getViewport( )函数返回一个对象,包含width和height这两个属性,表示浏览器视口的大小。
3)滚动大小