js dom 框架(js大神不愿意告诉你dom的那些事)
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
在最终提交表单之前触发
,
免责声明:本文仅代表文章作者的个人观点,与本站无关。其原创性、真实性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容文字的真实性、完整性和原创性本站不作任何保证或承诺,请读者仅作参考,并自行核实相关内容。文章投诉邮箱:anhduc.ph@yahoo.com