DOM

什么是DOM

document Object Model

专门操作网页内容的API标准

W3C

为什么

统一不同浏览器操作网页内容的API

用DOM操作网页内容,几乎所有浏览器100%兼容

DOM Tree

网页中一切内容都是节点(Node)对象

一切节点对象都存储在一个树型结构中

根节点

document

节点对象三大属性

nodeType

节点的类型

何时

判断节点类型

document 9 elem 1 attr 2 text 3

问题:

无法进一步判断元素的名称

解决

另见:

nodeName

节点名称

何时

只要进一步判断元素的名称

document #document elem 全大写标签名 attr 属性名 text #text

nodeValue

节点值

document null elem null attr 属性值 text 文本内容

DOM操作

构建DOM树

查找触发事件的元素

绑定事件

查找要操作的元素

修改

增加

删除

事件处理函数中的this

自动获得触发事件的当前元素

查找

不需要查找可直接获得的节点

document

document.documentElement

html

document.head

document.body

document.forms[i/"id"]

form

按节点间关系查找

何时

已经获得一个节点,要找周围的相关节点时

节点树

包含所有网页内容(节点)的树结构

2大类关系

1. 父子

elem.parentNode

最靠谱

elem.childNodes

*直接*子节点

elem.firstChild

elem.lastChild

2. 兄弟

elem.previousSibling

elem.nextSibling

优: 完整

问题:

受看不见的空字符的干扰

解决

元素树

仅包含元素节点的树结构

不是一棵新树,仅是节点树的子集

何时

只关心元素,不关心文本时

2大类关系

1. 父子

elem.parentElement

没有node结尾

elem.children

IE8

elem.firstElementChild

elem.lastElementChild

2. 兄弟

elem.previousElementSibling

elem.nextElementSibling

优: 不受看不见的空字符的干扰

缺: 不包含一切文本节点

可用.innerHTML

兼容性问题: IE9

childNodes和children

都返回动态集合(live collection)

不实际存储数据,每次访问集合,都重新查找DOM树

优:

首次查找返回速度快

缺:

反复访问集合,会导致反复查找DOM树

遍历

for(var i=0,len=children.length;i<len;i )

递归遍历

何时

只要遍历一个父节点下所有后代节点

如何

//Step1: 仅遍历parent的直接子节点 function getChildren1(parent){ console.log(parent.nodeType!=3?parent.nodeName:parent.nodeValue); var children=parent.childNodes; for(var i=0,len=children.length;i<len;i ){ //Step2: 为每个子节点调用和父节点完全相同的函数 arguments.callee(children[i]); } }

深度优先遍历

当同时有子节点和兄弟节点时,优先遍历子节点。所有子节点遍历完,才遍历兄弟节点

问题: 递归的效率是极低

解决: 可用循环代替递归

