DOM是“Document Object Model”的首字母缩写,即文档对象模型。用来描绘一个层次化的节点树,允许开发人员获取、添加、移除和修改页面的某一部分元素。
获取元素
通过id获取
const dom = document.getElementById("box1")
console.log(dom)
通过css选择器获取
console.log(document.querySelector(".name"))
console.log(document.querySelectorAll(".name"))
querySelector会选择捕捉到的第一个元素,querySelectorAll会将捕捉到的全部元素按照数组形式返回。
Element元素对象
元素tag
dom.tagName
属性
// 属性操作
const a = document.getElementById("a")
// 获取属性
console.log(a.getAttribute("href"))
// 设置、修改属性
a.setAttribute("href", "https://www.fengfengzhidao.com")
// 删除属性
a.removeAttribute("xxx")
dataset
可以以对象的形式获取、设置标签属性
<div id="box" data-name="枫枫">
这是一个盒子
</div>
<script>
const dom = document.getElementById("box")
// 获取
console.log(dom.dataset.name)
console.log(dom.dataset["name"])
console.log(dom.dataset)
// 设置
dom.dataset.addr = "长沙市"
// 删除
delete dom.dataset.name
// 可以使用自定义属性的方式
console.log( dom.getAttribute("data-addr"))
</script>
classList
以数组的形式获取、操作标签的class
<div class="box">
</div>
<script>
const box = document.querySelector(".box")
console.log(box.classList)
// 添加
box.classList.add("head")
// 是否包含
console.log(box.classList.contains("head"))
// 有就删除,没有就创建
box.classList.toggle("footer")
box.classList.toggle("footer")
// 删除
box.classList.remove("head")
// 替换
box.classList.replace("box", "box1")
</script>
outerHTML、innerHTML、innerText
<div id="box">
<a href="htt://www.fengfengzhidao.com">点我</a>
<span>你好</span>
</div>
<script>
const box = document.getElementById("box")
console.log(box.innerText)
console.log(box.innerHTML)
console.log(box.outerHTML)
// box.innerText = "<a>xxx</a>"
// box.innerHTML = `
// <div>
// <span>123</span>
// <span>234</span>
// </div>
// `
// box.outerHTML = "<a>xxx</a>"
</script>
style
设置或读取css样式
如果通过 style 属性去获取样式,则只能获取行内样式,不能获取其他地方的样式
对于 - 相连的css属性名,要么使用 [] 来调用属性,要么转换成小驼峰命名的方式
<div class="name" style="font-size: 20px; background-color: #800e0e; color: white">枫枫知道</div>
<script>
const dom = document.querySelector(".name")
// 获取样式
console.log(dom.style.fontSize)
console.log(dom.style.backgroundColor)
console.log(dom.style.color)
console.log(dom.style.textAlign) // 只能获取行内的,其他地方的获取不到
// 设置样式
dom.style.fontSize = "30px"
dom.style.padding = "30px"
</script>
可以通过 getComputedStyle 可以获取到的元素的计算之后的样式信息
console.log(getComputedStyle(dom).textAlign) // 获取计算后的style样式
节点操作
节点的操作主要就是增删改查
创建节点
document.createElement
// 创建节点
const dom = document.createElement("a")
dom.setAttribute("href", "https://www.fengfengzhidao.com")
dom.innerText = "枫枫知道"
插入子节点
给一个已知的节点去插入一个新的节点
appendChild,在父节点的最后一个子节点后插入一个节点
append,在父节点的最后一个子节点后插入多个不同的节点
insertBefore,在父节点的子节点之前插入节点
第二个参数为null就是append
// 插入子节点
const box = document.getElementById("box")
// box.appendChild(dom)
// box.append(dom)
// 在任意位置之前插入
// box.insertBefore(dom, null)
// console.log(box.children)
// box.insertBefore(dom, box.children[1])
// box.insertBefore(dom, document.querySelector(".d2"))
添加兄弟节点
after 在后面插入
before 在前面插入
const d1 = document.querySelector(".d1")
// d1.before(dom) // 在d1的前面插入
d1.after(dom) // 在d1的后面插入
删除节点
node.removeChild() 从DOM中删除一个子节点。返回删除的节点
node.remove() 删除自身,没有返回值
const d2 = document.querySelector(".d2")
console.log(d2.removeChild(d2.querySelector(".dd2"))) // 删除子节点,并返回被删除的子节点
d2.remove() // 删除自己
父子节点
const d2 = document.querySelector(".d2")
console.log(d2.children) // 获取它的子节点列表
console.log(d2.parentNode) // 获取它的父亲节点
事件
JS事件,就是用户或浏览器本身的某种行为,一般是用户对页面的一些动作引起的
例如,单击某个链接或按钮、在文本框中输入文本、按下键盘上的某个按键、移动鼠标等等
当事件发生时,您可以使用 JavaScript 中的事件处理程序(也可称为事件监听器)来检测并执行某些特定的程序。
一般情况下事件的名称都是以单词on开头的,例如点击事件 onclick、页面加载事件 onload 等
事件有三种绑定方式,分别是:
在标签上绑定事件
<input placeholder="用户名" oninput="input(event)">
<button>点我</button>
<script>
function input(e){
console.log(e.target.value)
}
</script>
在dom中绑定事件
const btn = document.querySelector(".btn")
btn.onclick = function (e){
console.log(e.target) // 获取被点击的dom对象
}
添加事件监听
function click(e){
console.log(e.target)
}
btn.addEventListener("click", click)
// btn.addEventListener("click", function (e){
// console.log(2, e.target)
// })
// 移除事件
const removeEvent = document.querySelector(".remove_event")
removeEvent.onclick = function (){
btn.removeEventListener("click", click)
}
需要记住的一些事件
load 加载完成
resize 窗口大小变化
scroll 滚动事件
blur 失去焦点
focus 获得焦点
click 用户单击鼠标左键或按下回车键触发
dbclick 用户双击鼠标左键触发。
mousedown 在用户按下了任意鼠标按钮时触发。
mouseenter 在鼠标光标从元素外部首次移动到元素范围内时触发。此事件不冒泡。
mouseleave 元素上方的光标移动到元素范围之外时触发。不冒泡。
mousemove 光标在元素的内部不断的移动时触发。
mouseover 鼠标指针位于一个元素外部,然后用户将首次移动到另一个元素边界之内时触发。
mouseout 用户将光标从一个元素上方移动到另一个元素时触发。
mouseup 在用户释放鼠标按钮时触发。
keydown 当用户按下键盘上的任意键时触发。按住不放,会重复触发。
keypress 当用户按下键盘上的字符键时触发。按住不放,会重复触发。
keyup 当用户释放键盘上的键时触发。
textInput 这是唯一的文本事件,用意是将文本显示给用户之前更容易拦截文本。
事件冒泡
当一个事件被触发时,它首先在最内层的元素(也称为目标元素或事件源)上发生
然后,这个事件会向上冒泡,依次触发其父元素上的同一类型事件,一直冒泡到最外层元素,通常是document对象
这种冒泡机制允许我们在父元素上设置事件处理器,以便在子元素的事件发生时执行特定的操作
<div class="p1">
<div class="p2">
<div class="p3">我是p3</div>
</div>
</div>
<script>
const p1 = document.querySelector(".p1")
const p2 = document.querySelector(".p2")
const p3 = document.querySelector(".p3")
p3.onclick = function (e){
console.log("p3", e.target)
}
p2.onclick = function (e){
console.log("p2", e.target)
}
p1.onclick = function (e){
console.log("p1", e.target)
}
</script>
阻止冒泡
event.stopPropagation()
阻止事件的默认行为
常规情况下点击a标签会自动跳转至页面这是事件的默认行为,若不想要这个效果,即可使用阻止事件的默认行为即可实现
event.preventDefault()
很多网站都有,点击外部链接会有安全提示
const a = document.querySelector("a")
a.onclick = function (e){
const ok = confirm(`你确定要访问 ${e.target.getAttribute("href")}吗`)
if (!ok){
e.preventDefault() // 取消标签的默认行为
}
}
事件委托
事件委托,又叫事件代理。事件委托就是利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件
比如说有100个子节点,像实现点击子节点执行某个函数,给100个子节点去绑定事件明显不划算,就可以通过事件委托来实现
<div class="box">
<div class="s s1">s1</div>
<div class="s s2">s2</div>
<div class="s s3">s3</div>
<div class="s s4">s4</div>
<div class="s s5">s5</div>
</div>
<script>
const box = document.querySelector(".box")
box.onclick = function (e){
console.log(e.target)
}
</script>
事件循环
JavaScript事件循环是一种机制,用于处理异步事件和回调函数。它是JavaScript运行时环境的一部分,负责管理事件队列和调用栈。
事件循环的基本原理是事件循环的核心是一个事件队列,所有的事件都被放入这个队列中,然后按照顺序依次执行。如果队列为空,JavaScript会等待新的任务加入队列。当JavaScript代码执行时,所有同步任务都会被立即执行,而异步任务则会被放入事件队列中
当所有同步任务执行完毕后,事件循环会从事件队列中取出一个任务,并将其放入调用栈中执行。当该任务执行完毕后,事件循环会再次从事件队列中取出下一个任务,并重复这个过程
// 什么是异步任务
console.log(1)
setTimeout(() => {
console.log(3)
}, 0)
console.log(2)
// 顺序 1 2 3
// 当同步任务执行完之后,才会从任务队列中执行异步任务
宏任务和微任务
异步任务也分宏任务和微任务
宏任务包括setTimeout、setInterval、I/O操作等
微任务包括Promise、MutationObserver等
当事件循环从事件队列中取出一个任务时,它会先执行所有微任务,然后再执行一个宏任务。这个过程会一直重复,直到事件队列中的所有任务都被执行完毕
console.log('1');
setTimeout(function() {
console.log('2');
Promise.resolve().then(function() {
console.log('3');
});
}, 0);
Promise.resolve().then(function() {
console.log('4');
});
console.log('5');
// 输出结果为: 1 5 4 2 3
执行顺序:
- 执行第一个
console.log,输出1。 - 执行
setTimeout,将其回调函数放入宏任务队列中。 - 执行
Promise.resolve().then,将其回调函数放入微任务队列中。 - 执行第二个
console.log,输出5。 - 当前任务执行结束,执行微任务队列中的所有任务,输出4。
- 执行宏任务队列中的第一个任务,即
setTimeout的回调函数,输出2。 - 执行
Promise.resolve().then的回调函数,输出3。
需要注意的是,微任务和宏任务的执行顺序是固定的,即先执行所有微任务,再执行宏任务。因此,如果在一个宏任务中产生了新的微任务,那么这些微任务会在下一个宏任务执行之前执行。
console.log('1');
setTimeout(function() {
console.log('2');
Promise.resolve().then(function() {
console.log('3');
});
}, 0);
Promise.resolve().then(function() {
console.log('4');
setTimeout(function() {
console.log('5');
}, 0);
});
console.log('6');
// 输出结果为:1 6 4 2 3 5
执行顺序:
- 执行第一个
console.log,输出1。 - 执行
setTimeout,将其回调函数放入宏任务队列中。 - 执行
Promise.resolve().then,将其回调函数放入微任务队列中。 - 执行第三个
console.log,输出6。 - 当前任务执行结束,执行微任务队列中的所有任务,输出4。
- 执行宏任务队列中的第一个任务,即
setTimeout的回调函数,输出2。 - 执行
Promise.resolve().then的回调函数,将setTimeout的回调函数放入宏任务队列中。 - 当前任务执行结束,执行微任务队列中的所有任务,输出3。
- 执行宏任务队列中的第一个任务,即
setTimeout的回调函数,输出5。