JavaScript学习笔记(7)——DOM和事件

目录

前言

一、DOM

文档节点

元素节点

文本节点

属性节点

事件

文档的加载

DOM的修改

节点的复制

CSS样式

修改

读取

二、事件对象

总结


前言

本章学习DOM,包含各个节点,文档的加载,DOM的修改等。在事件对象中将学习事件的捕获、冒泡。


一、DOM

Document Object Model

文档对象模型,通过DOM可以来任意来修改网页中各个内容,DOM把JS与网页联系起来

        文档 文档指的是网页,一个网页就是一个文档

        对象 对象指DOM将网页中的每一个节点都转换为对象, 转换完对象以后,就可以以一种纯面向对象的形式来操作网页了

        模型 模型用来表示节点和节点之间的关系,方便操作页面

节点(Node) 节点是构成网页的最基本的单元,网页中的每一个部分都可以称为是一个节点。虽然都是节点,但是节点的类型却是不同的。

节点是网页所有对象的父类

常用的节点

  • 文档节点 (Document),代表整个网页
  • 元素节点(Element),代表网页中的标签
  • 属性节点(Attribute),代表标签中的属性
  • 文本节点(Text),代表网页中的文本内容

要使用DOM来操作网页,我们需要浏览器至少得先给我一个对象
    浏览器已经为我们提供了一个document对象,它是一个全局变量可以直接使用
    document代表的是整个的网页

文档节点

document对象表示的是整个网页,它是window对象的属性,可以在页面中直接使用

document对象的原型链
    HTMLDocument -> Document -> Node -> EventTarget -> Object.prototype -> null
凡是在原型链上存在的对象的属性和方法都可以通过Document去调用
部分属性:
    document.documentElement --> html根元素
    document.head --> head元素
    document.title --> title元素
    document.body --> body元素
    document.links --> 获取页面中所有的超链接

元素节点

在网页中,每一个标签都是一个元素节点

如何获取元素节点对象?
        1. 通过document对象来获取元素节点
        2. 通过document对象来创建元素节点

1.通过document来获取已有的元素节点:

document.getElementById()
        根据id获取一个元素节点对象
document.getElementsByClassName()
        根据元素的class属性值获取一组元素节点对象
        返回的是一个类数组对象
        该方法返回的结果是一个实时更新的集合
                当网页中新添加元素时,集合也会实时的刷新
document.getElementsByTagName()
        根据标签名获取一组元素节点对象
        返回的结果是可以实时更新的集合
        document.getElementsByTagName("*") 获取页面中所有的元素
document.getElementsByName()
        根据name属性获取一组元素节点对象
        返回一个实时更新的集合
        主要用于表单项
document.querySelectorAll()
        根据选择器去页面中查询元素
        会返回一个类数组(不会实时更新)
document.querySelector()
        根据选择器去页面中查询第一个符合条件的元素

2.创建一个元素节点
document.createElement()
        根据标签名创建一个元素节点对象

div元素的原型链
    HTMLDivElement -> HTMLElement -> Element -> Node -> ...
通过元素节点对象获取其他节点的方法
    element.childNodes 获取当前元素的子节点(会包含空白的子节点,包含文本和换行)
    element.children 获取当前元素的子元素  (这个比较合理,用这个)
    element.firstElementChild 获取当前元素的第一个子元素
    element.lastElementChild 获取当前元素的最后一个子元素
    element.nextElementSibling 获取当前元素的下一个兄弟元素
    element.previousElementSibling 获取当前元素的前一个兄弟元素
    element.parentNode 获取当前元素的父节点
    element.tagName 获取当前元素的标签名

<div id="box1">
    我是box1
    <span class="s1">我是s1</span>
    <span class="s1">我是s2</span>
</div>
<script>
const box1 = document.getElementById("box1")
const cns = box1.childNodes
</script>

文本节点

在DOM中,网页中所有的文本内容都是文本节点对象

可以通过元素来获取其中的文本节点对象,但是我们通常不会这么做,可以直接通过元素操作它们,无需获取

我们可以直接通过元素去修改其中的文本

element.textContent 获取或修改元素中的文本内容

        获取的是标签中的内容,不会考虑css样式

element.innerText 获取或修改元素中的文本内容

        innerText获取内容时,会考虑css样式

        通过innerText去读取CSS样式,会触发网页的重排(计算CSS样式),性能会差一点

        上述修改元素文本内容,当字符串中有标签时,会自动对标签进行转义,<li> --> &lt;li&gt;

element.innerHTML 获取或修改元素中的html代码

        可以直接向元素中添加html代码

        innerHTML插入内容时,有被xss注入的风险,避免从用户那接收内容来修改html代码

<div id="box1">
    <span style="text-transform: uppercase;">我是box1</span>
</div>
<script>
const box1 = document.getElementById("box1")
</script>

属性节点

在DOM也是一个对象,通常不需要获取对象而是直接通过元素即可完成对其的各种操作

如何操作属性节点:

方式一:

        读取:元素.属性名

                注意:class属性需要使用className来读取

        读取一个布尔值时,会返回true或false

        修改:元素.属性名 = 属性值

