一、DOM的变化
- DOM2级核心
- DOM2级视图
- DOM2级事件
- DOM2级样式
- DOM2级遍历和范围
- DOM2级的HTML
二、样式
2.1、访问元素的样式
任何支持style特性的HTML元素在javascript中都有一个对应的style属性。对于使用短划线的css属性ming,必须将其转化为驼峰大小的形式,才能通过Javascript访问
其中float属性,“DOM级样式”规范规定样式对象上相应的属性名是cssFloat,但是IE浏览器支持的是styleFloat
var myDiv=document.getElementById("myDiv")
myDiv.style.backgroundColor="red";
myDiv.style.width="100px"
myDiv.style.height="100px"myDiv.style.border="1px solid black"
2.1.1、DOM样式属性和方法
- 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)
//cssText
myDiv.style.cssText="width:25px;height:100px;background-color:green"
console.log(myDiv.style.cssText)//width: 25px; height: 100px; background-color: green;
//获取属性
for(var i=0,len=myDiv.style.length;i<len;i++){
// console.log(myDiv.style[i])
console.log(myDiv.style.item(i))//width height background-color}
//获取属性值
var prop,value,i,len;
for(var i=0,len=myDiv.style.length;i<len;i++){
prop=myDiv.style[i]
value=myDiv.style.getPropertyValue(prop);
console.log(prop+":"+value)//width: 25px; height: 100px; background-color: green;}
//删除属性值
myDiv.style.removeProperty("width")
//设置属性值
myDiv.style.setProperty("width","100px")
2.1.2、计算的样式
getComputedStyle()方法:这个方法接收两个参数,要取得计算样式的元素和一个伪字符串,如果不需要伪字符串,第二个参数可以是null,返回一个对象(与style属性的类型相同),其中包含当前元素的所有计算样式
var computerdStyle=document.defaultView.getComputedStyle(myDiv,null);
但IE浏览器不指出,它支持currentStyle属性
var computerdStyle=myDiv.currentStyle
2.2、操作样式表
CSSStyleSheet类型表示的是样式表,包括通过元素包含的样式表和在style元素中定义的样式表
document.styleSheets集合表示文档的所有样式表
for(var i=0,len=document.styleSheets.length;i<len;i++)
{
sheet=document.styleSheets.item(i);
console.log(sheet)//CSSStyleSheet {ownerRule: null, type: "text/css", href: "file:///F:/%E4%BB%A3%E7%A0%81%E6%96%87%E4%BB%B6/js%E9%AB%98%E7%BA%A7/style.css", ownerNode: link, parentStyleSheet: null, …}}
另外,也可以通过或者
2.2.1、CSS规则
CSSRule对象表示样式中地每一条规则,实际上,CSSRule是一个供其他多种类型继承的基类型,其中最常见的就是CSSStyleRule类型,包括以下属性
- cssText:返回整条规则对应的文本
- parentRule:如果是当前规则是导入的规则,这个属性引用的就是导入规则,否则,这个值为null
- parentStyleSheet:当前规则所属的样式表
- selectorText:返回当前规则的选择符文本
- style:一个CSSStyleDeclaration对象
- type:表示规则类型的常量值
var sheet=document.styleSheets[0];
var rules=sheet.cssRules||sheet.rules;//取得规则列表var
rule=rules[0];//取得第一条规则
console.log(rule.selectorText);//#myDiv
console.log(rule.style.cssText)//width: 100px; height: 200px; background-color: blue;
console.log(rule.style.backgroundColor)//blueconsole.log(rule.style.width)//100px
console.log(rule.style.height)//200px
2.2.2、创建规则
DOM规定,insertRule()方法:这个方法接收两个参数:规则文本和表示在哪里插入规则的索引
IE8以及之前的版本支持类似的方法,addRule():同样接收两个参数要想跨浏览器使用,可以引入如下函数
function insertRule(sheet,selectorText,cssText,position)
{
if(sheet.insertRule){ sheet.insertRule(selectorText+"{"+cssText+"}",position);
}else if(sheet.addRule){
sheet.addRule(selectorText,cssText,position)
}
}
2.2.3、删除规则
deleteRule():接收一个参数,要删除的规则的位置
DOM方法:deleteRule()
IE方法:removeRule()
跨浏览器的方法如下
function deleteRule(sheet,index){
if(sheet.deleteRule){
sheet.deleteRule(index)
}else if(sheet.removeRule){
sheet.removeRule(index)
}
}
2.3、元素大小
2.3.1、偏移量
包括元素在屏幕上占用的所有可见空间,元素的可见大小由其高度,宽度决定,包括所有的内边距,滚动条,边框大小
以上四个属性可以得到其偏移量
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
}
2.3.2、客户区大小
元素的客户区大小,指的是元素内容以及其内边距所占据的空间大小
function getViewport(){
if(document.compatMode=="BackCompat"){//混杂模式(IE7之前的版本
return{
width:document.body.clientWidth,
height:document.body.clientHeight
}
}else{//标准模式
return{
width:document.documentElement.clientWidth,
height:document.documentElement.clientHeight
}
}
}
2.3.3、滚动大小
滚动内容的元素的大小
在确定文档的总高度时,必须取得scrollWidth/clientWidth和scrollHeight/clientHeight的最大值,才能保证在跨浏览器的环境下得到精确的结果
var docHeight=Max.max(document.documentElement.scrollHeight,document.documentElement.scrollWidth)
var docWidth=Max.max(document.documentElement.scrollWidth,document.documentElement.clientWidth)
2.3.4、确定元素的大小
getBoundingClientRect():返回一个矩形对象,包含四个属性:left,top,right,bottom
var rectObject = myDiv.getBoundingClientRect();console.log(rectObject)//DOMRect {x: 8, y: 8, width: 100, height: 200, top: 8, right:108,bottom:208,left:8}
考虑兼容性的写法
//见书p326
三、遍历
3.1、 NodeIterator
两个主要的方法是nextNode()和previousNode()
可以使用document.createNodeIterator()方法创建它的实例
这个方法接受下列四个参数:
root:想要作为搜索起点的树的节点
whatToshow:表示想要访问节点的数字代码
filter:是一个NodeFilter对象,或者表示一个应该接受还是拒绝某种特定节点的函数,每个NodeFilter只有一个方法,即acceptNode(),如果应该访问给定的节点,返回NodeFilter.FILTER_ACCTPT,如果不用改访问,返回NodeFilter.FILTER_SKIP
entityReferenceExpansion:布尔值,表示是否扩展实体引用。
var div = document.getElementById("div1");
var iterator = document.createNodeIterator(div, NodeFilter.SHOW_ELEMENT,null, false);
var node = iterator.nextNode();
while (node !== null) {
console.log(node.tagName)//DIV P B UL LI LI LI
node = iterator.nextNode(); }
如果只需要遍历出li元素,则使用filter
var filter={
acceptNode:function(node){
return node.tagName.toLowerCase()=="li"?
NodeFilter.FILTER_ACCEPT:
NodeFilter.FILTER_SKIP;
}
}
var div = document.getElementById("div1");
var iterator = document.createNodeIterator(div, NodeFilter.SHOW_ELEMENT,null, false);
var node = iterator.nextNode();
while (node !== null) {
console.log(node.tagName)//DIV P B UL LI LI LI
node = iterator.nextNode(); }
3.2、TreeWalker
除了nextNode()和previousNode()外,还有其他几个方法:
- parentNode():遍历到当前父节点
- firstChild():遍历到当前节点的第一个子节点
- lastChild():遍历到当前节点的最后一个子节点
- nextSibling():遍历当前节点的下一个同辈节点
- previousSibling():遍历当前节点的上一个同辈节点
创建TreeWalker对象要使用document.createTreeWalker()方法,参数与document.createnodeIterator()相同。
不同的是,除了NodeFilter.FILTER_SKIP和NodeFilter.FILTER_ACCEPT外,还可以使用NodeFilter.FILTER_REJECT,其中NodeFilter.FILTER_SKIP会跳过相应的节点继续前进到子树的下一节点,NodeFilter.FILTER_REJECT会直接跳过整个的子树
当然,TreeWalker真正强大的地方在于能够在DOM结构中任何方向移动,即使不定义过滤器,也可以获取所有的li元素
var div = document.getElementById("div1");
var walker = document.createTreeWalker(div, NodeFilter.SHOW_ELEMENT,null, false);
walker.firstChild();
walker.nextSibling()
var node=walker.firstChild();
while(node!==null){
console.log(node.tagName);
node=walker.nextSibling() }
TreeWalker还有一个属性,名叫currentNode,表示任何遍历方法在上一次遍历返回中的节点
var node=walker.nextNode();
console.log(node===walker.currentNode)//true
四、范围
4.1、DOM中的范围
document.createRange()创建范围
每个范围都由一个Range类型的实例表示,这个实例拥有很多属性和方法。下列属性提供了当前范围在文档中的位置信息
startContainer:包含范围起点的节点
startOffset:范围在startContainer中起点的偏移量
endContainer:包含范围终点的节点
endOffset:范围在endConstiner中终点的偏移量
commonAncestorContainer:startContainer和endContainer共同祖先节点在文档树中位置最深的那个
4.1.1、用DOM范围实现简单选择
最简单的是使用selectNode()或者selectNodeContents(),这两个方法都接受一个参数,一个DOM节点,然后使用该节点中的信息来填充范围,其中selectNode()选择整个节点,包括其子节点,而selectNodeContents()选择节点的子节点
var range1=document.createRange(),
range2=document.createRange(),
p1=document.getElementById("p1");
range1.selectNode(p1);
range2.selectNodeContents(p1)
console.log(range1)//
startContainer: body
// startOffset: 1
// endContainer: body
// endOffset: 2
// collapsed: false
// commonAncestorContainer: body
// __proto__: Range
console.log(range2)
// startContainer: p#p1
// startOffset: 0
// endContainer: p#p1
// endOffset: 2
// collapsed: false
// commonAncestorContainer: p#p1
// __proto__: Range
4.1.2、用DOM范围实现复杂选择
要创建复杂的选择就要使用setStart()和setEnd(),这两个方法都接受两个参数:一个参照节点和一个偏移量值
模仿selectNode()和selectNodeContents()
var range1=document.createRange(),
range2=document.createRange(),
p1=document.getElementById("p1"),
p1Index=-1,
i,len;
for(i=0,len=p1.parentNode.childNodes.length;i<len;i++)
{
if(p1.parentNode.childNodes[i]==p1){
p1Index=1;
break;
}
}
range1.setStart(p1.parentNode,p1Index);
range1.setEnd(p1.parentNode,p1Index+1);
range2.setStart(p1,0);
range2.setEnd(p1,p1.childNodes.length)
console.log(range1)
console.log(range2)
他们更胜一筹的是可以选择节点的一部分
//选择hello world中的llo wo
var p1=document.getElementById("p1"),
helloNode=p1.firstChild.firstChild,
worldNode=p1.lastChild;
var range=document.createRange();
range.setStart(helloNode,2);
range.setEnd(worldNode,3)
4.1.3、操作DOM范围中的内容
在前面创建的文档片段中,选区分别开始和结束于两个文本标签的内部,因此不能算格式良好的DOM结构,但是,范围知道自己缺少哪些开标签和闭标签,能够重新构建有效的DOM结构
从文档中删除范围内所包含的内容deleteContents()
var p1=document.getElementById("p1"),
helloNode=p1.firstChild.firstChild,
worldNode=p1.lastChild;
var range=document.createRange();
range.setStart(helloNode,2);
range.setEnd(worldNode,3)range.deleteContents()//Herld!
执行上述代码后,页面会显示如下HTML代码:
Herld!
由于范围选区在修改底层DOM结构是能够保证格式良好,因此,即使内容被删除了,最终的DOM结构依旧是良好的。extractContent()也会从文档中移除范围选区,但是这两个方法的区别在于,extractContent()会返回范围的文档片段
...
var fragment=range.extractContents();p1.parentNode.appendChild(fragment)
结果页面的HTML代码为
Herld!
llowocloneContents()创建范围对象的一个副本,然后在文档的其他地方插入该文档的副本
...
var fragment=range.cloneContents()
p1.parentNode.appendChild(fragment)
结果页面的HTML代码为
Hello world!
llo wo #### 4.1.4、插入DOM范围中的内容 insertNode():向范围选区的开始处插入一个节点var span=document.createElement("span");
span.style.color="red";
span.appendChild(document.createTextNode("Inserted text"));r
ange.insertNode(span)
surroundContents(),这个方法环绕插入内容,这个方法接受一个参数,即环绕范围内容的节点
range.selectNode(helloNode);
var span=document.createElement("span");
span.style.backgroundColor='yellow';
range.surroundContents(span)
4.1.5、折叠DOM范围
collapse():用来折叠范围,这个方法接受一个参数,一个布尔值,表示要折叠到范围的那一端。参数true表示折叠到范围的起点,参数false表示折叠到范围的终点,要确定范围已经折叠完毕,可以检查collapsed属性
range.collapse(true)
console.log(range.collapse)
检测某个范围是否处于折叠状态,可以帮我们确定范围中的两个节点是否紧邻。
<p id="p1">Paragraph 1</p><p id="p2">Paragraph 2</p>
var p1=document.getElementById("p1"),
p2=document.getElementById("p2"),
range=document.createRange()range.setStartAfter(p1);
range.setEndBefore(p2)console.log(range.collapsed)//true
4.1.6、比较DOM范围
在多个范围的情况下,可以使用compareboundaryPoints()方法来确定这些范围是否公共的边界(起点或者终点),这个方法接受两个参数:比较范围的常量和要比较的范围
范围常量:
Range.START_TO_START(0)
Range.START_TO_END(0)
Range.END_TO_END(0)
Range.END_TO_START(0)
compareBoundaryPoints()方法的返回值:如果第一个范围在第二个范围前面,返回-1,相等,返回0,之后,返回1
var range1=document.createRange()
var range2=document.createRange()
var p1=document.getElementById("p1");
range1.selectNodeContents(p1);
range2.selectNodeContents(p1)
range2.setEndBefore(p1.lastChild)
console.log(range1.compareBoundaryPoints(Range.START_TO_START,range2));
//0
console.log(range1.compareBoundaryPoints(Range.END_TO_END,range2))//1
4.1.6、复制DOM范围
可以使用clonerange(),这个方法会创建调用它的范围的一个副本
var newRange=range.clineRange()
新创建的范围与原来的范围包含相同的属性,而修改他的端点不会影响原来的范围
4.1.7、清理DOM范围
detach(),以便从创建的文档中分离出该范围
4.2、IE8及更早版本中的范围
createTextRange():创建文本范围
4.2.1、用IE范围实现简单的选择
findText():两个参数,给定的文本以及0或1(表示向那个方向搜索)这个方法会找到第一次出现的给定文本,并将范围移过来以环绕文本,如果没有找到文本,就返回false,否则返回true
var range=document.body.createTextRange();
var found=range.findText("hello")
console.log(found);//true
console.log(range.text)//hello
IE中,与selectNode()方法类似的方法是moveToElementText(),这个方法接受一个DOM元素,并选择该元素的所有文本,包括HTML标签
var range=document.body.createTextRange();
var p1=document.getElementById("p1");
range.moveToElementText(p1)
4.2.2、使用IE范围实现复杂的选择
move():首先会折叠当前范围,在将范围移动指定的单位数量
moveStart()
moveEnd()
expand():将任何部分选择的文本全部选中
这些方法都接受两个参数:移动单位和移动单位的数量,其中,移动单位是下列一种字符串。
- character:逐个字符移动
- word:逐个单词移动
- sentence:逐个句子移动
- textedit:移动到当前范围选区的开始挥着结束位置
range.movestart("word",2);//起点移动两个单词
range.moveEnd("character",1)//终点移动一个字符
4.2.3、操作IE范围中的内容
text属性或者pasteHTML()方法
text可以设置文本的内容
var range=document.body.createTextRange();
range.findText("Hello");
range.text="howdy"
pasteHTML()向范围内插入HTML代码
var range=document.body.createTextRange();
range.findText("Hello");
range.pasteHTML("<em>Howdy</em>")
4.2.4、折叠IE范围
collapes()用法与前面相同,但是没有对应的collapsed属性让我们知道乏味是否已经折叠完毕,为此,必须使用boundingWidth属性,该属性返回范围的宽度,如果属性为0,则表示已经折叠了
var isCollapsed=(range.boundingWidth==0)
4.4.5、比较IE范围
compareEndPoints()接受两个参数:比较的类型和要比较额范围,要比较的类型是:StsrtToStart,StartToEnd,StartToEnd,StartToStart
同样与DOM类似的是,它也会按照相同的规则返回值,如果第一个范围在第二个范围前面,返回-1,相等,返回0,之后,返回1
IE中还有两个方法,也是用来比较范围的:isEqual()用于确定两个范围是否相等,inRange()用于确定一个范围是否包含另一个范围
var range1=document.body.createTextRange();
var range2=document.body.createTextRange();
range1.findText("Hello World");
range2.findText("Hello");
console.log(range1.isEqual(range2));//false
console.log(range1.inRange(range2))//true
4.4.6、复制IE范围
duplicate()方法可以复制文本范围,结果会创建原范围的一个副本