JS学习笔记(十二)DOM
文章目录
JS学习笔记(十二)DOM一、DOM1.1 Document类型1.2 DOM树1.3 获取文档子节点 body 和 html(一)获取body(二)获取html 1.4 文档信息1.5 获取元素1.5.1 根据ID获取1.5.2 根据标签名获取1.5.3 HTML5新增的获取方式 1.6 特殊集合1.7 文档写入 二、节点2.1 Node类型2.1.1 nodeName 和 nodeValue 2.2 节点关系2.3 节点操作2.3.1 父节点的操作2.3.2 子节点的操作基本操作第一个子元素和最后一个子元素的获取 2.3.3 兄弟节点2.3.4 创建节点2.3.5 添加节点2.3.6 删除节点2.3.7 复制节点 2.4 Element类型 (元素)2.4.1 获取属性值2.4.2 设置属性值2.4.3 移除属性2.4.4 自定义属性1. 设置H5自定义属性2. 获取H5自定义属性 2.4.5 attribute 属性2.4.6 表单属性设置2.4.7 修改样式 2.5 Text类型2.5.1 创建文本节点2.5.2 规范化文本节点2.5.3 拆分文本节点 三、 DOM编程3.1 NodeList 四、MutationObserver接口4.1 基本用法1. observer()2. 回调与MutationRecord3. disconnect()4. 复用MutationObserver5. 重用MutationObserver 4.2 MutationObserverInit与观察范围4.3 异步回调与记录队列1. 记录队列2. takeRecords() 五、HTML55.1 CSS类扩展5.1.1 getElementByClassName()5.1.2 ClassList 属性1. 朴素的操作(不建议使用)2. 进阶的操作(建议使用) 5.2 焦点管理5.2.1 document.activeElement5.2.2 document.hasFocus 5.3 HTMLDocument 扩展1. readyState 属性2. compatMode 属性3. head 属性 5.5 自定义数据属性5.6 插入标记1. innerHTML 属性三种动态创建元素的区别 2. outerHTML 属性3. insertAdjcentHTML()与insertAdjacentText() 5.7 scrollIntoView() 六、专有扩展6.1 children属性6.2 contains()6.3 插入标记1. innerTextInnerText 和 InnerHtml的不同 2. outerText 七、DOM2 和 DOM37.1 DOM的演进7.1.1 XML命名空间1. Node 的变化2. Document的变化3. Element的变化 7.1.2 其他变化1. DocumentType的变化2. Document的变化3. Node 的变化:4. 内嵌窗格的变化 7.2 样式7.2.1 存取元素样式1. DOM样式属性和方法2. 计算样式 7.2.2 操作样式表7.2.3 元素尺寸1. 偏移尺寸style 和 offset 的区别 2. 客户端尺寸3. 滚动尺寸4. 三大尺寸总结5. 确定元素尺寸 7.3 遍历7.3.1 NodeIteratornextNode()和 previousNode() 7.3.2 TreeWalker7.3.3 元素遍历 7.4 DOM范围7.5 选择7.5.1 简单选择7.5.2 复杂选择 八、DOM操作总结(一)创建(二)增(三)删(四)改(五)查(六)属性操作(七)事件操作一、DOM
1.1 Document类型
Document类型表示 JS 文档中表示文档节点的类型,Document节点的特点:
nodeType等于9nodeName值为“#document”nodeValue值为 nullparentNode值为nullownerDocument值为null
1.2 DOM树
文档:一个页面就是一个文档,DOM中使用document表示元素:页面中所有的标签都是元素,DOM中使用element表示节点:网页中的**所有内容 **都是节点(标签、属性、文本、注释等),DOM中使用node表示注意:DOM把以上内容都看作对象
1.3 获取文档子节点 body 和 html
(一)获取body
document.body
(二)获取html
document.documentElement
let html = document.documentElement;console.log(html === document.childNodes[0]); //trueconsole.log(html === documentfirstChild); //true
1.4 文档信息
提供浏览器所加载的网页信息
属性有:title、URL、domain、referrer
URL:地址栏中的URLdomain:包含页面的域名referrer:包含链接到当前页面的那个页面的URL
1.5 获取元素
获取元素的方式:
根据ID获取根据标签名获取通过HTML5新增的方法获取特殊元素获取
1.5.1 根据ID获取
通过getElementsById()获取
1.5.2 根据标签名获取
通过getElementsByTagName()获取,返回一个包含零个或多个元素的NodeList
获得文档内所有元素:
let allElement = document.getElementByTagName("*");
1.5.3 HTML5新增的获取方式
getElementsByClassNamedocument.getElementsByClassName('类名');
querySelector 和 querySelectorAll
document.querySelector('选择器'); //根据指定的选择器返回第一个元素对象document.querySelectorAll('选择器');//根据指定的选择器返回所有元素对象
matches()
若元素匹配该选择符则返回true,否则返回false
if (document.body.matches("body.page1")) {// true}
1.6 特殊集合
document.anchors:包含文档中所有带name属性的<a>
document.forms:包含文档中所有form元素document.images:包含文档中所有img元素document.links:包含文档中所有带href属性的的元素1.7 文档写入
向网页输入流写入内容:write()、writeln()、open()、close()。
write()就简单的写入文本,writeln()会在字符串末尾追加一个换行符。write()和 writeln()经常用于动态包含外部资源
二、节点
节点至少拥有nodeType、nodeName 和 nodeValue属性
2.1 Node类型
每个节点都有nodeType属性,表示该节点的类型,节点类型由定义再Node类型上的12个数值常量表示:
Node.ELEMENT_NODE(1) 元素节点Node.ATTRIBUTE_NODE(2) 属性节点Node.TEXT_NODE(3) 文本节点(包含文字、空格、换行等)Node.CDATA_SECTION_NODE(4)Node.ENTITY_REFERENCE_NODE(5)Node.ENTITY_NODE(6)Node.PROCESSING_INSTRUCTION_NODE(7)MENT_NODE(8)Node.DOCUMENT_NODE(9)Node.DOCUMENT_TYPE_NODE(10)Node.DOCUMENT_FRAGMENT_NODE(11)Node.NOTATION_NODE(12)
2.1.1 nodeName 和 nodeValue
nodeName 和 nodeValue保存着有关节点的信息。这两个属性的值完全取决于节点的类型,在使用之前最好先检测节点类型
2.2 节点关系
每个节点都有childNodes属性,其中包含一个NodeList的实例。ownerDocument 属性是一个指向代表整个文档的文档节点的指针。是所有节点都共享的关系
2.3 节点操作
2.3.1 父节点的操作
孩子节点对象.parentNode
2.3.2 子节点的操作
基本操作
1.parentNode.childNodes
返回包含指定节点的子节点集合,返回值里包含了所有的子节点,包括元素节点,文本节点等,若只想获得里面的元素节点还需要进一步处理,所以一般不使用childNodes
2.parentNode.children
parentNode.children是只读属性,返回所有的子元素节点,只返回子元素节点,其他的不返回。
第一个子元素和最后一个子元素的获取
3..parentNode.firstChild
4.parentNode.lastChild
以上两种方法包括所有的节点
5.parentNode.firstElementChild
只返回第一个子元素节点,找不到则返回null
6.parentNode.lastElementChild
firstElementChild 和 lastElementChild有兼容性问题。
更好的方案(实际开发的写法)
既不会有兼容性问题又可以返回第一个子元素
parentNode.children[0]
2.3.3 兄弟节点
1.node.nextSibling
返回当前元素的下一个兄弟节点,包括所有节点
2.node.previousSibling
返回当前元素的上一个兄弟节点,包括所有节点
3.node.nextElementSibling
返回当前元素的下一个兄弟元素节点
4.node.previousElementSibling
同样这两个方法有兼容性问题
解决方案:
自己封装一个兼容性函数
function getNextElementSibling(element) {var el = element;while (el = el.nextSibling) {if (el.nodeType === 1) {return el;}}return null;}
2.3.4 创建节点
document.createElement('tagName')
创建的元素原先不存在,是根据要求动态生成的,所以也称动态创建元素节点
2.3.5 添加节点
1.node.appenChild(child)
将一个节点添加到指定父节点的子节点的列表末尾
如果把文档中已经存在的节点传给appendChild(),则这个节点会从之前的位置被转移到新位置。即若调用appendChild()传入父元素的第一个节点,则这个节点会成为父元素的最后一个节点
//假设someNode有多个节点let returnedNode = someNode.appendChild(someNode.firstChild);alert(returnedNode == someNode.firstChild);//falsealert(returnedNode == lastChild);//true
2.node.insertBefore(child,指定元素)
将一个节点添加到指定父节点的指定子节点前面
2.3.6 删除节点
node.removeChild(child)
从DOM中删除一个子节点,返回删除的节点
2.3.7 复制节点
node.cloneNode()
返回调用该方法的节点的一个副本,也称克隆节点/拷贝节点
注意:
若括号里为空或者false,则是浅拷贝,及只复制节点本身,不克隆里面的子节点若括号参数为true,则是深度拷贝,会复制节点本身及里面的所有子节点
2.4 Element类型 (元素)
Element 类型的节点特征:
nodeType 等于1nodeName 值为元素的标签名nodeValue 等于 nullparentNode 值为 Document 或 Element对象子节点可以是Element、Text、Comment、ProcessingInstruction、CDATASection、EntityReference类型
可以通过nodeName或tagName属性来获取元素的标签名,但注意,div.tagName 返回的是“DIV”而不是“div”,HTML中,元素标签名始终以全大写表示。
2.4.1 获取属性值
element.属性element.getAttribute(‘属性’);区别:
element.属性 :获取内置属性值(元素自带的属性)element.getAttribute(‘属性’):主要获取自定义属性
2.4.2 设置属性值
element.属性 = ‘值’设置内置属性值element.setAttribute(‘属性’, ‘值’);主要针对自定义属性div.id = 'test';div.className = 'navs';div.setAttribute('index',2);div.setAttribute('class','footer'); //这里写的是class 不是className
注意:class在两种方法中的写法
2.4.3 移除属性
removeAttribute(属性);
2.4.4 自定义属性
目的:为了保存并使用数据,有些数据可以保存到页面中而不用保存到数据库中。
自定义属性通过getAttribute(‘属性’)获取
1. 设置H5自定义属性
H5规定自定义属性以 **data- 开头 **做属性名并赋值
<div data-index= '1'></div>//或使用JS设置element.setAttibute("data-index",2);
<div getTime="20" data-index="2" data-list-name="niki"></div><script>var div = document.querySelector("div");console.log(div.dataset.listName);console.log(div.dataset["listName"]);</script>
dataset 是一个集合,里面存放了所有以data开头的自定义属性若自定义属性里面有多个- 链接的单词,我们获取的时候采取驼峰命名法
2. 获取H5自定义属性
兼容性获取:element.getAttribute(‘data-index’);H5新增element.dataset.index或element.dataset[‘index’]IE11 才开始支持2.4.5 attribute 属性
Element是唯一一个使用attribute属性的DOM 节点类型。attribute 属性包含一个NamedNodeMap实例,其包含以下方法:
getNamedItem(name):返回nodeName属性等于name的节点removeNamedItem(name):删除nodeName属性等于name的节点setNamedItem(node):向列表中添加node节点,以其nodeName为索引item(pos):返回索引位置pos出的节点
attributes属性中的每个节点的nodeName是对应属性的名字,nodeValue 是属性的值,如要去的元素id属性的值
let id = element.attributes.getNamedItem("id").nodeValue;let id = element.attributes.getNamedItem["id"].nodeValue;
2.4.6 表单属性设置
案例:模仿京东显示隐藏密码
核心思路:点击眼睛按钮,把密码框类型改为文本框就可以看见里面的密码一个按钮两个状态,点击一次,切换为文本框,继续点击一次切换为密码框算法:利用一个flag遍历,判断flag的值,如果时1就切换为文本框,flag设置为0,如果时0就切换为密码框,flag设置为1
let eye = document.getElementById("eye");let pwd = document.getElementById("pwd");// 注册事件处理程序let flag = 0;eye.addEventListener("click", () => {// 点击一次后,flag一定变化if(flag == 0) {pwd.type = 'text';eye.src = 'images/open.png';flag = 1;} else {pwd.type = 'password';eye.src = 'images/close.png';flag = 0;}})
2.4.7 修改样式
1.element.style 行内样式操作2.element.className 类名样式操作
注意:
JS 里面的样式采取驼峰命名法,如:fontSizeJS 修改 style 样式操作,产生的是行内样式,css 权重比较高如果样式较多,可以采取操作类名方式更改元素样式class因为是个保留字,因此使用className来操作元素类名属性className 会直接更改元素的类名,会覆盖原来的类名
2.5 Text类型
Text类型的节点的特征:
nodeType 等于3nodeName 值为“#text”;nodeValue 值为节点中包含的文本parentNode 值为Element对象
Text节点中包含的文本可以通过nodeValue属性访问,也可通过data属性访问,这两个属性包含相同的值
2.5.1 创建文本节点
document.createTextNode()
2.5.2 规范化文本节点
normalize()
用来合并相邻的文本节点。
let element = document.createElement("div");element.className="mes";let textNode = document.createTextNode("hello world!");element.appendChild(textNode);let anotherTextNode = document.createTextNode("niki");element.append(anotherTextNode);document.body.appendChild(element);alert(element.childNodes.length); //2element.normalize();alert(element.childNodes.length);//1alert(element.firstChild.nodeValue)//"hello world!niki"
2.5.3 拆分文本节点
splitText()
该方法在指定的偏移位置拆分nodeValue,将一个文本节点拆分为两个文本节点
三、 DOM编程
3.1 NodeList
NodeList 就是基于DOM文档的实时查询,以下行为会导致无穷循环:
let divs = document.getElementsByTagName("div");for (let i = 0; i < divs.length; ++i) {let div = document.createElement("div");document.body.appendChild(div)}
解决方案:
let divs = document.getElementsByTagName("div");for (let i = 0, len = divs.length; i < len; ++i) {let div = document.createElement("div");document.body.appendChild(div)}
四、MutationObserver接口
MutationObserver接口可以在DOM被修改时异步执行回调。使用MutationObserver可以观察整个文档、DOM树的一部分或某个元素。此外还可以观察元素属性、子节点、文本或前三者任意组合的变化
4.1 基本用法
MutationObserver 的实例要通过调用MutationObserver构造函数并传入一个回调函数来创建
let observer = new MutationObserver(() => console.log("DOM is mutataed!"));
1. observer()
新创建的MutationObserver 实例不会关联DOM的任何部分,要用observer与DOM关联。observer()接收两个必须的参数:要观察其变化的DOM节点,以及一个MutationObserver 对象(用于控制观察哪些方面的变化,是一个键值对形式配置选项的字典)
let observer = new MutationObserver(() => console.log("<body> attributes changed!"))observer.observe(document.body,{attributes:true});document.body.className ='foo';console.log('changed body class');//changed body class//<body> attributes changed!
回调中的console后执行,表明回调并非与实际的DOM变化同步进行。
2. 回调与MutationRecord
每个回调都会收到一个按顺序入队的MutationRecord实例的数组。MutationRecord 实例包含的信息包括发生了什么变化,以及DOM的哪一部分收到了影响。,传给回调函数的第二个参数是观察变化的MutationObserver实例
let observer = new MutationObserver((mutationRecords) => console.log(mutationRecord));
3. disconnect()
默认情况,只要被观察的元素不被垃圾回收,MutationObserver的回调就会响应DOM变化事件,从而被执行。要提前终止执行回调,可以用disconnect(),该方法不仅会停止此后变化事件的回调,也会抛弃已经加入任务队列要异步执行的回调:
let observer = new MutationObserver(() => console.log("<body> attributes changed!"))observer.observe(document.body,{attributes:true});document.body.className = 'foo';observer.disconnect();observer.body.className = 'bar';// 无日志输出
要想让已经加入任务队列的回调执行,可以使用setTimeout()让已经入列的回调执行完毕再调用disconnect()
let observer = new MutationObserver(() => console.log("<body> attributes changed!"))observer.observe(document.body,{attributes:true});document.body.className = 'foo';setTimeout(() => {observer.disconnect();observer.body.className = 'bar';},0)// <body> attributes changed!
4. 复用MutationObserver
多次调用observe(),可以服用一个MutationObserver对象观察多个不同的目标节点。此时,MutationRecord的target属性可以标识发生变化事件的目标节点
let observer = new MutationObserver((mutationRecords) => console.log(mutationRecords.map((x) => x.target)));let childA = document.createElement("div");let childB = document.createElement("span");document.body.appendChild(childA);document.body.appendChild(childB);// 观察两个节点observer.observe(childA, {attributes:true});observer.observe(childB, {attributes:true});// 修改两个节点的属性childA.setAttribute("foo","bar");childB.setAttribute("foo","bar");
5. 重用MutationObserver
调用disconnect()并不会结束MutationObserver的生命,还可以重新使用这个观察者,再将他关联到新的目标节点
let observer = new MutationObserver(() => console.log("<body> attributes changed!"))observer.observe(document.body,{attributes:true});document.body.setAttribute("foo","bar") // 触发事件setTimeout(() => {observer.disconnect();document.body.setAttribute("bar","baz"); // 不会触发事件},0);setTimeout(() => {observer.observe(document.body,{attributes:true});document.body.setAttribute("baz","qux"); // 触发事件},0);
4.2 MutationObserverInit与观察范围
MutationObserverInit 对象用于控制对目标节点的观察范围,观察的事情包括属性变化、文本变化和子节点变化
4.3 异步回调与记录队列
1. 记录队列
每次MutationRecord 被添加到MutationObserver的记录队列时,仅当之前没有已排期的微任务回调时,才会将观察者注册的回调作为微任务调度到任务队列上,这样可以保证记录队列的内容不会被回调处理两次
2. takeRecords()
takeRecords()可以清空记录队列,去除并返回其中所有的MutationRecord实例
五、HTML5
5.1 CSS类扩展
5.1.1 getElementByClassName()
见1.5.3
5.1.2 ClassList 属性
1. 朴素的操作(不建议使用)
可通过className 实现类名的添加、删除和替换。className也是一个字符串,所以每次操作后都要重新设置这个值才能生效
<div class="bd user disable"></div>
该div有3个类名。要想删除其中一个,就得先把className拆开,删除不想要的那个,再把包含剩余类的字符串设置回去:
// 要删除的类let targetClass = 'user';// 把类名拆成数组let classNames = div.className.split(/\s+/);// 找到要删除类名的索引let idx = classNames.indexOf(targetClass);// 若有就删除if(idx>-1) {classNames.splice(idx,1);}// 重新设置类名div.className = classNames.join(" ");
2. 进阶的操作(建议使用)
className 是一个新的集合类型DOMToken的实例,有length属性,还有以下方法:
add(value):相类名列表中添加指定的类名(字符串)value,若该值已经存在,则什么也不做contains(value):返回布尔值,表示给定的value是否存在remove(value):从类名列表中删除指定的字符串值valuetoggle(value):若类名列表中已经存在指定的value,则删除,若不存在则添加
5.2 焦点管理
5.2.1 document.activeElement
document.activeElement 始终包含当前拥有焦点的DOM元素。页面加载时,可以通过用户输入(按Tab键或代码中使用focus())让某个元素自动获得焦点
默认情况下,document.activeElement 在页面刚加载完之后会设置为document.body.而在也米娜完全加载之前,document.activeElement 值为null
5.2.2 document.hasFocus
返回布尔值,表示文档是否拥有焦点
5.3 HTMLDocument 扩展
1. readyState 属性
document.readyState属性的两个值:
loading:表示文档正在加载complete:表示文档加载完成
2. compatMode 属性
指示浏览器当前处于什么渲染模式。标准模式下,patMode的值是”CSS1Compat“,混则模式下,patMode 的值是”BackCompat“
3. head 属性
HTML5新增document.head 属性,指向<head>
5.5 自定义数据属性
见2.4.4
5.6 插入标记
1. innerHTML 属性
读取innerHTML 时,会返回元素所有后代的HTML字符串,包括元素、注释和文本节点。(包括html标签,同时保留空格和换行)
写入innerHTML时,则会根据提供的字符串值以新的DOM子树代替元素中原来包含的所有节点。如果赋值不包含任何HTML标签,则直接生成一个文本节点
实际返回的文本内容会因浏览器而不同,IE 和 Opera 会把所有的元素百年前转换为大写,而 Safari、Chrome 和Firefox 会按照源代码的格式返回
尽管innerHTML不会执行自己创建的<script>
,但仍向恶意用户暴露了很大的攻击面,如果页面中要使用用户提供的信息,建议不要使用innerHTML,以防XSS攻击。
三种动态创建元素的区别
document.write()element.innerHTMLdocument.createElement()区别:
document.write() :是将内容直接写入页面的内容流。但是当文档流执行完毕,它会导致页面全部重绘
innerHTML :是将内容写入某个DOM节点,不会导致页面全部重绘。创建多个元素效率更高,不要拼接字符串,采取数组形式拼接,结构稍微复杂
function foo(){var d1 = +new Date();var arrry = [];for(var i=0;i<1000;i++) {arrry.push('<div style="width:100px;height:2px;border:1px solid blue;"></div>')}document.body.innerHTML = arrry.join('');var d2 = +new Date();console.log(d2-d1);}foo();
document.createElement():创建多个元素效率稍微低一点点,但结构更清晰
function foo(){var d1 = +new Date();var arrry = [];for(var i=0;i<1000;i++) {var div = document.createElement('div');div.style.width = '100px';div.style.height = '2px';div.style.border = '1px solid red';document.body.appendChild(div);}var d2 = +new Date();console.log(d2-d1);}foo();
2. outerHTML 属性
读取outerHTML 属性时,会返回调用它的元素(其本身及所有后代元素)的HTML字符串。
写入outerHTML 时,调用他的元素会被传入HTML字符串经过解释后生成的DOM子数取代
3. insertAdjcentHTML()与insertAdjacentText()
这两个方法都接收两个参数:要插入标记的位置和插入的HTML或文本。
第一个参数必须为下列值中的一个(这些值不区分大小写):
”beforebegin“:插入当前元素的前面,作为前一个同胞节点”afterbegin“:插入当前元素的内部,作为新的子节点或放在第一个子节点的前面”beforeend“:插入当前元素的内部,作为新的子节点或放在最后一个子节点的后面”afterend“:插入当前元素后面,作为下一个同胞节点
第二个参数会作为HTML字符串解析(与innerHTML 和outerHTML相同)或作为纯文本解析(与innerText 和 outerHTML相同)
5.7 scrollIntoView()
可以滚动浏览器窗口或容器元素以便包含元素的元素进入视口,参数如下:
alignToTop(布尔值): true:窗口滚动后元素的顶部与视口顶部对齐false:窗口滚动后元素的底部与视口底部对齐scrollIntoViewOptions是一个选择对象 behavior:定义过渡动画,可取的值为”smooth“和”auto“,默认为”auto“block:定义垂直方向的对齐,可取”start“(默认)、”center“、”end“ 和 ”nearest“inline:定义水平方向的对齐,可取”start“、”center“、”end“ 和 ”nearest“(默认) 不传参数等同于alignToTop 为 true
六、专有扩展
指的是还未被标准化(进入HTML5),各个浏览器厂商为弥补功能缺失而为DOM添加的专有扩展
6.1 children属性
children 属性是一个HTMLCollection,只包含元素的Element类型的子节点
6.2 contains()
确定一个元素是否是另一个元素的后代,
DOM Level 3 的compareDocumentPosition()也可以确定节点间的关系。该方法会返回表示两个节点关系的位掩码
6.3 插入标记
1. innerText
对应元素中包含的所有文本内容。读取值时,innerText会按照深度优先顺序将子数中所有的文本的值拼接起来。写入值时,innerText会移除元素的所有后代并插入一个包含该值的文本节点。(去除html标签,同时空格和换行也会去掉)
div.innerText = 'Hello world!';<div id='content'>Hello world!</div>
设置innerText会移除元素之前的所有后代节点,完全改变DOM子树设置innerText会编码出现在字符串中的HTML语法字符(大小于号、引号及和号)通过将innerText设置等于innerText,可以去除所有的HTML标签而只剩下文本
InnerText 和 InnerHtml的不同
innerText:
不识别 html 标签可获取元素里面的内容会去除空格和换行
innerHtml:
识别 html 标签可获取元素里面的内容保留空格和换行
2. outerText
作用范围包含调用它的节点
读取文本时,outerText 与 innerText 实际返回同样的内容。
写入文本值时,outerText不止会移除所有的后代节点,而是会替换整个元素
七、DOM2 和 DOM3
7.1 DOM的演进
DOM2 和 DOM3 的core模块的目标:扩展DOM API,满足XML的所有需求并提供更好的错误处理和特性检测。
DOM2 core未新增任何类型,仅仅在DOM1 core 的基础上增加了一些方法和属性。
DOM 3 core则除了增强原有类型,也新增了新类型
7.1.1 XML命名空间
XML命名空间可以实现在一个格式规范的文档中混用不同的XML语言,而不必担心元素命名冲突。严格来讲,XML命名空间在XHTML中才支持,HTML并不支持。
XML命名空间是使用xmlns指定的。XHTML的命名空间是”/1999/xhtml“,应该包含在任何格式规范的XHTML页面的<html>
中:
<html xmlns="http://www//1999/xhtml" lang="en"><head><title>Document</title></head><body>hello!</body></html>
对上面的例子来说,所有元素都默认属于XHTML命名空间。可以使用xmlns给命名空间创建一个前缀,格式为:”xmlns:前缀“。
若文档中只使用一种XML语言,那命名空间前缀其实是多余的,只有一个文档混合使用多种XML语言时才有必要。如下面的文档就使用了XHTML和SVG两种语言:
<html xmlns="http://www//1999/xhtml" lang="en"><head><title>Document</title></head><body><svg xmlns="http://www.w3/org/2000/svg" version="1.1"><rect x="0" y="0" width="100" style="fill: red;"/></svg></body></html>
1. Node 的变化
DOM2中,Node类型包含以下特定于命名空间的属性:
localName:不包含命名空间前缀的节点名namespcaeURI:节点的命名空间URL,未指定则为nullprefix:命名空间前缀,未指定则为null
DOM3增加了如下的方法:
isDefaultNamespace(namespaceURI):返回布尔值,表示namespaceURI是否为节点的默认命名空间lookupNamespaceURI(prefix):返回给定prefix的命名空间URIlookupPrefix(namespaceURI):返回给定namespURI的前缀
2. Document的变化
DOM2 在document类型上新增了如下的命名空间特定方法:
createElementNS(namespaceURI,tagName):以给定的标签名tagName创建指定命名空间namespaceURI的一个新元素createAttibuteNS(namespaceURI,attibuteName):以给定的属性名attibuteName创建指定命名空间namespaceURI的一个新属性。getElementByTagNameNS(namespaceURI,attibuteName):返回指定命名空间namespaceURI中所有标签名为tagName的元素的NodeList
3. Element的变化
getAttributeNSgetAttributeNodeNSgetElementByTagNameNShasAttributeNSremoveAttributeNSsetAttributeNSsetAttributeNodeNS7.1.2 其他变化
1. DocumentType的变化
DocumentType 新增了3个属性:publicId、systemId和internalSubset
2. Document的变化
importNode:从其他文档获取一个节点并导入新文档。createDocumentType():创建DocumentType类型的节点createDocument():创建新文档createHTMLDocument():创建完整的HTML文档3. Node 的变化:
DOM3 新增了两个用于比较节点的方法:isSameNode()和isEqualNode():
isEqualNode():节点相同,即引用同一个对象isSameNode():节点相等,即节点类型相同,拥有相等的属性,且attributes和childNodes也相等
DOM3 也增加了给DOM节点附加额外数据的方法:setUserData()。该方法接收3个参数:键、值、处理函数。处理函数会在包含数据的节点被赋值、删除、重命名或导入其他文档的时候执行
4. 内嵌窗格的变化
DOM2 给HTMLIFrameElement<iframe>
新增属性:contentDocument。该属性包含代表子内嵌窗格中内容的document 对象的指针。
还有个属性contentWindow,返回相应的窗格的window对象,有一个document对象
7.2 样式
三种定义样式的方法:
外部样式表(<link>
)文档样式表(<style>
)元素特定样式(style属性)
7.2.1 存取元素样式
CSS属性名使用连字符表示法,在JS中这些属性必须转换为驼峰大小写形式,(注意:float不能转换,其是JS中的保留字):
background-image -------> style.backgroundImage
1. DOM样式属性和方法
cssText:包含style属性中的css代码
length:应用给元素的CSS属性数量,跟item()一起配套迭代CSS属性
parentRule:表示CSS信息的CSSRule对象
getPropertyPriority(propertyName):若CSS属性使用了!important,则返回”important“,否则返回空字符串
getPropertyValue(propertyName):返回属性propertyName的字符串值
item(index):返回索引为index的CSS属性名
style[i] = style.item(i)
removeProperty(propertyName):删除propertyName,使用该方法删除属性意味着会应用该属性的默认样式
setProperty(propertyName,value,priority):设置CSS属性propertyName的值为value,priority是”important“空字符串
2. 计算样式
DOM2 Style 在document.defaultView上增加了getComputedStyle()。
document.defaultView.getComputedStyle(myDiv,null);
该方法接收两个参数:**要取得计算样式的元素和伪元素字符串。**若不需要查询伪元素,则第二个参数可以传null。getComputedStyle()返回一个CSSStyleDeclaration对象,包含元素的计算样式
注意:在所有浏览器中,计算样式都是只读的,不能修改getComputedStyle()返回的对象。且计算样式还包含浏览器内部样式中的信息。因此有默认值的CSS属性会出现在计算样式中
7.2.2 操作样式表
CSSStyleSheet 从 StyleSheet继承的属性:
disabled:样式表是否被禁用(可读写)
href:是<link>
包含的样式表,则返回样式表的URL
media:样式表支持的媒体类型集合
ownerNode:指向拥有当前样式表的节点,HTML中不是<link>
就是<style>
。若当前样式表通过@import被包含在另一个样式表中,则该属性值为null
parentStyleSheet:若当前样式表通过@import被包含在另一个样式表中,则该属性指向导入他的样式表
title:ownerNode的title属性
type:字符串,表示样式表的类型。CSS样式表就是”text/css“
CSSStyleSheet 还支持的属性和方法:
cssRules:当前样式表包含的样式规则的集合ownerRule:若样式表是使用@import 导入的,则指向导入规则。否则为nulldeleteRule(index):在指定位置删除cssRules中的规则insertRule(rule,index):在指定位置向cssRules中插入规则
document.styleSheet 表示文档中可用的样式表集合。这个集合的length属性保存着文档中样式表的数量,而每个样式表都可以使用中括号或item()获取
7.2.3 元素尺寸
1. 偏移尺寸
偏移尺寸包含元素在屏幕上占用的所有视觉空间。视觉空间由高度宽度,包括**所有的内边距,滚动条和边框(不八行外边距)**组成。可用于取得元素偏移尺寸的4个属性:
offsetHeight:元素在垂直方向上占用的像素尺寸,包括他的高度、水平滚动条的高度和上下边框的高度offsetLeft:元素左边框外侧距离包含元素左边框内测的像素数offsetTop:元素上边框外侧距离包含元素上边框内测的像素数offsetWidth:元素在水平方向上占用的像素尺寸offsetParent:返回作为该元素带有定位的父级元素,若父级元素没有定位则返回body
注意:
offsetLeft 和 offsetTop是相对于包含元素的返回的数值都不带单位
要确定一个元素在页面中的偏移量,可以把它的offsetLeft 和offsetTop属性分别与offsetParent的相同属性相加,一直到根元素:
function getElementLeft(element) {let actualLeft = element.offsetLeft;let current = element.offsetParent;while (current != null) {actualLeft += current.offsetLeft;current = current.offsetParent;}return actualLeft;}
style 和 offset 的区别
2. 客户端尺寸
客户端尺寸包含元素内容及其内边距所占用的空间,属性有:clientWidth 和 clientHeight。客户端尺寸实际就是元素内部的空间,因此不包含滚动条占用的空间。这两个属性常用于确认浏览器视口尺寸
3. 滚动尺寸
提供元素内容滚动距离的信息,属性有:
scrollHeight:没有滚动条出现时,元素内容的总高度scrollWidth:没有滚动条出现时,元素内容的总宽度scrollLeft:内容区左侧隐藏的像素数,设置这个属性可以改变元素的滚动位置,默认为0scrollTop:内容区顶部隐藏的像素数,设置这个属性可以改变元素的滚动位置,默认为0
4. 三大尺寸总结
主要用法:
offset系列经常用于获得元素位置offsetLeft offsetTopclient系列经常用于获取元素大小clientWidth clientHeightscroll 经常用于获取滚动距离主要页面滚动距离通过window.pageXOffset获得
5. 确定元素尺寸
浏览器在每个元素上都暴露了getBoundingClientRect(),返回一个DOMRect对象,包含6个属性:left、top、right、bottom、height和width
7.3 遍历
用于辅助顺序遍历DOM结构的两个类型,从某个起点开始执行对DOM结构的深度优先遍历:NodeIterator 和 TreeWalker
7.3.1 NodeIterator
通过document.createNodeIterator () 创建实例,接收4个参数:
root:作为遍历根节点的节点
whatToShow:数值代码,表示应该访问哪些节点,是个位掩码,通过引用一个或多个过滤器来指定访问哪些节点
filter,NodeFilter对象或函数:表示是否接收或跳过特定节点,节点的过滤器函数
NodeFilter对象只有一个方法accpectNode(),若给定节点应该访问就返回NodeFIlter.FILTER_ACCEPT,否则返回NodeFIlter.FILTER_SKIP
entityReferenceExpansion:布尔值,表示是否扩展实体引用
例子:定义只接收<p>
元素的接待你过滤器对象:
let filter = {acceptNode(node) {return node.tagName.toLowerCase() == "p"? NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_SKIP;}};//filter还可以是函数,下面的写法与上面的等价let filter = function(node){return node.tagName.toLowerCase() == "p"? NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_SKIP;}let iterator = document.createNodeIterator(root,NodeFilter.SHOW_ELEMENT,filter,false);
nextNode()和 previousNode()
NodeIterator 的主要方法,其区别:
nextNode():在DOM子树中以深度优先方式进前一步,第一次调用返回根节点。遍历到DOM树最后一个节点时,返回nullpreviousNode():在遍历中后退一步。遍历到DOM树最后一个节点时,返回遍历的根节点
例子:遍历div中所有元素
<div id="div1"><p><b>HELLO</b> WORLD!</p><ul><li>List item 1</li><li>List item 2</li><li>List item 3</li></ul></div>
let div = document.getElementById("div1");let iterator = document.createNodeIterator(div,NodeFilter.SHOW_ELEMENT,null,false);let node = iterator.nextNode();while(node!=null){console.log(node.tagName);node = iterator.nextNode();}
7.3.2 TreeWalker
TreeWalker 是 NodeIterator 的高级版,用document.createTreeWalker()创建,与NodeIterator 类似,通常可以取代NodeIterator 。
TreeWalker 的filter有三个返回值:
NodeFilter.FILTER_ACCEPTNodeFilter.FILTER_SKIP:跳过节点,访问子树中下一个节点NodeFilter.FILTER_REJECT:表示跳过该节点以及该节点的整个子树
除了nextNode()和 previousNode(),还添加了parentNode(),firstChild()、lastChild()、nextSibling()和 previousSibling()
TreeWalker 类型有一个currentNode属性,表示遍历过程中上一次返回的节点。可以通过修改该属性来影响接下来遍历的起点
7.3.3 元素遍历
DOM 元素有5个属性:
childElementCount:返回子元素数量(不包含文本节点和注释)firstElementChild:指向第一个Element类型的子元素(firstElementChild版:firstChild)lastElementChild:指向最后一个Element类型的子元素(firstElementChild版:lastChild)previousElementSibling:指向前一个Element类型的同胞元素(firstElementChild版:previousSibling)nextElementSibling:指向后一个Element类型的同胞元素(firstElementChild版:nextSibling)
firstElementChild 和 firstChild 的区别:
firstElementChild 一定返回的是元素节点firstChild返回的不一定是元素节点
例子:遍历特定元素的所有子元素
let parentElement = document.getElementById('parent');let currentChildElement = parentElement.firstElementChild;while(currentChildElement) {// 获得元素节点processChild(currentChildElement);if(currentChildElement == parentElement.lastChild) {break;}currentChildElement = currentChildElement.nextElementSibling;}
7.4 DOM范围
document.createRange(),可以创建一个DOM范围对象,这个新创建的范围对象是与创建它的文档相关联的,不能在其他文档中使用。相关的方法和属性:
startContainer:范围起点所在的节点(选区中第一个子节点的父节点)startOffset:范围起点在startContainer中的偏移量。若startContainer为文本节点、注释节点或CData区块,则startOffset指范围起点之气那跳过的字符数;否则,表示范围中第一个节点的索引。endContainer:范围终点所在的节点(选区中最后一个节点的父节点)endOffset:范围起点在startContainer中的偏移量。commonAncestorContainer:文档以startContainer和endContainer为后代的最深节点。
7.5 选择
7.5.1 简单选择
selectNode()和selectNodeContents():通过范围选择文档中某个部分。两个方法都接收一个节点作为参数,并将该节点的信息添加到调用它的范围。selectNode()选择整个节点,包括其后代节点,而selectNodeContents()只选择节点的后代。
<p id="p1"><b>hello</b> world!</p>
let range1 = document.createRange(),range2 = document.createRange(),p1 = document.getElementById("p1");range1.selectNode(p1);range2.selectNodeContents(p1);
更精细控制范围的方法:
setStartBefore(refNode)setStartAfter(refNode)setEndBefore(refNode)setEndAfter(refNode)
7.5.2 复杂选择
setStart() 和 setEnd() 。对setStart(),参照节点会成为startContainer,偏移量赋给startOffset。而setEnd()而言,参照节点会成为endContainer,偏移量会付给endOffset
八、DOM操作总结
关于DOM操作,主要是创建、增、删、改、查、属性操作、事件操作
(一)创建
document.writeinnerHTMLcreateElement(二)增
appenChildinsertBefore(三)删
removeChild(四)改
修改元素的属性:src、href、title等修改普通元素的内容:innerHTML、innerText修改表单元素:value、type、disabled等修改元素样式:style、className(五)查
DOM提供的API方法:getElementById、getElementsByTagName 古老方法 不推荐H5提供的新方法:querySelector、querySelectorAll 提倡利用节点获取元素:父(parentNode)、子(children)、兄(previousElementSibling、nextElementSibiling) 提倡(六)属性操作
主要针对于自定义属性
setAttribute:设置DOM属性值getAttibute:获取DOM属性值removeAttribute :移除属性值