方式二:

        读取:元素.getAttribute(属性名)

        修改:元素.setAttribute(属性名, 属性值)

        删除:元素.removeAttribute(属性名)

<input class="a" type="text" name="username" value="admin">
<script>
const input = document.getElementsByName("username")[0]
console.log(input.type)
console.log(input.className)
</script>

事件

事件就是用户和页面之间发生的交互行为
        比如:点击按钮、鼠标移动、双击按钮、敲击键盘、松开按键...  
可以通过为事件绑定响应函数(回调函数),来完成和用户之间的交互
绑定响应函数的方式:
        1.可以直接在元素的属性中设置
        2.可以通过为元素的指定属性设置回调函数的形式来绑定事件(一个事件只能绑定一个响应函数)会覆盖
        3.可以通过元素addEventListener()方法来绑定事件,一个事件能绑定多个响应函数

<button id="btn">点我一下</button>
<script>
// 获取到按钮对象
const btn = document.getElementById("btn")
//方法1
<button id="btn1" onmouseenter="alert('你点我干嘛~')">点我一下</button>
//方法2
btn.onclick = function(){
    alert("我又被点了一下~~")
}
btn.onclick = function(){
    alert("1123111")
}

//方法3
btn.addEventListener("click", function(){
	alert("哈哈哈")
})
btn.addEventListener("click", function(){
	alert("嘻嘻嘻")
})
</script>

文档的加载

网页是自上向下加载的,如果将js代码编写到网页的上边,js代码在执行时,网页还没有加载完毕,这时会出现无法获取到DOM对象的情况

如何解决这个问题:
        1. 将script标签编写到body的最后
        2. 将代码编写到window.onload的回调函数中
        3. 将代码编写到document对象的DOMContentLoaded的回调函数中(执行时机更早)
        4. 将代码编写到外部的js文件中,然后以defer的形式进行引入(执行时机更早,早于DOMContentLoaded)

window.onload 事件会在窗口中的内容加载完毕之后才触发(包括如果使用到的其他文档加载完)
document的DOMContentLoaded事件会在当前文档加载完毕之后触发
 

//方法2
window.onload = function () {
	const btn = document.getElementById("btn")
	console.log(btn)
}
window.addEventListener("load", function () {
	const btn = document.getElementById("btn")
	alert(btn)
})
//方法3
document.addEventListener("DOMContentLoaded", function () {
	const btn = document.getElementById("btn")
	alert(btn)
})
//方法4
<script defer src="./script/script.js"></script>

DOM的修改

1、增

appendChild() 用于给一个节点添加子节点

insertAdjacentElement()可以向元素的任意位置添加元素

        两个参数:1.要添加的位置 2.要添加的元素
        beforeend 标签的最后         afterbegin 标签的开始  
        beforebegin 在元素的前边插入元素(兄弟元素) afterend 在元素的后边插入元素(兄弟元素)

方法:

list.appendChild(li)

list.insertAdjacentElement("afterend", li)

list.insertAdjacentHTML("beforeend", "<li id='bgj'>白骨精</li>")

const list = document.getElementById("list")
// 获取按钮
const btn01 = document.getElementById("btn01")
btn01.onclick = function () {
    // 创建一个li
    const li = document.createElement("li")
    // 向li中添加文本
    li.textContent = "唐僧"
    // 给li添加id属性
    li.id = "ts"

    list.appendChild(li)

    list.insertAdjacentElement("afterend", li)
    list.insertAdjacentHTML("beforeend", "<li id='bgj'>白骨精</li>")
}

2、删

remove()方法用来删除当前元素

swk.remove()

3、改

replaceWith() 使用一个元素替换当前元素  被替换元素.replaceWith(替换元素)

const btn02 = document.getElementById("btn02")
btn02.onclick = function(){
    // 创建一个蜘蛛精替换孙悟空
    const li = document.createElement("li")
    li.textContent = "蜘蛛精"
    li.id = "zzj"

    // 获取swk
    const swk = document.getElementById("swk")

    swk.replaceWith(li)
}

事件中可以通过取消默认行为来阻止超链接的跳转,使用return false来取消默认行为,只在 xxx.xxx = function(){}这种形式绑定的事件中才适用

节点的复制

使用 cloneNode() 方法对节点进行复制时,它会复制节点的所有特点包括各种属性
    这个方法默认只会复制当前节点,而不会复制节点的子节点(例如里面的文本节点就不会复制)
    可以传递一个true作为参数,这样表示既复制当前节点也复制节点的子节点

const btn01 = document.getElementById("btn01")
btn01.onclick = function () {
	const newL1 = l1.cloneNode(true) // 用来对节点进行复制的
    newL1.id = "newL1"
    list2.appendChild(newL1)
}

CSS样式

修改

1、元素.style.样式名 = 样式值【少用,要有单位】

如果样式名中含有'-',则需要将样式名修改为驼峰命名法:background-color --> backgroundColor

这样修改的样式相当于给元素添加内联样式

2、修改class属性来间接修改样式

元素.classList 是一个对象,对象中提供了对当前元素的类的各种操作方法