function getChilddren2(parent){ //Step1: 创建迭代器对象 var iterator=document.createNodeIterator( parent, NodeFilter.SHOW_ALL , null, false .SHOW_ELEMENT ); var node; while((node=iterator.nextNode())!=null){ //node获得当前正在遍历的节点 console.log(node.nodeType!=3?node.nodeName:node.nodeValue); } }

问题:

只能遍历所有,如需筛选,得自己写判断

解决:

如何按条件查询

按HTML查找

按id

var elem=document.getElementById("id")

返回一个元素对象

如果找不到,返回null

强调: 只能用在document上

按标签名

var elems=parent.getElementsByTagName("标签名")

返回动态集合

如果找不到,返回空集合

强调:

可用在任意父节点上

不仅查找直接子节点,且查找所有后代节点

按name

var elems=document.getElementsByName("name")

强调:

只能在document上调用

按class

var elems=parent.getElementsByClassName("class")

返回动态集合

如果找不到,返回空集合

强调:

可用在任意父节点上

不仅查找直接子节点,且查找所有后代节点

只要class中包含指定的类名,就选择

兼容性问题

IE9

问题:

一次只能用一个条件查找,如果查找条件复杂时,会步骤繁琐

按选择器查找

Selector API

只找一个

var elem=parent.querySelector("selector")

找所有符合条件的多个

var elems=parent.querySelectorAll("selector")

返回非动态集合

强调:

可在任意父元素上调用

受制于浏览器对选择器的兼容性

按HTML vs 按选择器

1. 返回值:

按HTML

返回动态集合

selector API

返回非动态集合

直接存储所有数据,反复访问集合,不需要反复查找DOM树

2. 首次查询效率

按HTML更高

仅返回需要的内容,不需要准备完整数据

selector API低

第一次要返回完整数据

3. 易用性:

按HTML繁琐

selector API简单

何时

如果只凭一个条件即可获得想要的元素时,首选按HTML查找

如果需要多级复杂条件查找才能获得想要的元素时,用selector API

修改

内容

.innerHTML

获取或设置开始标签到结束标签之间的html代码片段

.textContent

获取或设置开始标签到结束标签之间的纯文本内容

去掉所有标签

翻译转义字符为正文

IE8:

.innerText

表单元素的内容

.value

属性

标准属性

核心DOM

操作一切结构化文档的通用API

即可操作HTML,又可操作XML

获取

了解

var attrNode=elem.attributes[i/属性名] .getAttributeNode("属性名")

var value=attrNode.value

var value=elem.getAttribute("属性名")

修改

elem.setAttribute("属性名",属性值)

如果属性不存在,也可set

判断是否包含

var bool=elem.hasAttribute("属性名")

移除

elem.removeAttribute("属性名")

只移除开始标签中的attribute,不删除内存中对象的property

特点

万能

繁琐

解决

HTML DOM

专门操作HTML文档的简化版API

只对部分常用API进行简化

如何

elem.属性名

所有HTML标准属性都被封装在HTML DOM对象中,可直接用.访问。用法普通对象的属性完全一样

特点:

简单

不是万能

需要核心DOM的补充

状态属性

disabled, checked, selected

问题:

核心DOM不能操作:

解决:

HTML DOM

elem.状态

.checked .selected .disabled

选择器:

查找指定状态的元素

:checked :selected :disabled

扩展(自定义)属性

何时

代替id,元素,class选择器,给多个元素添加行为

HTML DOM无法访问扩展属性

核心DOM

HTML5

定义:

data-属性名="值"

访问:

elem.dataset.属性名

查找

CSS属性选择器

[data-属性名=值]

样式

内联样式:

elem.style.css属性名

强调:

css属性名要去横线变驼峰

何时

专门用于修改内联样式

不影响其他元素的样式

优先级最高

问题:

获取时,只能获得内联样式

无法访问从样式表层叠或继承来的完整样式

解决

获取一个元素计算后的完整样式:

计算后的样式:

最终应用到元素上的完整样式

包括所有内联,内部,外部样式

将相对单位的值,计算为绝对单位

何时

只要获取样式,就要获取计算后的样式

var style=getComputedStyle(elem对象)

var value=style.样式属性名

强调:

通过getComputedStyle获得的样式对象是只读

内部/外部样式表

修改样式表中的样式

var sheet=document.styleSheets[i]

var rule=sheet.cssRules[i]

如果获得的是keyframes,就需要继续找子rule

rule.style.样式属性=值

最好的修改样式的做法

修改class属性,批量应用样式

添加和删除

3步

创建新元素对象

var elem=document.createElement("标签名")

设置关键属性

将元素添加到DOM树

parent.appendChild(child)

parent.insertBefore(child,oldChild)

parent.replaceChild(child,oldChild)

问题:

每操作一次DOM树,都会导致重新layout

解决

优化

尽量少的操作DOM树

如果同时添加父元素和子元素

先在内存中将子元素添加到父元素

再将父元素一次性添加到DOM树上

如果同时添加多个平级子元素

使用文档片段

什么是

内存中临时存储多个子元素的虚拟父元素

3步:

创建文档片段

var frag=document.createDocumentFragment();

将子元素临时添加到frag中

frag.appendChild(child)

将frag添加到DOM树

parent.appendChild(frag)

强调:

frag不会成为页面元素,添加子元素后,frag自动释放

删除

parent.removeChild(child)

child.parentNode.removeChild(child)

HTML DOM常用对象

Image

var img=new Image();

Select/Option

属性

value

当前选中项的value

如果选中项没有value,则使用内容

selectedIndex

当前选中项的下标

options

获得当前select下所有option的集合

length

相当于.options.length

获得option的个数

清空option

.length=0

事件

onchange

当选中项发生改变时

方法

sel.add(option)

不支持文档片段

sel.remove(i)

Option

创建

var opt=new Option(text,value)

属性

text,value,index

Table/...

创建

var thead=.createTHead()

var tbody=.createTBody()

var tfoot=.createTFoot()

删除

.deleteTHead()

.deleteTFoot()

获取

.tHead

.tBodies[i]

.tFoot

行分组

创建

var tr=.insertRow(i)

固定套路

1. 末尾追加一行: insertRow()

2. 开头插入一行: insertRow(0)

删除

.deleteRow(i)

问题

i无法自动获得

解决

首选

table.deleteRow(tr.rowIndex)

获取

.rows

tr

创建

var td=.insertCell(i)

删除

.deleteCell(i)

获取

.cells

删除行

行分组.deleteRow(i)

i是相对于当前行分组内的位置

table.deleteRow(tr.rowIndex)

rowIndex是相对于整个表中的位置

Form

获取:

var form=document.forms[i/id]

属性:

.elements

获得所有表单元素的集合

input textarea select button

.length

.elements.length

获得所有表单元素的个数

方法:

form.submit()

代替submit按钮,在程序中手动提交表单

Element

获得表单中的元素

获得任意表单元素:

form.elements[i/id/name]

如果表单元素有name属性

form.name

方法

.focus()

.blur()

事件

onsubmit

在最终提交表单之前触发

js dom 框架(js大神不愿意告诉你dom的那些事)(1)

,