首页 > 代码库 > javaScript之DOM

javaScript之DOM

一. 什么是DOM、DOM Tree 、查找元素:

1. 什么是DOM: Document Object Model
DHTML: 所有实现网页动态效果的技术统称
DHTML=HTML+CSS+JS
鄙视题: HTML XHTML DHTML XML
HTML: Hyper Text Markup language
专门编写网页内容的语言
XHTML: 严格的HTML语言标准
DHTML: 所有动态网页技术统称
XML: eXtensible Markup language
专门存储结构化数据时
用途: 1. 存储 2. 在互联网中传输
vs HTML 都是标记语言: 语法完全相同!
不同: XML完全自定义标签和属性名
<student sid="1001">
<name>范冰冰</name>
<math>81</math>
<chs>65</chs>
<eng>93</eng>
</student>
json: JavaScript Object Notation
‘{"name":"范冰冰","math":81,"chs":65,"eng":93}‘

DHTML模型:
BOM: Browser Object Model:专门操作浏览器窗口的API
问题:没有标准!——兼容性极差
window
___________________|___________________________
| | | | | |
history navigator | location screen event
DOM: -----------------|-专门操作网页内容API---
document
|
DOM Tree
|
Node对象

DOM标准: W3C——绝大多数浏览器100%兼容!
DOM初衷: 操作一切结构化文档: HTML XML ——核心DOM
核心DOM: API繁琐,万能!
HTML DOM: 基于核心DOM,专门操作网页内容的简化版本
问题: 仅对主要API提供了简化,不是万能
实际开发: 优先使用HTML DOM
如果HTML DOM无法实现的,就用核心DOM补充

2. ***DOM Tree:
浏览器加载网页的过程:
请求html页面
|
html代码->DOM Tree---->Render Tree->***layout
| | |
请求css->css代码->cssRules |--->paint

html代码->DOM Tree:
1. 在内存中创建document对象——树根
2. 开始顺序读取html内容,边读取边创建节点对象
将节点对象挂到document对象下的DOM Tree上

***节点对象: Node类型
网页中的一切内容都是节点对象:
三大属性:
node.nodeType: 类型
Document:9
Element:1
Attribute:2
Text:3
何时使用: 验证当前获得的节点对象类型时
主要区分: 元素节点和文本节点
node.nodeName: 名称:
元素节点: 标签名(全大写)
何时使用: 精确区分不同元素时
属性节点: 属性名
文本节点: 同一返回#text
document节点: 返回#document
node.nodeValue: 值
文本节点: 文本内容
元素节点: 空

***节点间关系: 六大关系:
1. 父子: node.parentNode: 获得node的上级节点
node.childNodes: 获得node下的所有直接子节点
***childNodes返回的是动态集合:
不实际保存所有的节点对象,仅保存节点对象的引用
每访问一次动态集合都要重新查找DOM树
结果: 所有动态集合,都要先保存长度,再遍历!
node.firstChild: 获得node下第一个子节点
node.lastChild: 获得node下最后一个子节点
2. 兄弟: node.previousSibling: node的前一个兄弟
node.nextSibling: node的后一个兄弟
强调: 除parentNode外,其余都会受到看不见的空字符干扰,包括:回车,制表符,空格

****递归遍历DOM树: 遍历指定父节点下所有子代节点!
递归:对碰到的所有子内容都执行和父级相同的操作
函数内部,又调用了自己
何时使用: 今后只要遍历不确定层级深度的树形结构时
比如: 公司的组织结构
操作系统中文件夹结构
DOM树的节点结构
如何使用: 2步:
1. 先定义仅遍历直接子节点的函数
2. 在函数内,对每个子节点,再调用函数本身,执行相同的操作。

 

 

***DOM Tree
递归遍历(手写): 深度优先: 优先遍历当前节点的子节点
arguments.callee: 指代正在调用的函数本身
何时使用: 专用于递归内部替代写死的函数名
结论: ***递归: 算法简单,效率极低
解决: 多数递归都可用循环代替
循环因为不占用更多系统资源和反复创建对象
效率极高

节点树: 包含所有节点对象的树结构
元素树: 仅包含元素节点的树结构——就是节点树的子集
6个关系:
1. 父子: childNodes(子节点)->children(子元素)
2. 兄弟:
其他属性都是在节点树属性中间插入Element
兼容性: 除children外,都是IE9+
children,IE8

