DOM
甚么是DOM
Document Object Model
专门针对操作方式FTP的API国际标准
W3C
为何
国际标准化相同应用程序操作方式FTP的API
用DOM操作方式FTP,基本上大部份应用程序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
按结点间关系查找
何时能
已经获得两个结点,要找周围的相关结点时
结点树
包含大部份FTP(结点)的树内部结构
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
.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
在最终提交表单之前触发