1、Dom
1.1、概念
Document Object Model(文档对象模型), 整个WEB页面, 所有的Dom元素都在Document整个文档里。DOM就是把整个文档页面当做一个对象进行操作, document 下 包含了 根据 html 创建 的 Dom 对象, 这个DOM对象, 以树形结构展示, 即DOM树
1.2、Node类型
- Node.ELEMENT_NODE:数值1,对应元素节点Element。
- Node.ATTRIBUTE_NODE:数值2,对应属性节点Attr。
- Node.TEXT_NODE:数值3,对应文本节点Text。
- Node.CDATA_SECTION_NODE:数值4,对应文档中CDATA部(不会由解析器解析的文本)。
- Node.ENTITY_REFERENCE_NODE:数值5,对应实体引用。
- Node.ENTITY_NODE:数值6,对应实体类型Entity。
- Node.PROCESSING_INSTRUCTION_NODE:数值7,对应处理指令。
- Node.COMMENT_NODE:数值8,对应注释节点Comment。
- Node.DOCUMENT_NODE:数值9,对应文档节点Document。
- Node.DOCUMENT_TYPE_NODE:数值10,对应文档类型节点DocumentType。
- Node.DOCUMENT_FRAGMENT_NODE:数值11,对应文档片段节点DocumentFragment。
- Node.NOTATION_NODE:数值12,对应DTD中声明的符号
1.3、节点和元素
元素也是节点的一种,所以是包含关系,元素对应类型为ELEMENT_NODE
节点:
- 父节点:parentNode
- 前兄弟节点:previousSibling
- 后兄弟节点:nextSibling
- 子节点:childNodes
- 第一个子节点:fristChild
- 最后一个子节点:lastChild
元素:
- 父元素:parentElement
- 前兄弟节点:previousElementSibling
- 后兄弟节点:nextElementSibling
- 子节点:children
- 第一个子节点:firstElementChild
- 最后一个子节点:lastElementChild
2、DOM操作
2.1、创建
1、document.write
这是我们最开始学习html会遇到的:文档流
浏览器在打开页面时会开启一个文档流,来渲染每个标签,从上到下执行完了后会关闭文档流,
但要是执行完后,再添加document.write,就会输出覆盖body下的所有内容,目前来看,此用法没啥使用场景
2、innerHTML
看到这个会想起innerText和textContent,其实这三区别主要是innerText和textContent是纯文本内容,内部不能插入标签因为不会被解析,而innerHTML可以解析插入的标签,而innerText和textContent区别,我会在最后疑难讲解中仔细说
如果直接用等号(=),会覆盖原来的值,用加等(+=),从视觉角度没有覆盖,就是增加新元素,本质上是把原来的元素取出来,再和新的元素一起添加进去,其实也是覆盖了原来的内容,它会让原来的元素事件失效
textContent 是 Node 对象的属性;
innerHTML 是 Element 对象的属性;
innerText 是 HTMLElement 对象的属性;
3、createElement
创建一个元素
document.createElement(tagName[, options])
tagName: 指定要创建元素类型的字符串
options: 这是高阶用法了,基本没用到
其值是包含一个属性名为 is 的对象,该对象的值是用 customElements.define() 方法定义过的一个自定义元素的标签名
// 定义新元素
customElements.define('expanding-list', ExpandingList, { extends: "ul" });
let expandingList = document.createElement("ul", { is: "expanding-list" });
2.2、增加
2.2.1、appendChild
增到到最后面,即追加:父元素.appendChild(标签名) 注意:这个标签名是变量,不能加引号
2.2.2、insertBefore
增加到某一子元素前面,即插入:父元素.insertBefore(标签名,在哪个元素之前插入)
如果添加的是新创建的元素,就是添加,否则相当于是移动
2.2.3、cloneNode
浅克隆:cloneNode(),只克隆样式(即标签),无内容
深克隆:cloneNode(true),克隆了样式和内容,但是没有方法
2.3、删除
父元素.removeChild(要被删除的元素)
2.4、查找
1、获取单个DOM对象:document.getElementById(‘id’)
2、获取DOM伪数组
xxx.getElementsByTagName(‘标签名’)
xxx.getElementsByClassName(‘类名’)
xxx.querySelector
xxx.quertSelectorAll
获取父元素:parentNode
获取父元素下的子元素:children
- children 属性是 Element 对象的一个只读属性,返回一个只包含元素节点(Element 节点)的 HTMLCollection。
- children 只会包含元素节点,不包括其他类型的节点(如文本节点或注释节点)。
- children 不会包含那些隐藏的元素,比如使用 CSS 的 display: none; 或 visibility: hidden; 隐藏的元素。
- 例如,如果一个 div 元素下有若干个子元素,div.children 将返回一个包含这些子元素的 HTMLCollection。
获取父元素下的所有元素childNodes - childNodes 属性是 Node 对象的一个只读属性,返回一个包含所有子节点的 NodeList。
- childNodes 包含父元素下的所有子节点,包括元素节点、文本节点、注释节点等。
- childNodes 返回的是一个动态的 NodeList,会随着 DOM 结构的变化而更新。
- 例如,如果一个 div 元素下有若干个子节点,包括元素节点、文本节点和注释节点,div.childNodes 将返回包含所有这些子节点的 NodeList。
2.5、修改元素属性
常见:src、href、tittle等
表单:disabled(是否禁用)、checked(单复选框是否选中)、selected(下拉菜单是否选中),这些属性,在js中是写上就代表使用了,因此修改的时候,赋值为true 或false即可
修改样式:dom.style.xxx = ‘xxx’
修改类名:dom.className = ‘’
classList:是一个伪数组,它保存当前这个元素所有的类
- add() 添加一个类
如果要添加多个类,用逗号隔开,每个类都是独立的一个参数 - remove() 删除一个类
如果要删除多个类,用逗号隔开,每个类都是独立的一个参数 - contains() 判断是否有某个类
如果有得到true,如果没有得到false - toggle() 切换一个类
原来有这个类就删除,原来没有这个类就添加 - replace() 替换一个类
参数1:被替换的类
参数2:要替换的新类1
2.6、修改自定义属性(拓展)
- 新增或设置DOM的属性值:setAttribute()
- 获取DOM的属性值:getAttibute()
- 移除DOM的属性值(自定义和非自定义都可以移除):removeAttibute()
- dateset:
自定义属性写法规范:以用data-开头,方便识别哪些是自定义的属性
方法:元素.dataset
它是一个对象,可以获取所有以data-开头的自定义的属性
获取单个属性,用元素.dataset.属性名
设置元素属性,元素.dataset.属性名 = 数据
3、疑难讲解
3.1、innerText和textContent区别?
对浏览器来说,有textContent会优先使用textContent,因为innerText的返回值依赖于页面的显示,而textContent依赖于代码的内容,所以innerText设置会引起浏览器的回流(reflow),至于回流和重绘我就不细讲了,textContent则不会,所以textContent不会导致浏览器有性能问题
innerText被设置 display: none 时,会返回对应节点文本
innerText被设置 visibility: hidden 时,不会返回对应节点文本
3.2 children和childNodes这种伪数组如何遍历?
1、最简单的都是伪数组转数组
Array.from(伪数组).forEach(() => {})
[].slice.call(伪数组, () => {})
[].forEach.call(伪数组, () => {})
2、NodeList类型的伪数组默认可以调用forEach, for
3、HTMLCollection类型的伪数组默认可以调用for
3.3、各种节点类型的详解
3.3.1 Document
JavaScript通过Document类型表示文档。浏览器中的document对象是HTMLDocument的一个实例,表示整个HTML页面。Document节点具有以下特征:
- nodeType为Node.DOCUMENT_NODE,值为9。
- nodeName的值为#document。
- nodeValue的值为null。
- parentNode的值为null。
- ownerDocument的值为null。
- 其子结点可能是一个DocumentType、Element、ProcessingInstruction或Comment。
3.3.2 Element
Element类型用于表现XML或HTML元素,提供对元素标签名、子节点及特性的访问。例如和
- nodeType为Node.ELEMENT_NODE,值为1。
- nodeName的值为元素的标签名。
- nodeValue的值为null。
- parentNode可能是Document或Element。
- 其子节点可能是Element、Text、Comment、ProcessingInstruction、CDATASection或EntityReference。
3.3.3 Attr
Attr类型在DOM表示元素特性。特性是位于元素attributes属性中的节点。具有下列特征:
- nodeType为Node.TEXT_NODE,值为3。
- nodeName的值是特性的名称。
- nodeValue的值是特性的名称。
- parentNode的值为null。
- 在HTML中不支持子节点(没有子节点)。
- 在XML中子节点可以是Text或EntityReference
3.3.4 Text
文本节点由Text类型表示,包含的是可以照字面解释的纯文本内容。纯文本中可以包含转义后的HTML字符,但不能包含HTML代码。Text节点具有以下特征:
- nodeType为Node.TEXT_NODE,值为3。
- nodeName的值为#text。
- nodeValue的值为节点所包含的文本。
- parentNode是一个Element。
- 不支持子节点(没有子节点)。
3.3.5 Comment
注释在DOM中是通过Comment类型来表示的。Comment节点具有下列特征:
- nodeType为Node.COMMENT_NODE,数值为8。
- nodeName的值为#comment。
- nodeValue的值是注释的内容。
- parentNode可能是Document或Element。
- 不支持子节点(没有子节点)。
3.3.6 CDATASection
CDATASection类型只针对基于XML文档,表示的是CDATA区域。与Comment类似,CDATASection类型继承自Text类型,因此拥有除splitText()之外的所有字符串操作方法。CDATASection节点具有以下特征:
- nodeType为CDATA_SECTION_NODE,值为4。
- nodeName的值为#cdata-section。
- nodeValue的值是CDATA区域中的内容。
- parentNode可能是Document或Element。
- 不支持子节点(没有子节点)。
3.3.7 DocumentType
DocumentType类型在Web浏览器中并不常用。DocumentType包含着与文档有关的doctype有关的所有信息,它具有下列特征:
- nodeType为Node.DOCUMENT_TYPE_NODE,值为10。
- nodeName的值为doctype的名称。
- nodeValue的值为null。
- parentNode是Document类型。
- 没有子节点。
3.3.8 DocumentFragment
DocumentFragment是文档片段,一种"轻量级"文档,可以包含和控制节点,但不像完整文档那样占用额外资源。可以将它作为"仓库"使用。具有下列特征:
- nodeType为Node.DOCUMENT_FRAGMENT_NODE,值为11。
- nodeName的值为#document-fragment。
- nodeValue的值为null。
- parentNode的值为null。
- 子节点可以是Element、ProcessingInstruction、Comment、Text、CDATASection或EntityReference。