递归API:
1. NodeIterator:深度优先的顺序,前进或后退
如何使用: 2步:
1. 创建迭代器对象:
var iterator=document.createNodeIterator(
node,
NodeFilter.SHOW_ALL/SHOW_ELEMENT,
null,
false
);
2. 使用循环反复调用,直到nextNode()返回null为止:
var currNode=iterator.nextNode();//跳到下一个
var prevNode=iterator.previousNode();//返回上一个

2. TreeWalker: 用法和iterator完全一样:
多了个别API: walker.firstChild();
walker.lastChild();

3. ***查找:
1. 按HTML查找
1. 按id查找*1个*:
var elem=document.getElementById("id值");
2. 按标签名查找*多个*:
var elems=parent.getElementsByTagName("标签名")
强调:1. elems返回的也是动态集合
2. 不但可查找直接子节点,而且还查找所有子代节点。
3. 按Name属性查找*多个*: 专门找表单中的元素
var elems=parent.getElementsByName("name");
4. 按class属性查找*多个*: IE9+
var elems=parent.getElementsByClassName("class")

2. 按CSS选择器: Selector API ——jQuery的核心
1. var elem=parent.querySelector("选择器");
会找到parent下的和选择器匹配的第一个元素
2. var elems=parent.querySelectorAll("选择器");
会找到parent下的和选择器匹配的所有子代元素
强调: elems是非动态集合!
elems中实际存储节点对象及其属性
反复访问elems,不会导致重复查找
for(var i=0;i<elems.length;i++)

getElementXXX vs Selector API
效率: getElementsXXX 高于 Selector API
使用: Selector API 比 getElementXXX 更易用!
jQuery: write less do more
何时使用: 一次查找就可得到结果——首选getXXX
查找层级复杂的元素时——Selector API

二、元素内容  、属性  、样式

1. 元素内容:
1. innerHTML: 开始标签到结束标签之间的html原文
何时使用: 批量替换或删除元素下所有子内容时
避免反复layout! 提高效率。
2. innerText/textContent: 开始标签到结束标签之间的解析后的纯文本内容。——丢弃所有标签,翻译特殊符号

课堂练习: 2_2:
1.获取select下所有option: sel.options
遍历:
for(var i=0,len=sel.options.length;i<len;i++)
2.判断option是否被选中:
opt.selected -可直接作为bool用
3. 如果遍历时,可能中途删除新元素:从后向前遍历!

2. 属性:
核心DOM: 万能,繁琐
读取属性值: var 属性值=elem.getAttribute("属性名")
设置属性值: elem.setAttribute("属性名","属性值")
移除属性: elem.removeAttribute("属性名")
判断属性: var bool=elem.hasAttribute("属性名")

HTML DOM: 简单,不能完成所有功能
读取属性值: var 属性值=elem.属性名;
设置属性值: elem.属性名="值";
移除属性: elem.属性名="";

Property vs Attribute:
Attribute(特性): 出现在html开始标签中的属性
Property(属性): 在程序中,可用.访问的对象的属性
html标准特性: 所有的attribute都可用.访问!
都是Property
也可用核心DOM访问
自定义特性: 只能用核心DOM访问
比如: a.year -> 仅在内存中的对象上
不会出现在页面的特性中
a.href -> 即使对象的属性,有可设置页面的特性

课堂练习: 3_2.html
1. 获得焦点与失去焦点:
onfocus: 当获得焦点时自动触发
onblur: 当失去焦点时自动触发

3. 样式:
1. 内联样式:直接写在开始标签style中的样式属性
1. 读取: var 属性值=elem.style.属性名
2. 设置: elem.style.属性名="值"
清除内联样式:
style是封装了所有内联样式属性的对象,不能直接赋值""来清除内联样式。而要设置style.cssText为""。
强调:
1.凡是页面上获取的,或设置回页面的属性值都是字符串 2. 长度,大小,位置属性的值,都是带单位的。
设置时: 结尾拼"单位"
读取时: 先parseFloat,再计算
3.***style对象只能获得内联样式,无法获得外部或内部样式表中的样式属性。
解决: 今后凡是获取计算后的完整样式:
var style=getComputedStyle(elem);//DOM
elem.currentStyle; //IE8
兼容代码:
if(elem.currentStyle){
var style=elem.currentStyle;
}else{
var style=getComputedStyle(elem);
}
今后凡是设置元素的样式时,都可用.style.属性:
因为内联样式的优先级最高!

