JS学习笔记(十二)DOM
文章目录
一、DOM
1.1 Document类型
Document类型表示 JS 文档中表示文档节点的类型,Document节点的特点:
- nodeType等于9
- nodeName值为“#document”
- nodeValue值为 null
- parentNode值为null
- ownerDocument值为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]); //true
console.log(html === documentfirstChild); //true
1.4 文档信息
提供浏览器所加载的网页信息
属性有:title、URL、domain、referrer
- URL:地址栏中的URL
- domain:包含页面的域名
- referrer:包含链接到当前页面的那个页面的URL
1.5 获取元素
获取元素的方式:
- 根据ID获取
- 根据标签名获取
- 通过HTML5新增的方法获取
- 特殊元素获取
1.5.1 根据ID获取
通过 getElementsById() 获取
1.5.2 根据标签名获取
通过 getElementsByTagName() 获取,返回一个包含零个或多个元素的NodeList
获得文档内所有元素:
let allElement = document.getElementByTagName("*");
1.5.3 HTML5新增的获取方式
- getElementsByClassName
document.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)
- Node.COMMENT_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);//false
alert(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 等于1
- nodeName 值为元素的标签名
- nodeValue 等于 null
- parentNode 值为 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 里面的样式采取驼峰命名法,如:fontSize
- JS 修改 style 样式操作,产生的是行内样式,css 权重比较高
- 如果样式较多,可以采取操作类名方式更改元素样式
- class因为是个保留字,因此使用className来操作元素类名属性
- className 会直接更改元素的类名,会覆盖原来的类名
2.5 Text类型
Text类型的节点的特征:
- nodeType 等于3
- nodeName 值为“#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); //2
element.normalize();
alert(element.childNodes.length);//1
alert(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):从类名列表中删除指定的字符串值value
- toggle(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 属性
指示浏览器当前处于什么渲染模式。标准模式下,document.compatMode的值是”CSS1Compat“,混则模式下,document.compatMode 的值是”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.innerHTML
- document.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()也可以确定节点间的关系。该方法会返回表示两个节点关系的位掩码
掩码 | 节点关系 |
---|---|
0x1 | 断开(传入的节点不在文档中) |
0x2 | 领先(传入的节点在DOM树中位于参考节点之前) |
0x4 | 随后(传入的节点在DOM树中位于参考节点之后) |
0x8 | 包含(传入的节点是参考节点的祖先) |
0x10 | 被包含(传入的节点是参考节点的后代) |
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的命名空间是”http://www.w3.org/1999/xhtml“,应该包含在任何格式规范的XHTML页面的<html>
中:
<html xmlns="http://www/w3.org/1999/xhtml" lang="en">
<head>
<title>Document</title>
</head>
<body>
hello!
</body>
</html>
对上面的例子来说,所有元素都默认属于XHTML命名空间。可以使用xmlns给命名空间创建一个前缀,格式为:”xmlns:前缀“。
若文档中只使用一种XML语言,那命名空间前缀其实是多余的,只有一个文档混合使用多种XML语言时才有必要。如下面的文档就使用了XHTML和SVG两种语言:
<html xmlns="http://www/w3.org/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,未指定则为null
- prefix:命名空间前缀,未指定则为null
DOM3增加了如下的方法:
- isDefaultNamespace(namespaceURI):返回布尔值,表示namespaceURI是否为节点的默认命名空间
- lookupNamespaceURI(prefix):返回给定prefix的命名空间URI
- lookupPrefix(namespaceURI):返回给定namespURI的前缀
2. Document的变化
DOM2 在document类型上新增了如下的命名空间特定方法:
- createElementNS(namespaceURI,tagName):以给定的标签名tagName创建指定命名空间namespaceURI的一个新元素
- createAttibuteNS(namespaceURI,attibuteName):以给定的属性名attibuteName创建指定命名空间namespaceURI的一个新属性。
- getElementByTagNameNS(namespaceURI,attibuteName):返回指定命名空间namespaceURI中所有标签名为tagName的元素的NodeList
3. Element的变化
- getAttributeNS
- getAttributeNodeNS
- getElementByTagNameNS
- hasAttributeNS
- removeAttributeNS
- setAttributeNS
- setAttributeNodeNS
7.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 导入的,则指向导入规则。否则为null
- deleteRule(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:内容区左侧隐藏的像素数,设置这个属性可以改变元素的滚动位置,默认为0
- scrollTop:内容区顶部隐藏的像素数,设置这个属性可以改变元素的滚动位置,默认为0
4. 三大尺寸总结
三大尺寸大小对比 | 作用 |
---|---|
offsetWidth | 返回自身包括padding,内容区的宽度,边框,返回数值不带单位 |
clientWidth | 返回自身包括padding,内容区的宽度,不含边框,返回数值不带单位 |
scrollWidth | 返回自身实际宽度,不含边框,返回数值不带单位 |
主要用法:
- offset系列经常用于获得元素位置 offsetLeft offsetTop
- client系列经常用于获取元素大小 clientWidth clientHeight
- scroll 经常用于获取滚动距离
- 主要页面滚动距离通过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树最后一个节点时,返回null
- previousNode():在遍历中后退一步。遍历到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_ACCEPT
- NodeFilter.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.write
- innerHTML
- createElement
(二)增
- appenChild
- insertBefore
(三)删
- 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 :移除属性值
(七)事件操作
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/150429.html