DOM相关知识点
此文目的
本文主要是整理DOM相关的知识点,方便日后的查看和各位的查缺补漏。所以重在整理,并不会展开。目前还在持续整理中,打算在16日左右完结。
Node属性和方法
nodeType
Node.nodeType// 1为元素节点,2为属性节点,3为文本节点
nodeName与tagName
elementName = Element.tagName;//返回为大写标签名,如DIV,IMG。一般用tagName即可。 * Attr ------ Attr.name 属性名 * Element ------ Element.tagName 标签名 * Text ------ nodeName为‘#text’,tagName为undefined
nodeValue
* Text ------ 文本内容 * Element ------ null
//返回的是NamedNodeMap,不是ARRY。NamedNodeMap是字符串形式的名/值对。无序,且可自动更新。 //获取参照mdn var attr = element.attributes; ```
- firstChild:表示某一节点的第一个节点
- lastChild:表示某一节点的最后一个子节点
- childNodes:表示所在节点的所有子节点
- parentNode:表示所在节点的父节点
- nextSibling:紧挨着当前节点的下一个节点
- previousSibling:紧挨着当前节点的上一个节点
-方法:
Node.hasChildNodes() // 如果包含子节点就返回true
DOM 创建
DOM节点(Node)通常对应于一个标签,一个文本,或者一个HTML属性。DOM节点有一个nodeType属性用来表示当前元素的类型,它是一个整数:
- Element,元素
- Attribute,属性
- Text,文本
DOM节点创建最常用的便是document.createElement和document.createTextNode方法:
var el1 = document.createElement('div'); var node = document.createTextNode('hello world!');
DOM 查询
getElementsByTagName等返回的实时的元素集合不需要预先获得所有的元素信息,而.querySelectorAll()会立刻收集所有的信息到一个静态的列表里,因而会[降低性能][2]。 可以用instanceof操作符检查节点的原型链: ``` myElement.firstChild.nodeType instanceof Text ```
元素查询的API返回的的结果是DOM节点或者DOM节点的列表。
//类似于css选择器: 选择classA下的classb元素 document.querySelector(".classA .classB"); // 返回选择的第一个元素.myEl var el = myEl.querySelector("#foo > div.bar"); // 返回一个文档中a static NodeList,不是即时的 var els = myEl.querySelectorAll(".class"); //元素是否匹配选择器 myElement.matches('div.bar') === true // 返回的是HTMLCollection,即时更新的。 var el = document.getElementById('ID'); var els = document.getElementsByClassName('CLASS'); var els = document.getElementsByTagName('标签名'); var els = document.getElementsByName('name属性');
Element也提供了很多相对于元素的DOM导航方法:
// 获取父元素、父节点 var parent = ele.parentNode; var parent = ele.parentElement;//非标准 // 获取子节点,子节点可以是任何一种节点,可以通过nodeType来判断 var nodes = ele.children;//元素节点 var nodes = ele.childNodes; //所有节点,包括文本,元素等。可配合nodeType == 1得到元素节点 // 当前元素的第一个/最后一个子元素节点 ele.firstElementChild;//第一个元素节点 ele.firstChild //第一个节点,一般是文本节点 ele.lastElementChild;//最后一个元素节点 ele.lastChild//最后一个节点 // 下一个/上一个兄弟节点 var el = ele.nextElementSibling;//元素节点 var el = ele.nextSibling;//包括文本节点 var el = ele.previousElementSibling; var el = ele.previousSibling;
DOM 更改
append,replace,insertBefor的参数el如果已存在DOM中,都会先移除,再插入到新位置。
删除一个元素自身
myElement.parentNode.removeChild(myElement)
// 添加、删除子元素.多次appendChild到一个父节点会引起浏览器多次重新渲染,此时可以将节点组合到fragment = document.createDocumentFragment()中。 ele.appendChild(el);//避免链式操作 ele.removeChild(el);//如果有返回值,则存在内存中。 // 替换子元素 //newChild如果存在dom中,则会被移除。replaceNode 为oldChild replaceNode = parentNode.replaceChild(newChild, oldChild); // 插入子元素 //newElement如果存在dom中,会先被移除再插入(不想移除可先复制)。 //referenceElement必须有,可为null,为null时,插入到parentElement最后 //return新增加的node(fragment不返回) newElement = parentElement.insertBefore(newElement, referenceElement); //没有insertAfter parentElement.insertBefore(newElement,referenceElement.nextSibling) //prepend,使用insertBefore代替。 ParentNode.prepend(nodesToPrepend); //IE支持不好 parentElement.insertBefore(newElement, theFirstChild);//jquery中prepend()也是用此方法 //克隆节点 //node需要被克隆的node //deep为ture,则克隆所有子节点。deep不要省略,因为各版本浏览器默认值不同。 //深度克隆会克隆所有属性(除addEventListener和后续添加的click事件如:node.onclick = fn,但是会克隆写在dom中的onclick事件),容易导致id重复的问题。 var dupNode = node.cloneNode([deep]); //document和iframe之间的克隆 var node = document.importNode(externalNode, deep);
修改class,属性和样式
修改属性
.getAttibute(), .setAttribute()和.removeAttribute()这三个方法。这些方法直接修改的是元素的HTML属性(与DOM属性相对),因此会使浏览器重新渲染。浏览器重新渲染不仅比只是设置DOM属性代价更高,而且还会产生不期望的后果。作为一个小原则,除非你真的想对HTML“持久化”那些改变,你就只用上面的方法修改与DOM属性不相关的HTML属性(比如colspan)
// 获取一个{name, value}的数组 var attrs = el.attributes; // 获取、设置属性 var c = el.getAttribute('class'); el.setAttribute('class', 'highlight'); // 判断、移除属性 el.hasAttribute('class'); el.removeAttribute('class'); // 是否有属性设置 el.hasAttributes(); // Get an attribute value const value = myElement.value // Set an attribute as an element property myElement.value = 'foo' // Set multiple properties using Object.assign() Object.assign(myElement, { value: 'foo', id: 'bar' }) // Remove an attribute myElement.value = null
修改class
className和classList
myElement.classList.add('foo') myElement.classList.remove('bar') myElement.classList.toggle('baz') el.className += ' class'
修改样式
在JavaScript里要写成驼峰形式.如果我们想获得CSS规则的值,我们可以通过.style属性。然而,通过它只能拿到我们明确设置过的样式。想拿到计算后的样式值,我们可以用.window.getComputedStyle()。它可以拿到这个元素并返回一个CSSStyleDeclaration。这个返回值包括了这个元素自己的和继承自父元素的全部样式。
myElement.style.marginLeft = '2em' window.getComputedStyle(myElement).getPropertyValue('margin-left') // 动态添加样式规则 var style = document.createElement('style'); style.innerHTML = 'body{color:red} #top:hover{background-color: red;color: white;}'; document.head.appendChild(style);
常见问题
innerHTML与outerHTML的区别?
DOM元素的innerHTML, outerHTML, innerText, outerText属性的区别也经常被面试官问到, 比如对于这样一个HTML元素:
<div id="main"> 我是测试文本<br/> </div>
let el = document.querySelector("#main"); console.log("el.innerHTML: ",el.innerHTML); //我是测试文本<br> console.log("el.outerHTML: ",el.outerHTML); //<div id="main">我是测试文本<br></div> console.log("el.innerText: ",el.innerText); //我是测试文本 console.log("el.outerText: ",el.outerText); //我是测试文本 /* el.innerText = "哈哈"; */ el.outerText = "哈哈";
- innerHTML:内部HTML;
- outerHTML:外部HTML;
- innerText:内部文本;
outerText:内部文本;
上述四个属性不仅可以读取,还可以赋值。outerText和innerText的区别在于outerText赋值时会把标签一起赋值掉,另外xxText赋值时HTML特殊字符会被转义。
https://jsfiddle.net/langlang...
jQuery的html()与innerHTML的区别?
jQuery的.html()会调用.innerHTML来操作,但同时也会catch异常,然后用.empty(), .append()来重新操作。 这是因为IE8中有些元素的.innerHTML是只读的。见:http://stackoverflow.com/ques...
NodeList 和 HTMLCollection区别。
NodeList是节点集合,包括任何节点类型。HTMLCollection是元素集合。NodeList有.forEach(),但IE不支持,所以一般转换成数组再调用//[Arry.from()][5] Array.from(myElements).forEach(doSth); Array.protoType.forEach.call(myElements,doSth); [].forEach.call(myElements,doSth)
参考文章:
- No JQuery! 原生 JavaScript 操作 DOM
- HTML属性与DOM属性的区别?
相关推荐
Vue和React是数据驱动视图,如何有效控制DOM操作?能不能把计算,更多的转移为js计算?因为js执行速度很快。patch函数-->patch,对比tag,对比tag与key,对比children