咱们聊聊【DOM】吧

很长时间以来,我执着于写代码,看代码,不管三七二十一,咚咚咚,几行代码复制粘贴映入眼帘;也许对于我这样的新手来讲,更喜欢看别人的代码,认为别人的就是最好的,看看页面的布局,想想别人重构页面的思路。。。‘做这一行,你要有想法,没想法的人的未来是很糟糕的’,耳边经常有这样如同雷同的话语,而我就是比较喜欢看别人的代码,也许,看着看着,自己的思路也就与别人不一样啦。。。


我不是一个好的程序媛,更谈不上合格这一说,每次写代码,只知道有这个方法,但是具体怎么用,完全是一边百度一边问别人;对于JavaScript的一些方法和属性都有些模糊不清,这也是我写下这篇博客的一个原因。


做技术的人,对于JavaScript都不陌生,JavaScript是网络上最流行的脚本语言,专门实现网页的动态交互功能的;它的三大组成部分是:

①  ES(ECMAScript):是JavaScript的核心语法,它就是一套标准,描述了语言的基本语法和数据类型;

②  DOM(Document Object Model):文档对象模型,专门操作网页内容的一系列API;

③  BOM(Browser Object Model):浏览器对象模型,专门用来操作浏览器窗口的API;

咱们先来了解一下DOM:

⑴  什么是DOM?

专门操作网页内容的API

⑵  三种API

•  核心DOM:可以操作一切结构化文档,包括HTML、XML;

--  万能的

问题:API繁琐

•  HTML DOM:对核心DOM中【部分】常用的API,提供简化的版本;

--  不是万能的

--  专门操作HTML网页内容的API

•  XML DOM:专门操作XML文档的API


温馨提示:

在实际开发中,选最简单的使用,如果简单的无法实现,就用会用的喽!


这里有必要说一下【HTML/XHTML/XML/DHTML】?

HTML:是专门编写网页内容的语言

XHTML:相对于HTML,语法更加严格

XML:专门存储和传输数据的结构化文档

DHTML:一切可以实现网页动态效果的技术的统称;包含了HTML+CSS+JS

⑶  DOM Tree

•  什么是DOM Tree?

网页的所有内容,在内存中其实是以树形结构存储的


•  什么时候创建的呢?

当浏览器读取到html内容时,会自动创建DOM树

•  如何创建的呢?

①  读到html文档时,先创建根节点对象: document 查找元素,创建元素

②  开始顺序读取html文档的内容,创建子节点:网页中一切内容,都是DOM树上的节点对象

节点对象:Node 所有节点对象的父类型

▪  三大属性:

▫  node.nodeType:节点的类型,值为数字

何时使用:判断或者区分节点的类型时

如何使用:

document:9

元素节点:1

属性节点:2

文本节点:3

DOCTYPE:10

问题:nodeType无法细致的区分每种元素

▫  node.nodeName:节点的名称

何时使用:判断或区分节点名时,更多用于细致区分每种元素标签名

如何使用:

document:#document

元素节点:标签名 (全大写)

属性节点:属性名

文本节点:#text

DOCTYPE: html

▫  node.nodeValue:节点的值

何时使用:只用于获得属性的值和文本的内容

如何使用:

document:null

元素节点:null

属性节点:属性值

文本节点:文本内容

DOCTYPE: null

节点间关系:


▪  节点树:

包含所有节点的树结构;任何文本,也都是节点,所以,节点树,会受到看不见的空文本的干扰

何时使用:站在现有节点,查找周边节点

建议:查找节点要就近。

▫  父子关系:

elem.parentNode => 获得elem的父节点       

elem.childNodes ->类数组对象 => 获得elem的所有*直接*子节点 

✦  childNodes:返回所有直接子节点对象,保存在一个类数组对象中。

elem.firstChild => 获得elem的第一个子节点

elem.lastChild=> 获得elem的最后一个子节点

▫  兄弟关系:

elem.previousSibling => 获得elem的前一个兄弟节点

elem.nextSibling=> 获得elem的后一个兄弟节点

▪  元素树:

仅是节点树的一个子集

优: 仅包含元素节点,不受空文本的干扰

缺: 无法访问文本节点

解决: elem.innerHTML

▫  父子关系:

parentElement

children

firstElementChild

lastElementChild

▫  兄弟关系:

previousElementSibling

nextElementSibling

【对比一下】

节点树 
元素树
parentNodeparentElement
childNodeschildren
firstChildfirstElementChild
lastChildlastElementChild
previousSiblingpreviousElementSibling
nextSiblingnextElementSibling


•  遍历API

