目录
一、DOM简介
DOM,全称 Document Object Model
Document ,即文档,所谓文档就是指整个网页,换言之,DOM是用来操作网页的。
Object,即对象。DOM将网页中的每一部分内容都转换为了对象,div有div的对象,input有input的对象,甚至一段文本、一段注释也有其所对应的对象。
转换为对象干什么?还记得面向对象吗?转换为对象后,我们就可以以面向对象的方式去操作网页,想要操作哪个元素就获取哪个元素的对象,然后通过调用其方法或属性完成各种操作。
Model,即模型。模型用来表示对象之间的关系,也就是父子元素、祖先后代、兄弟元素等,明确关系后我们便可以通过任意一个对象去获取其他对象。
概念:
节点(Node)
-在DOM标准下,网页中的每一个部分都会转换为对象。这些对象有一个共同的称呼——节点,一个网页将会由多个节点构成,但有着不同的类型
1.文档节点
2.元素节点
3.文本节点
4.属性节点
5……
-结构上,也就是模型,节点是网页中所有对象的父类
关系
-祖先——包含后代元素的元素是祖先元素
-后代——被祖先元素包含的元素是后代元素
-父——直接包含子元素的元素是父元素
-子——直接被父元素包含的元素是子元素
-兄弟——拥有相同父元素的元素是兄弟元素
如何使用DOM
面向对象的编程语言,无非就是两个步骤:1.找对象,2.搞对象。
所以使用DOM我们首先要先拿到一个DOM对象,然后以该对象为切入点来完成各种操作。
二、HelloWorld
要使用DOM来操作网页,我们需要浏览器至少得先给我一个对象
才能去完成各种操作
所以浏览器已经为我们提供一个document对象,它是一个全局变量可以直接使用
document代表的是整个网页
doucument.getElementById( ) 通过document使用getElementById方法获取指定Id的元素
通过JS修改页面对象的内容,使用innerText 属性
<body>
<button id="btn">点我一下</button>
<script>
/*
要使用DOM来操作网页,我们需要浏览器至少得先给我一个对象
才能去完成各种操作
所以浏览器已经为我们提供一个document对象,它是一个全局变量可以直接使用
document代表的是整个网页
*/
// document.write("hh")
// console.log(document);
// 通过document获取btn对象
const btn = document.getElementById("btn")
console.log(btn);
// 修改btn中的内容
btn.innerText = "Click Me"
</script>
</body>
三、文档节点
document 对象
- document 对象表示的是整个网页
- document对象的原型链
HTMLDocument -> Document -> Node -> EventTarget -> Object.prototype -> null
- 凡是在原型链上存在的对象的属性和方法都可以通过Document去调用
- 部分属性:
document.documentElement --> 获取html 根元素
document.head --> 获取head元素
document.title --> 获取title元素
document.body --> 获取body元素
document.links --> 获取页面中所有的超链接
......
<body>
<script>
console.log(document.__proto__);//HTMLDocument,说明该对象本身为HTMLDocument
console.log(document.__proto__.__proto__);//Document,说明HTMLDocument的父类为Document
console.log(document.__proto__.__proto__.__proto__);//Node,说明Document的父类为Node
console.log(document.__proto__.__proto__.__proto__.__proto__);//EventTarget ,说明Node父类为EventTarget
console.log(document.__proto__.__proto__.__proto__.__proto__.__proto__);//Object.prototype
console.log(document.__proto__.__proto__.__proto__.__proto__.__proto__.__proto__);//null
// 由于继承,原型链上的对象的属性和方法都可以使用,因此我们应该明确document的原型链
</script>
</body>
部分属性的例子:
<body>
<a href="#">aaa</a>
<script>
console.log(document.body);
console.log(document.documentElement);
console.log(document.title);
document.title = 'hhh'
console.log(document.title);
console.log(document.forms);//获取网页中的所有表单
console.log(document.images);//获取网页中的所有图片
console.log(document.links);//获取网页中的所有链接,得到的数组
</script>
</body>
四、获取元素节点
元素节点对象(element)
- 在网页中,每一个标签都是一个元素节点,如head, html,title,script,buton
- 如何获取元素节点对象?
1. 通过document对象来获取元素节点
2. 通过document对象来创建元素节点
- 通过document来获取已有的元素节点:
如:
document.documentElement --> 获取html 根元素
document.head --> 获取head元素
document.title --> 获取title元素
document.body --> 获取body元素
document.getElementById( )
- 根据 id 获取一个元素节点对象,因为id 不能重复
document.getElementsByClassName( )
- 根据元素的class 属性值来获取一组元素节点对象,
- 返回的是一个类数组对象
- 该方法返回的结果是一个实时更新的集合
当网页中新添加新元素时,集合也会实时的刷新
document.getElementsByTagName( )
- 根据标签名获取一组元素节点对象
- 返回的结果是可以实时更新的集合,返回是一个类数组对象
- document.getElementsByTagName("*") 星号* 表示获取页面中所有的元素,没有document
document.getElementsByName( )
- 根据name 属性获取一组元素节点对象
- 返回一个实时更新的集合
- 主要用于表单项,因为表单项name属性更有意义
<body>
<button id = "btn">点我一下</button>
<span class="s1">我是span </span>
<span class="s1">我是span</span>
<span class="s1">我是span</span>
<span class="s1">我是span</span>
<span class="s1">我是span</span>
<div>我是div</div>
<div>啦啦啦</div>
<div>略略略</div>
<div>来来来</div>
<div>嘻嘻嘻</div>
<form>
<input type="text" name="username">
<input type="radio" name="gender" value="male">男
<input type="radio" name="gender" value="female">女
</form>
<script>
const btn = document.getElementById("btn")
console.log(btn);
// document.getElementsByClassName(),根据class属性值获取一组元素节点对象
const spans = document.getElementsByClassName("s1")
console.log(spans);//HTMLCollection(5) [span.s1, span.s1, span.s1, span.s1, span.s1]
//返回的是一个类数组,可以用for循环遍历,根据索引取元素
console.log(spans.length);//5,因为其是一个类数组
for(let i=0;i<spans.length;i++){
console.log(spans[i]);//获取,即使修改在后面,但因为是实时的更新,所以会输出修改后的
// 修改
spans[i].innerText = 'hhhh'+ i
}
// document.getElementsByTagName( ),根据标签名获取一组元素节点对象
const divs = document.getElementsByTagName("div")
console.log(divs);//HTMLCollection(5) [div, div, div, div, div]
console.log(document.getElementsByTagName("*" ));
// document.getElementsByName( ),根据name属性获取一组元素节点对象
const genderInput = document.getElementsByName("gender")
console.log(genderInput);//NodeList(2) [input, input]
</script>
document.querySelectorAll( )
- 根据选择器去页面中查询元素 ,注意传入的是选择器, id选择器加 #, 类选择器加 .
- 会返回一个类数组(不会实时更新)
- 没有也会返回一个类空数组,注意当使用id选择器时,返回的是只有一个元素的类数组,要想得到该元素,可以使用索引获得
document.querySelector( )
- 根据选择器去页面中查询第一个符合条件的元素,相当于使用document.querySelectorAll( )获得元素后加上索引0得到的结果
<body>
<button id = "btn">点我一下</button>
<span class="s1">我是span </span>
<span class="s1">我是span</span>
<span class="s1">我是span</span>
<span class="s1">我是span</span>
<span class="s1">我是span</span>
<div>我是div</div>
<div>啦啦啦</div>
<div>略略略</div>
<div>来来来</div>
<div>嘻嘻嘻</div>
<script>
// document.querySelectorAll( )
const divs2 = document.querySelectorAll("div")
const divs3 = document.querySelectorAll("#btn")// id选择器加 #
const divs4 = document.querySelectorAll(".s1")//类选择器加 .
console.log(divs2); //NodeList(5) [div, div, div, div, div]
console.log(divs3); //NodeList [button#btn],虽然id选择器只能得到一个元素节点,
//但其返回的仍是一个类数组,要想得到则使用索引divs3[0]
console.log(divs4); //NodeList(5) [span.s1, span.s1, span.s1, span.s1, span.s1]
// document.querySelector( )
const div = document.querySelector("div")
console.log(div);//<div>我是div</div>
</script>
</body>
- 创建一个元素节点
document.createElement( )
- 根据标签名创建一个元素节点对象,传入的是标签名,但此时该元素节点没有插入到网页中
<body>
<script>
const h2 = document.createElement("h2")
</script>
</body>
五、元素的属性和方法
div元素的原型链:
HTMLDivElement -> HTMLElement -> Element -> Node -> EventTarget -> Object.prototype -> null
<body>
<div id="box1">我是box1</div>
<script>
const box1 = document.getElementById("box1")
console.log(box1);//<div id="box1">我是box1</div>
console.log(box1.__proto__);//HTMLDivElement
console.log(box1.__proto__.__proto__);//HTMLElement
console.log(box1.__proto__.__proto__.__proto__);//Element
console.log(box1.__proto__.__proto__.__proto__.__proto__);//Node
console.log(box1.__proto__.__proto__.__proto__.__proto__.__proto__);//EventTarget
console.log(box1.__proto__.__proto__.__proto__.__proto__.__proto__.__proto__);//Object.prototype
console.log(box1.__proto__.__proto__.__proto__.__proto__.__proto__.__proto__.__proto__);//null
</script>
</body>
通过元素节点对象获取其他节点的方法:
同样可以使用上一节中通过document对象获取其他节点的方法,但是需要将document改为元素节点对象。
element.childNodes 获取当前元素的子节点(会包含空白的子节点)
element.children 获取当前元素的子元素
element.firstChild 获取当前元素的第一个子节点(不实用)
element.firstElementChild 获取当前元素的第一个子元素
element.lastElementChild 获取当前元素的最后一个子元素
element.nextSibling 获取当前元素紧挨着的后一个兄弟节点
element.nextElementSibling 获取当前元素紧挨着的后一个兄弟元素
element.previousSibling 获取当前元素紧挨着的前一个兄弟节点
element.previousElementSibling 获取当前元素紧挨着的前一个兄弟元素
element.parentNode 获取当前元素的父节点
element.parentElement 获取当前元素的父元素
注意: element.parentNode、 element.parentElement 区别不大,因为父节点只能是元素和document, 但父元素中不包括document,只有这一个区别,且区别不重要
element.tagName 获取当前元素的标签名
通过以上可以发现,DOM提供了两个版本,一个是节点版本,一个是元素版本
使用通过document对象获取其他节点的方法例子如下:
<body>
<div id="box1">
我是box1
<span class="s1">我是s1</span>
<span class="s1">我是s1</span>
</div>
<span class="s1">我是s1</span>
<script>
const spans = box1.getElementsByTagName("span")
console.log(spans);//HTMLCollection(2) [span.s1, span.s1]
const spans2 = box1.getElementsByClassName("s1")
console.log(spans2);//HTMLCollection(2) [span.s1, span.s1]
</script>
</body>
element.childNodes 获取当前元素的子节点(会包含空白的子节点)
<body>
<div id="box1">
我是box1
<span class="s1">我是s1</span>
<span class="s1">我是s1</span>
</div>
<div id="box2">
我是box2
<span class="s1">我是s1</span><span class="s1">我是s1</span></div>
<span class="s1">我是s1</span>
<script>
const cns = box1.childNodes
console.log(cns);//NodeList(5) [text, span.s1, text, span.s1, text]
console.log(cns.length);//5
const cns2 = box2.childNodes
console.log(cns2.length);//3
console.log(cns2);//NodeList(3) [text, span.s1, span.s1]
const children = box1.children
console.log(children.length);//2
console.log(children);//HTMLCollection(2) [span.s1, span.s1],只获取子元素
const fchild = box1.firstChild
console.log(fchild);//"我是box1",获取第一个子节点
const fchild1 = box1.firstElementChild
console.log(fchild1);//<span class="s1">我是s1</span>,获取第一个子元素
const n = box1.nextSibling
console.log(n);//#text,获取当前元素紧挨着的后一个兄弟节点
const n2 = box1.nextElementSibling
console.log(n2);//<div id="box2">...</div>,获取当前元素紧挨着的后一个兄弟元素
const n3 = box1.tagName
console.log(n3);//DIV 获取当前元素的标签名
</script>
</body>
六、文本节点
在DOM中,网页中所有的文本内容都是文本节点对象,包括空白
可以通过元素来获取其中的文本节点对象,但是我们通常不会这么做
我们可以直接通过元素去修改其中的文本
修改文本的三个属性
element.textContent 获取或修改元素中的文本内容
- 获取的是标签中的内容,不会考虑CSS样式
element.innerText 获取或修改元素中的文本内容
- innerText获取内容时,会考虑CSS样式
- 通过innerText 去读取CSS样式,会触发网页的重排(计算CSS样式),
所以会比textContent 性能差一些
- 前两种,当字符串中有标签时,会自动对标签进行转义,将其变为字符串, 而不是标签
- 前两种没有被xss注入的风险
element.innerHTML 获取或修改元素中的 html 代码
- 可以直接向元素中添加 html 代码
- innerHTML插入内容时,有被 xss 注入的风险
textContent 和 innerText 获取内容的区别:
textContent获取的是标签中的内容,不会考虑CSS样式, innerText 会考虑CSS样式
如下例子中,使用textContent 可以获取到box1内容,而使用innerText没有内容,因为使用CSS样式将其隐藏了
<body>
<div id="box1">
<span style="display:none;">我是box1</span>
</div>
<div id="box2">
<!-- 将文字设置为大写 -->
<span style="text-transform: uppercase;">我是box2</span>
</div>
<script>
const box1 = document.getElementById("box1")
const box2 = document.getElementById("box2")
console.log(box1.textContent);
console.log(box1.innerText);
console.log(box2.textContent);
console.log(box2.innerText);
</script>
</body>
下图为上述代码输出的结果:
<body>
<div id="box1">我是div</div>
<div id="box2">
<span>我是box2</span>
</div>
<script>
/*
在DOM中,网页中所有的文本内容都是文本节点对象
*/
const box1 = document.getElementById("box1")
const box2 = document.getElementById("box2")
// 通过元素来获取其中的文本节点对象
// const text = box1.firstChild
// console.log(text);//我是div, 获取到了该元素的文本节点,但一般不这么做
console.log(box1.textContent);//我是div,获取文本内容
box1.textContent = "新的内容"//修改文本内容
console.log(box1.innerText);//新的内容,获取文本内容
box1.innerText = '哈哈哈'//修改文本内容
box2.innerHTML = "<li>糖果</li>"//将box2的内容修改为了<li>标签,
// 可直接向元素中添加Html代码
// box1.innerHTML = "<script src='https://sss//sss.js'><\/script>";
// 当修改的内容为用户或者别人输入等内容时,有被xss注入的风险
// 如上面一行代码修改为<script>标签,将我们自己写的一些代码取代了
//这样会对我们整个代码都有影响,网页中代码就改变了,即使是下一用户使用时
// 该<script>标签也会起作用
</script>
</body>
七、属性节点
属性节点(Attr)
- 在DOM中也是一个对象,通常不需要获取该对象,而是直接通过元素即可完成对其的各种操作
- 如何操作属性节点:
方式一:(更方便)
读取:元素. 属性名(注意,class属性需要使用className来读取)
读取一个布尔值时,会返回true 或 false
修改:元素.属性名 = 属性值注意,class属性需要使用className来修改)
修改布尔值时,属性值为 true 或 false,若输入的不是布尔值,会自动转换为 布尔值,如0转换为false
方式二:
读取:元素. getAttribute(属性名)(class属性直接用class来读取即可)
读取一个布尔值时,返回是其对应的属性值,而不是布尔值
修改:元素. setAttribute(属性名,属性值)
修改布尔值时,输入的属性值是啥,就会将该布尔值属性值修改为啥,
不会将其转换为布尔值
删除:元素. removeAttribute(属性名)
方法一的例子:
<body>
<!-- disabled 用来设置标签是不是被禁用的,该属性值是什么无所谓
有该属性就被禁用,没有就不被禁用-->
<input disabled="disabled" class="a" type="text" name="username" value="admin">
<script>
// const input = document.getElementsByName("username")[0]
const input = document.querySelector("[name=username]")//获取该元素的方法很多,如这两种
console.log(input);
console.log(input.name);//username
console.log(input.value);//admin
console.log(input.class);//undefined
console.log(input.className);//a ,class属性需要用className来读取
console.log(input.disabled);//true,有该属性返回true
input.value = 'hhh'
console.log(input.value);
</script>
</body>
方法二的例子:
<body>
<input disabled="disabled" class="a" type="text" name="username" value="admin">
<script>
// const input = document.getElementsByName("username")[0]
const input = document.querySelector("[name=username]")//获取该元素的方法很多,如这两种
// 读取属性节点
console.log(input.getAttribute("name"));//username
console.log(input.getAttribute("type"));//text
console.log(input.getAttribute("class"));//a
console.log(input.getAttribute("disabled"));//disabled
// 使用该方法获取布尔值时,获得的是其对应的属性值,而不是布尔值
// 修改属性节点
input.setAttribute("value","孙悟空")
input.setAttribute("disabled",true)
// 使用该方法修改布尔值时,属性值输入为啥,则修改为相应的字符串,而不会将其转变为布尔值
// 也就是当我们输入false时,并不会将这个布尔值属性去除,只会将其属性值变为false
// 删除属性节点
input.removeAttribute("disabled")
</script>
</body>