DOM详解
相关代码都放在了我的github上:https://github.com/kisscancer/cnblogs.com-ch11ry/tree/master/DOM-DEMO
DOM层次节点
一.Node类型
- 通过element.nodeType获取到元素的Node类型
- Node.ELEMENT_NODE(1);
- nodeType:1
- nodeName:元素的标签名
- nodeValue:null
- parentNode:可能是 Document 或 Element
- Node.ATTRIBUTE_NODE(2);
- nodeType:2
- nodeName:特性的名称
- nodeValue:特性的值
- parentNode:null
- 在 HTML 中不支持(没有)子节点
- 在 XML 中子节点可以是 Text 或 EntityReference
- Node.TEXT_NODE(3);
- nodeType:3
- nodeName:"#text"
- nodeValue:节点所包含的文本
- parentNode:Element
- 不支持(没有)子节点
- Node.CDATA_SECTION_NODE(4);
- nodeType:4
- nodeName:"#cdata-section"
- nodeValue:CDATA 区域中的内容
- parentNode:可能是 Document 或 Element
- 不支持(没有)子节点
- Node.ENTITY_REFERENCE_NODE(5);
- Node.ENTITY_NODE(6);
- Node.PROCESSING_INSTRUCTION_NODE(7);
- Node.COMMENT_NODE(8);
- nodeType:8
- nodeName:"#comment"
- nodeValue:注释的内容
- parentNode:可能是 Document 或 Element
- 不支持(没有)子节点
- Node.DOCUMENT_NODE(9);
- nodeType:9
- nodeName:"#document"
- nodeValue:null
- parentNode:null
- ownerDocument:null
- Node.DOCUMENT_TYPE_NODE(10);
- nodeType:10
- nodeName:doctype 的名称
- nodeValue:null
- parentNode:Document
- 不支持(没有)子节点
- Node.DOCUMENT_FRAGMENT_NODE(11);
- nodeType:11
- nodeName:"#document-fragment"
- nodeValue:null
- parentNode:null
- 子节点可以是 Element、 ProcessingInstruction、 Comment、 Text、CDATASection 或EntityReference
- Node.NOTATION_NODE(12) ;
- 节点关系:每个节点都有一个 childNodes 属性,其中保存着一个 NodeList 对象,NodeList 是一种类数组对象,并且是一个引用类型,如果元素中的DOM发生变化,那么此nodeList也会随之更新。节点之间基本的访问方法如下:
- firstChild
- lastChild
- nextSibling
- previousSibling
- parentNode
// TODO:代码示例1
- 节点操作:
- appendChild:向childNodes列表的末尾添加节点。arg1:要插入的节点
- insertBefore:根据位置信息向childNodes列表插入节点。arg1:要插入的节点;arg2:作为参照的节点
- replaceChild:根据位置信息向childNodes列表插入节点,并且替换掉某个节点。arg1:要插入的节点;arg2:需要配替换掉的节点
- removeChild:移除要节点。arg1:要被移除的节点
- clonNode:克隆节点。arg1:boolean类型,true时,深度克隆(包含所有子节点);false时,浅克隆(只克隆节点本身)
- normalize:处理文档树中的文本节点。比如节点中有两个相邻的#text子节点,调用此方法后,会合并成一个#text子节点
// TODO:代码示例2
二.Document类型
- 文档子节点
- document.documentElement:返回html节点及其子节点
- documeng.body:返回body节点及其子节点
- document.title:文档标题
- document.URL:完整的网站URL
- document.domain:网站的域名
- document.referrer:从哪个网站跳转过来的
// TODO:代码示例3
- 查找元素
- document.getElementById:返回id相同的第一个匹配到的节点。arg1:节点的id
- document.getElementsByTagName:返回标签相同的NodeList,类型为HTMLCollection对象。arg1:节点的标签
- document.getElementsByName:返回name相同的NodeList,类型为HTMLCollection对象。arg1:节点的name
// TODO:代码示例4
三.Element类型
- HTML元素:都继承HTMLElement,都具有如下公共属性:
- id:唯一标识
- title:附加说明,一般通过工具条显示
- lang:元素内容的语言代码
- dir:语言方向
- className:对应标签中的class属性,因为class在js中是保留字,所以用className代替
// TODO:代码示例5
- Attribute(一般比较少用,直接用js的属性方式访问,如:element.id)
- getAttribute:获得对应Attribute的值,如果对应的值不存在,则返回null(如果要获取class,需要传入className)。arg1:要获取的Attribute
- setAttribute:设置Attribute的值。arg1:要设置的Attribute;arg2:对应的值
- removeAttribute:移除Attribute的值。arg1:要移除的Attribute
// TODO:代码示例6
- Attributes(用的较少,还是Attribute来的方便):获取节点的所有Attribute。NamedNodeMap类型,每个节点的nodeName是特征名(如id、class),nodeValue是对应的值。和NodeList一样,是动态的,拥有如下方法
- getNamedItem(name):返回nodeName等于name的节点
- removeNamedItem(name):从列表中删除nodeName等于name的节点
- setNamedItem(node):向列表中添加节点,以节点的 nodeName 属性为索引
- item(position):返回位于数字position位置的对应节点
// TODO:代码示例7
- 自定义Attribute
- 加上“data-”前缀
- 通过dataset属性可以访问到所有的自定义Attribute
// TODO:代码示例8
- 创建元素
- createElement(tagName):创建对应的标签。arg1:标签名。一般会联合appendChild、inserBefore、replaceChild方法使用
// TODO:代码示例9
- 元素子节点
- 通过childNodes来获取元素的子节点。但是根据不同的浏览器,可能会获取到的节点数会不同,需要判断一下nodeType等于1的,才是真正的子节点
// TODO:代码示例10
四.Text类型
- 可以通过nodeValue或data属性访问Text的值
// TODO:代码示例11
- 操作文本节点的方法
- appendData(text):将 text 添加到节点的末尾。arg1:要添加的text
- deleteData(offset, count):从 offset 指定的位置开始删除 count 个字符。arg1:字符串开始的下标;arg2:总共需要删除的字符串数量
- insertData(offset, text):在 offset 指定的位置插入 text。arg1:字符串开始的下标;arg2:需要插入的text文字
- replaceData(offset, count, text):用 text 替换从 offset 指定的位置开始到 offset+count 为止处的文本。arg1:字符串开始的下标;arg2:需要替换的文字数量;arg3:替换的文字
- splitText(offset):从 offset 指定的位置将当前文本节点分成两个文本节点。arg1:需要分割的文本下标
- substringData(offset, count):提取从 offset 指定的位置开始到 offset+count 为止处的字符串。arg1:字符串开始的下标;arg2:需要提取的文字总数
// TODO:代码示例12
- 创建文本节点
- createTextNode(text):创建内容为text的文本节点。arg1:需要创建的内容
// TODO:代码示例13
- 规范化文本节点
- 在Noede类型的描述中,有一个normalize方法,作用是处理文档树中的文本节点。在同一节点下,重复追加文本节点时,就用的到这个方法。
// TODO:代码示例14
- 分割文本节点
- 有了规范化文本节点,那么就有相反的分割文本节点,对应的方法就是splitText
// TODO:代码示例15
五.DocumentFragment类型
- 此类型可以当作临时存储DOM元素的“仓库”来使用
- 因为DOM的渲染是很占用时间和资源的。所以在修改DOM节点的时候,最好少做修改。此时就可以用到DocumentFragment类型来临时存储DOM节点。
- 一旦DocumentFragment被添加进网页中,DocumentFragment中的内容就会被移除
// TODO:代码示例16
DOM操作技术
一.动态脚本
- 动态脚本的宗旨,是在HTML加载的时候,不加载脚本。等到某一时间,才来动态加载JS
// TODO:代码示例17
二.动态样式
- 动态样式的宗旨,是在HTML加载的时候,不加载脚本。等到某一时间,才来动态加载JS
// TODO:代码示例18
三.使用NodeList
- NodeList是DOM中的重中之重,理解 NodeList 及其“近亲” NamedNodeMap 和 HTMLCollection,是从整体上透彻理解 DOM 的关键所在。这三个集合都是“动态的”;换句话说,每当文档结构发生变化时,它们都会得到更新。因此,它们始终都会保存着最新、最准确的信息。从本质上说,所有 NodeList 对象都是在访问 DOM 文档时实时运行的查询。
// TODO:代码示例19
DOM扩展
一.选择符API
支持Selectors API Level 1的浏览器有 IE 8+、 Firefox 3.5+、 Safari 3.1+、 Chrome 和 Opera 10+ 。
- querySelector():接收一个 CSS 选择符,返回与该模式匹配的第一个元素,如果没有找到匹配的元素,返回 null。
// TODO:代码示例20
- querySelectorAll():接收的参数与 querySelector()方法一样,都是一个 CSS 选择符,但返回的是所有匹配的元素而不仅仅是一个元素。这个方法返回的是一个 NodeList 的实例。
// TODO:代码示例21
二.元素遍历
使用ChildNodes提供的方法获取节点时,会遇到子节点中存在#text类型的节点的问题,所以出现了Element Traversal规定,该规定返回的是不包含#text类型的节点
- childElementCount:返回子元素(不包括文本节点和注释)的个数。
- firstElementChild:指向第一个子元素; firstChild 的元素版。
- lastElementChild:指向最后一个子元素; lastChild 的元素版。
- previeousElementSibling:指向前一个同辈元素; previousSibling 的元素版。
- nextElementSibling:指向后一个同辈元素; nextSibling 的元素版。
// TODO:代码示例22
三.与类相关的扩展(HTML5)
- getElementsByClassName:接收一个参数,即一个包含一或多个类名的字符串,返回带有指定类的所有元素的 NodeList。传入多个类名时,类名的先后顺序不重要。arg1:names 是一个字符串,表示用于匹配的 class 名称列表; class 名称通过空格分隔
// TODO:代码示例23
- classList属性:所有元素都有classList 属性。 这个 classList 属性是新集合类型 DOMTokenList 的实例。 包含以下方法:
- add(className):为元素添加className
- contains(className):判断元素是否存在classclassName
- remove(className):移除元素的className
- toggle(className):若元素有className,则移除;若元素没有className,则添加
// TODO:代码示例24
四.自定义数据类型(HTML5)
- 为元素添加非标准的属性时,需要添加前缀 “data- ”
- 添加了自定义属性之后,可以通过元素的 dataset 属性来访问自定义属性的值。 dataset 属性的值是 DOMStringMap的一个实例,也就是一个名值对儿的映射。
// TODO:代码示例25
五.插入标记(HTML5)
- innerHTML属性:获取或设置HTML节点(不包括元素本身)
// TODO:代码示例26
- outerHTML属性:获取或设置HTML节点(包括元素本身)
// TODO:代码示例27
- insertAdjeventHTML(insertPosition:String,htmlText:String)方法:插入HTML文本到执行位置。
- insertPosition中可能出现的值:
- "beforebegin",在当前元素之前插入一个紧邻的同辈元素;
- "afterbegin",在当前元素之下插入一个新的子元素或在第一个子元素之前再插入新的子元素;
- "beforeend",在当前元素之下插入一个新的子元素或在最后一个子元素之后再插入新的子元素;
- "afterend",在当前元素之后插入一个紧邻的同辈元素。
// TODO:代码示例28
六.ScrollIntoView()
- 该方法是让元素置于浏览器可见的位置
// TODO:代码示例29
七.children属性
- 使用childsNode属性时,会将#text类型的节点也返回。
- 我们可以使用元素遍历(Element Tranversal)来过滤掉#text类型的节点。
- 但是更方便的,是用children属性,此属性会直接返回有元素的节点,即nodeType等于2的节点。
// TODO:代码示例3
八.contains()方法
- 检测节点是否存在于元素中
// TODO:代码示例31
九.innerText
- 获取或设置元素节点中的#text(不包括元素本身)
// TODO:代码示例32
十.outerText
- 获取或设置元素节点中的#text(包括元素本身)
// TODO:代码示例33
DOM2与DOM3
一.样式
- js可以访问style中的属性,是如果遇到“-”分割的属性,则在js中以驼峰命名法来解决,如:
- background-image:style.backgroundImage
- color:style.color
- font-family:style.fontFamily
- float:cssFloat(Firefox、 Safari、 Opera 和 Chrome)或者styleFloat(IE)
// TODO:代码示例34
- 计算的样式,通过getComputedStyle()方法获得元素中style+css的并集(IE不支持)
// TODO:代码示例35
二.元素大小
- 偏移量,此属性不包含外边距,通过以下4个属性可以取得元素的偏移量
- offsetHeight:元素在垂直方向上占用的空间大小,以像素计。包括元素的高度、(可见的)水平滚动条的高度、上边框高度和下边框高度。
- offsetTop:元素的上外边框至包含元素的上内边框之间的像素距离
- offsetWidth:元素在水平方向上占用的空间大小,以像素计。包括元素的宽度、(可见的)垂直滚动条的宽度、左边框宽度和右边框宽度。
- offsetLeft:元素的左外边框至包含元素的左内边框之间的像素距离。
// TODO:代码示例36
- 客户区大小
- 客户区大小,指的是元素内容及其内边距所占据的空间大小
- clientWidth:元素内容区宽度加上左右内边距宽度
- clientHeight:元素内容区高度加上上下内边距高度
// TODO:代码示例37
- 滚动大小
- 滚动大小,指的是包含滚动内容的元素的大小
- scrollHeight:在没有滚动条的情况下,元素内容的总高度。
- scrollWidth:在没有滚动条的情况下,元素内容的总宽度。
- scrollLeft:被隐藏在内容区域左侧的像素数。通过设置这个属性可以改变元素的滚动位置。
- scrollTop:被隐藏在内容区域上方的像素数。通过设置这个属性可以改变元素的滚动位置。
// TODO:代码示例38
- 在不包含滚动条的页面中,scrollWidth/scrollHeight和clientWidth/clientHeight这两对属性,在不同的浏览器中,有不同的表现:
- Firefox 中这两组属性始终都是相等的,但大小代表的是文档内容区域的实际尺寸,而非视口的尺寸
- Opera、 Safari 3.1 及更高版本、 Chrome 中的这两组属性是有差别的,其中 scrollWidth 和scrollHeight 等于视口大小,而 clientWidth 和 clientHeight 等于文档内容区域的大小
- IE(在标准模式)中的这两组属性不相等,其中 scrollWidth 和 scrollHeight 等于文档内容区域的大小,而 clientWidth 和 clientHeight 等于视口大小
三.遍历(IE不支持)
- NodeIterator
- 使用ducoment.createNodeIterator(root,whatToShow,filter,entityReferenceExpansion)方法创建实例
- 参数如下:
- root:想要作为搜索起点的树中的节点
- whatToShow:表示要访问哪些节点的数字代码
- filter:是一个 NodeFilter 对象,或者一个表示应该接受还是拒绝某种特定节点的函数
- entityReferenceExpansion:布尔值,表示是否要扩展实体引用。这个参数在 HTML 页面中没有用,因为其中的实体引用不能扩展
- whatToShow 参数是一个位掩码,通过应用一或多个过滤器(filter)来确定要访问哪些节点。这个参数的值以常量形式在 NodeFilter 类型中定义,如下所示
- NodeFilter.SHOW_ALL:显示所有类型的节点。
- NodeFilter.SHOW_ELEMENT:显示元素节点。
- NodeFilter.SHOW_ATTRIBUTE:显示特性节点。由于 DOM 结构原因,实际上不能使用这个值。
- NodeFilter.SHOW_TEXT:显示文本节点。
- NodeFilter.SHOW_CDATA_SECTION:显示 CDATA 节点。对 HTML 页面没有用。
- NodeFilter.SHOW_ENTITY_REFERENCE:显示实体引用节点。对 HTML 页面没有用。
- NodeFilter.SHOW_ENTITYE:显示实体节点。对 HTML 页面没有用。
- NodeFilter.SHOW_PROCESSING_INSTRUCTION:显示处理指令节点。对 HTML 页面没有用。
- NodeFilter.SHOW_COMMENT:显示注释节点。
- NodeFilter.SHOW_DOCUMENT:显示文档节点。
- NodeFilter.SHOW_DOCUMENT_TYPE:显示文档类型节点。
- NodeFilter.SHOW_DOCUMENT_FRAGMENT:显示文档片段节点。对 HTML 页面没有用。
- NodeFilter.SHOW_NOTATION:显示符号节点。对 HTML 页面没有用。
- filter可选参数:
- NodeFilter.FILTER_ACCEPT:表示返回遍历的节点
- NodeFilter.FILTER_SKIP:表示不返回遍历的节点
- 主要方法:
- nextNode:下一个节点
- previousNode:上一个节点
// TODO:代码示例39
- TreeWalker
- 使用document.createTreeWalker(root,whatToShow,filter,entityReferenceExpansion)方法创建实例,参数与createNodeIterator一致,但filter有所不同,具体如下:
- 除了 NodeFilter.FILTER_ACCEPT 和 NodeFilter.FILTER_SKIP 之外,还可以使用 NodeFilter.FILTER_REJECT。
- 和NodeIterator方法类似,除了包括 nextNode()和 previousNode()在内的相同的功能之外,这个类型还提供了下列用于在不同方向上遍历 DOM 结构的方法
- parentNode():遍历到当前节点的父节点;
- firstChild():遍历到当前节点的第一个子节点;
- lastChild():遍历到当前节点的最后一个子节点;
- nextSibling():遍历到当前节点的下一个同辈节点;
- previousSibling():遍历到当前节点的上一个同辈节点。
// TODO:代码示例40