①  NodeIterator:按照深度优先的原则,依次读取指定父节点下的每个节点

✦  深度优先:每次都优先遍历子节点,所有子节点遍历完毕,再遍历兄弟节点

✦  如何使用?

▪  创建NodeIterator对象

var iterator = document.createNodeIterator(

parent,NodeFilter.SHOW_ALL

.SHOW_ELEMENT

null,false

        );

▪  反复调用

var currNode = iterator.nextNode();
       ▫  让iterator跳到下一个节点,到头返回null
       ▫  强调: 调用一次nextNode,只向前跳一个节点。

iterator.previousNode() 退一个节点

②  TreeWalker:基本用法和NodeIterator完全一样

✦  强调:

✧  不遍历根节点,只遍历子节点

         ✧  又提供了向四周跳转的方法:

walker.parentNode();

walker.firstChild();

walker.lastChild();

walker.previousSibling();

walker.nextSibling();

•  查找/修改/创建/删除API

○  查找

▪  按HTML属性查找:

▫  按id查找一个元素:

var elem=document.getElementById("id")

强调:ById只能用在document对象上

▫  按标签名查找多个子元素:

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

强调:

✦  ByTagName可用在任意父元素上

✦  ByTagName不止查询直接子节点,且查询所有后代节点。

▫  按class属性查找:

var elems=parent.getElementsByClassName("class")

▫  按name属性查找:

var elems=parent.getElementsByName("name");

强调:

✦  即使返回一个元素,也会放在集合中返回。必须加[0],才能去除唯一一个元素

✦  返回值elems: 动态集合

☛动态集合:不实际存储对象的完整属性

问题:

每次访问动态集合时,都会反复去DOM树查找。

解决: 

遍历,首先将length属性的值,保存在变量中。用变量作为循环的条件

▪  用选择器查找:Selector API--jQuery的核心

▫   找1个:

var elem=parent.querySelector("selector");

▫  找多个:

var elems=parent.querySelectorAll("selector");

强调:

elems非动态集合,不会导致反复遍历DOM树

何时使用:

如果需要多次getxxx才能找到目标元素时

不适合使用:基于现有节点向上或向周围爬树时

getElementxxx VS SelectorAPI

效率:

getXXX的效率 比 SelectorAPI高!

getXXX返回动态集合,不需要准备所有数据就可返回结果。——快

selectorAPI,准备好所有相关数据,再返回。——慢

返回值:

getXXX -> 动态集合,可能造成反复遍历DOM树

selectorAPI -> 非动态集合,不会导致反复遍历DOM树

如何选择:

如果一次getXXX查找即可找到结果时,首选getXXX

如果需要多次getXXX才能找到目标元素时,首选selectorAPI

♕不需要查找,可直接获得的元素:

document.body  ->  <body>

document.head  ->  <head>

document.documentElement -> <html>

○  修改

修改内容/修改属性/修改样式

▪  修改内容:

▫  获取或修改元素开始标签和结束标签之间的html内容:

elem.innerHTML

▫  获取或修改元素开始标签和结束标签之间的纯文本内容(去掉标签,将特殊符号转为正文):

textContent 专门用于: 去掉内容中的标签,仅保留文字

 IE8: innerText

▪  修改属性:

▫  获取属性值:

//获得属性节点对象:

var attrNode=

elem.attributes[i/"属性名"];

elem.getAttributeNode("属性名");

attrNode.value //获得属性节点的值

//直接获得属性值

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

  ▫  设置属性值:

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

  ▫  移除属性:

elem.removeAttribute("属性名")

  ▫  判断是否包含指定属性:

elem.hasAttribute("属性名");

❀  HTML DOM: 对部分核心DOM的简化

❀  所有html标准的属性,自动成为元素对象的属性。可用.访问

     元素对象的属性和普通对象的属性用法完全相同。

❀  移除: 将属性赋值为""

强调: HTML DOM只能访问标准属性

自定义属性只能用核心DOM访问

❀  特殊: HTML class -> js className

建议: 修改样式,首选className修改

❀  自定义属性: HTML5

什么是: 开始标签中,data-开头的属性---data-i  data-age

❀  如何获取自定义属性值:

elem.dataset.i

▪  修改样式:

▫  修改内联样式:

获取或设置:

elem.style.css属性名=值

强调:

缺:只能获得内联样式

优:修改一个元素的样式时,又不影响其他元素。

何时使用: 只要修改一个元素的样式时,首选style.css属性名