元素.classList.add() 向元素中添加一个或多个class
元素.classList.remove() 移除元素中的一个或多个class
元素.classList.toggle() 切换元素中的class
元素.classList.replace("旧","新") 替换class
元素.classList.contains() 检查class

box1.className += " box2"  //不建议
box1.classList.add("box2", "box3", "box4")
box1.classList.add("box1")
box1.classList.remove("box2")
box1.classList.toggle("box2")
box1.classList.replace("box1", "box2")
let result = box1.classList.contains("box3")
console.log(result)

通过class修改样式的好处:
        可以一次性修改多个样式
        对JS和CSS进行解耦

读取

getComputedStyle(参数1,"参数2")

它会返回一个对象,这个对象中包含了当前元素所有的生效的样式

参数:
        1. 要获取样式的对象
        2. 要获取的伪元素

<style>
	.box1 {
		height: 200px;
		background-color: #bfa;
	}

	.box1::before {
		content: "hello";
		color: red;
	}
</style>
<script>
const btn = document.getElementById("btn")
const box1 = document.querySelector(".box1")

btn.onclick = function () {
    const styleObj = getComputedStyle(box1)
    console.log(styleObj.backgroundColor)
    console.log(styleObj.width)
    console.log(styleObj.left)
    //两个参数
    const beforeStyle = getComputedStyle(box1, "::before")
    console.log(beforeStyle.color)
    //要先转
    console.log(parseInt(styleObj.width) + 100)
    box1.style.width = parseInt(styleObj.width) + 100 + "px"
}
</style>

注意:样式对象中返回的是带单位样式值,一定不能来拿来直接计算,所以在计算时,一定要进行类型转换

样式对象中返回的样式值,不一定能来拿来直接计算,所以使用时,一定要确保值是可以计算的才去计算,因为有些返回auto

元素.属性(返回的数值没有单位,可以直接使用)

1、获取元素内部的宽度和高度(包括内容区和内边距)

元素.clientHeight
元素.clientWidth

2、获取元素的可见框的大小(包括内容区、内边距和边框)

元素.offsetHeight
元素.offsetWidth

3、获取元素滚动区域的大小

元素.scrollHeight
元素.scrollWidth

4、获取元素的定位父元素

元素.offsetParent

定位父元素:离当前元素最近的开启了定位的祖先元素,如果所有的元素都没有开启定位则返回body

5、获取元素相对于其定位父元素的偏移量

元素.offsetTop
元素.offsetLeft

6、获取或设置元素滚动条的偏移量

元素.scrollTop
元素.scrollLeft

二、事件对象

事件对象是由浏览器在事件触发时所创建的对象,这个对象中封装了事件相关的各种信息

浏览器在创建事件对象后,会将事件对象作为响应函数的参数传递,所以我们可以在事件的回调函数中定义一个形参来接收事件对象,与你定义的函数形式无关

const box1 = document.getElementById("box1")
box1.onmousemove = function(){
	console.log(event)
}
box1.onmousemove = event => {
	console.log(event)
}
box1.addEventListener("mousemove", event => {
	console.log(event.clientX, event.clientY)
	box1.textContent = event.clientX + "," + event.clientY
})

在DOM中存在着多种不同类型的事件对象

多种事件对象有一个共同的祖先 Event

event.target 触发事件的对象(不等于绑定事件的对象,this是指向绑定事件的对象)

event.currentTarget 绑定事件的对象(同this)

event.stopPropagation() 停止事件的传导

event.preventDefault() 取消默认行为,代替return false那种法子

事件的冒泡(bubble)

        事件的冒泡就是指事件的向上传导

        当元素上的某个事件被触发后,其祖先元素上的相同事件也会同时被触发

        冒泡的存在大大的简化了代码的编写,但是在一些场景下我们并不希望冒泡存在 不希望事件冒泡时,可以通过事件对象来取消冒泡 event.stopPropagation() 取消事件传导

        事件的冒泡与样式无关,只与结构有关(结构上重叠,虽然样式上不重叠也会触发冒泡)

事件的捕获

        指事件从外向内的传导,当前元素触发事件以后,会先从当前元素最大的祖先元素开始向当前元素进行事件的捕获

        如果希望在捕获阶段触发事件,可以将addEventListener的第三个参数设置为true

        一般情况下我们不希望事件在捕获阶段触发,所以通常都不需要设置第三个参数

事件的委派

        委派就是将本该绑定给多个元素的事件,统一绑定给document(一般),这样可以降低代码复杂度方便维护

        在document的触发事件通过写条件判断来筛选相关元素

事件的传播机制

在DOM中,事件的传播可以分为三个阶段:event.eventPhase 表示事件触发的阶段

        捕获阶段 (由祖先元素向目标元素进行事件的捕获)(默认情况下,事件不会在捕获阶段触发

        目标阶段 (触发事件的对象)如果事件指定不冒泡,那就会在这里中止

        冒泡阶段 (由目标元素向祖先元素进行事件的冒泡)


总结

本章学习了重点内容文档对象模型DOM以及事件。

根据尚硅谷李立超老师2022年的JS视频整理而成。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值