2. 内部/外部样式表:(不建议使用)
1. 获得要修改的属性所在的样式表对象:
document.styleSheets: 保存了当前网页的所有样式表对象.
var sheet=document.styleSheets[i];
2. 获得属性所在的cssRule对象:
每个sheet对象下,有一个cssRules集合:
保存了每个cssRule对象:
一个选择器+{},就是一个cssRule对象
var rule=sheet.cssRules[i];
特殊:动画: 一个rule下还可能包含子cssRules
3. 通过rule对象的style属性.属性名

 

三、创建和删除节点 、HTML DOM常用对象(Select/Option,Table,Form)

1. 创建和删除节点:
创建单个节点: 3步
1. 创建空节点对象:
var elem=document.createElement("标签名");
比如: var a=document.createElement("a");
相当于:html: <a></a>
2. 定义必要属性: 修改元素的属性
比如: a.href="http://tmooc.cn";
a.innerHTML="go to tmooc";
相当于:html:
<a href="http://tmooc.cn">go to tmooc</a>
3. 将新元素,添加到指定父元素下: 导致重新layout
parent.appendChild(新元素)
parent.insertBefore(新元素,现有元素)

创建多个平级子节点: 3步:
1. 先创建文档片段对象:
文档片段:内存中,临时保存一组子元素的虚拟父元素 var frag=document.createDocumentFragment();
2. 将多个新节点,临时追加到文档片段对象中
frag.appendChild(新子节点);
3. 将文档片段作为一个整体追加到页面父元素上
parent.appendChild(frag);
何时使用: 只要创建多个平级子节点,就都要先放入文档片段,再整体追加到页面。

 

删除节点: parent.removeChild(子节点);
固定写法: 子节点.parentNode.removeChild(子节点)
替换节点: parent.replaceChild(新节点,旧节点);

2. ***HTML DOM常用对象: 对*个别*复杂元素提供了快捷的创建和删除等API

Image对象: 代表一个img元素:
简化: var img=new Image();

Select对象、Option对象:
select: 代表一个select元素
属性:
options集合保存所有option对象
固定套路: select.options.length=0 清除选项
selectedIndex 获得select中被选中项的下标
方法:
添加新option: select.add(新opt)
代替: select.appendChild(新opt)
删除指定位置的option: select.remove(i)
事件: onchange: 当选中项发生改变时触发

option: 代表一个option元素
创建option: var opt=new Option(text,value);
简化: var opt=document.createElement("option")
opt.innerHTML=text;
opt.value=http://www.mamicode.com/value;
固定套路: 创建opt同时,追加到select中
select.add(new Option(text,value))
属性: opt.index -> 专用于删除

 

table:
其实table上也有rows,insertRow,deleteRow
var thead=createTHead(); deleteTHead();
var tbody=createTBody();
var tfoot=createTFoot(); deleteTFoot();
强调: thead和tfoot只能创建一个
tbody没有delete方法
tHead——只能有一个
rows: 获得当前行分组内的所有tr对象
var tr=insertRow(i): 在当前行分组中i位置插入行
强调:省略i,表示末尾追加
deleteRow(i): 删除当前行分组中i位置的行
强调:省略i,表示删除第一行
tr
rowIndex: 当前行对象所在的行下标
专用于删除行
cells: 获得当前行分组内的所有td对象
var td=insertCell(i): 在当前行i位置插入新格
deleteCell(i): 删除当前行i位置的格
省略i的原理同insertRow和deleteRow
td
tBodies
tBody——可有多个
rows,insertRow(i),deleteRow(i)同tHead
tr
td
tFoot——只能有一个
rows,insertRow(i),deleteRow(i)同tHead
tr
td

Form: 指代页面上一个表单元素
1. 如何获取表单对象:
var form=document.forms[i/"id"/"name"]
2. 如何查找表单中的元素:
var elem=form.elements[i/"id"/"name"]
简写: form.name/id
3. 交互元素的特殊函数:
elem.focus(); //让表单元素elem获得焦点
elem.blur(); //
4. 表单元素:
事件:
onsubmit: 在正式提交表单前,自动触发
专门用于提交前的验证
只有验证通过,才继续提交
否则取消提交
方法:
submit(): 手动提交表单
5. 如果焦点在表单元素内时,按下回车键,会自动提交表单

javaScript之DOM