☛强调(css属性名

将css中的属性名去-,变驼峰,如:

font-size      fontSize

background-color backgroundColor

▫  修改内部/外部样式表里的样式:

✦  获取最终应用到当前元素的计算后的样式

var style=getComputedStyle(elem)

style.css属性名

何时使用:

只要获得一个元素完整的样式,就用getComputedStyle

✦  修改样式表中的样式:强烈不建议: 

样式表对象模型:COM

✧  每个样式表都是一个sheet对象:

var sheet=document.styleSheets[i]

✧  每个选择器后的{...},就是一个cssRule对象

var cssRule=sheet.cssRules[i]

✧  访问每个cssRule中的一个样式属性:

cssRule.style.css属性

○  添加元素(3步)

①  创建空元素:

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

比如: 

var a=document.createElement("a");

相当于在HTML页面创建了:<a></a>

②  设置关键属性:

比如:

a.href="http://tmooc.cn"
a.innerHTML="go to tmooc";

相当于在HTML中创建了:<a href="http://tmooc.cn">go to tmooc</a>

※  页面加载过程:

读html,构建DOM Tree

RenderTree→layout→paint

读CSS,构建cssRule

③  将新元素添加到指定父元素下:

parent.appendChild(child);

将child追加到parent的子元素末尾:

parent.insertBefore(child,oldChild);

将child插入到oldChild之前:

parent.replaceChild(child,oldChild);

用child替换parent下的oldChild:

原则:

尽量减少layout的次数,其实就是减少appendChild的使用次数。

注意:

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

先创建父元素,将子元素添加到父元素

最后将父元素整体添加到页面;

✦  如果父元素已经在页面上,需要同时添加多个同级子元素时:

文档片段:

内存中,临时存储多个子节点的虚拟父节点。

为什么:

反复向页面添加多个子节点会导致反复layout,减低效率

何时使用:

只要添加多个平级子节点时,都要先将子节点放在文档片段中,再将文档片段整体挂到页面上。

如何使用(3步): 

①  创建空文档片段: 

var frag=document.createDocumentFragment();

②  将多个子元素添加到文档片段下

frag.appendChild(child);

③  将片段整体添加到页面上:

parent.appendChild(frag);

片段不会成为页面上的元素,添加后,自动释放。

✦  另外:【select 】

事件:

onchange:当选中项发生改变时

属性: 

elect.selectedIndex 选中项下标

select.value: 

如果option有value,就返回value

如果option没有value,就返回文本

○  删除元素

parent.removeChild(child);

child.parentNode.removeChild(child);

•  HTML DOM常用对象:

○  HTML DOM常用对象有哪些呢?

Image

Select Option 

Table...

Form

✦  Image:指页面上一个img元素

✧  创建:

var img=new Image();

相当于:document.createElement("img")

✦  Select:指一个select元素

✧  事件:

onchange

✧  属性:

select.selectedIndex

select.value

select.options获得select下所有option

select.options.length获取或设置选项的个数,可简写为:select.length

✧  方法:

 将opt追加到select元素下:

select.add(opt)

select.appendChild(opt);

移除select中i位置的opt

select.remove(i)

✦  Option对象:指select下一个option元素

创建:

var opt=new Option(text,value);

相当于: 

var opt=document.createElement("option");

opt.innerHTML=text;

opt.value=value;

属性:opt.text

✦  简写:

创建一个新option,同时添加到select:

sel.add(new Option(text,value));

✦  Table:指代一个table元素

行分组(tHead): 

var thead=table.createTHead();

table.deleteTHead():

table.tHead

表主体(tBody):

var tbody=table.createTBody();

table.tBodis[i];

表页脚(tFoot):

var tfoot=table.createTFoot():

table.deleteTFoot():

table.tFoot

行:

行分组.rows;

var tr=行分组.insertRow(i);

如果省略i,表示末尾追加一行

行分组.deleteRow(i);

如果省略i,表示删除第一行

❀  i都是相对于当前行分组内的下标位置

格:

行.cells;

var td=行.insertCell(i);

强调:只能创建td元素

行.deleteCell(i);

table->tr

table.rows;

var tr=table.insertRow(i);

table.deleteRow(i);

i是相对于整个table的下标位置

tr.rowIndex属性:

标识当前tr在整个表中的行下标;如果删除rowIndex标识的行,必须用table

✦  Form:指代页面上一个表单元素

✧  获取表单:

var form=document.forms[i/id/name];

属性:

form.length 统计表单元素的个数

方法:

form.submit() //手动提交

✧  获取表单中的元素:

var elem=form.elements[i/id/name];

方法:

elem.focus();

elem.blur();

强调:

elements集合仅包含表单元素

简写:

form.id/name

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值