原生DOM学习笔记
文章目录
一、基本认知
1. 什么是DOM?
DOM (Document Object Model)——文档对象模型。是浏览器提供的一套专门用来操作网页内容的 API 。
2. DOM 树
3. DOM 对象(重要)
-
浏览器根据html标签生成的 js 对象,所有的标签属性都能在这个对象上找到,所以修改这个对象的属性会自动映射到标签身上。
-
DOM的核心思想:把网页内容当作对象来处理。
-
document对象 是DOM提供的一个对象,网页的所有内容都在document里
二、获取DOM对象
两种方式,更推荐第一种
-
根据CSS选择器获取DOM元素(主)
-
其他方式
1. 根据CSS选择器获取DOM元素(主要)
(1)document.querySelector()
选择匹配到的第一个元素:
const box = document.querySelector('div')
注意:括号里一定要有引号,然后里面写的是css选择器,css里咋写,引号里就咋写,返回值是匹配的第一个元素对象
(2)document.querySelectorAll()
选择匹配的多个元素:
const lis = document.querySelectorAll('ul li')
返回值是一个伪数组,里面是所有匹配到的对象的集合。
伪数组:
- 有长度有索引号
- 但是没有pop,push等方法
那么如果想要得到里面的每一个对象就采用遍历方式获取。
2. 其他方式
这些都是早期的写法,现在基本不怎么用了。
//(1)根据id获取元素.
document.getElementById('nav')
//(2)根据标签获取某一类元素
document.getElementByTagName('div')
//(3)根据类名获取元素
document.getElementByClassName('main')
三、操作DOM内容
1. innerText 属性
-
将文本元素添加/更新到任意标签位置(表单除外)
-
显示纯文本,不会解析标签
const box = document.querySelector('.box') box.innerText = '你好' // 这个属性不会解析标签,也就是说,如果你这么写: box.innerText = '<a>xxxx</a>',是不会把里面内容当成超链接的,只是纯文本。
2. innerHTML属性
与innertext 的区别就是,这个属性会解析标签,那么当多标签的时候建议使用模板字符串(``)。
用法没啥区别。
四、操作元素属性
1. 操作元素-常用属性
**比如:**src href title…等等,下面是进行修改的例子:
//例子:
const pic = document.querySelector('img')
pic.src = './imgs/02.jpg'
pic.title = 'laosan'
2.操作元素-样式属性
用到操控样式的情况还是非常多的,比如:
- 轮播图小圆点自动更换颜色演示
- 点击按钮滚动图片…
(1)通过 style 属性操作 CSS
该方法在修改样式比较少的情况下有优势。并且生成的是行内样式表,权重高,会覆盖掉之前的样式。
const box = document.querySelector('.box')
box.style.width = '300px' //注意要写引号,因为需要跟单位
box.style.backgroundColor = 'pink' //这个里面是不可以写成background-color的,会识别成减法,所以要用小驼峰命名法。
**案例:**随机更换body的背景图片。
//定义一个函数,取到N-M之间的随机整数,复制粘贴就行了,感兴趣就当做数学题研究一下
function getRandom(N,M){
return Math.floor(Math.random()*(M-N+1))+N
}
const random = getRandom(1,10)
document.body.style.backgroundImage=`url(./images/desktop_${random}.jpg`
(2)通过类名className修改 CSS
过程就是现在css里面写一个类,给这个类设定一个样式,当需要修改成这样的样式时候,直接赋给这个元素。
但是需要注意一下,这个会替换掉之前的class类名。
const div = document.querySelector('djv')
div.className = 'mean'
//那么如果还想保留之前的class类,可以这样写,就即保存了当前的,也添加了新的
div.className = 'mean navicate'
(3)通过classList修改CSS (常用)
为了解决className容易覆盖掉之前的类名这个问题,我们是可以通过classList的方式来追加和删除类。
const div = document.querySelector('djv')
// 类名不加点,并且是字符串
// 追加一个类
div.classList.add('nav')
// 删除一个类
div.classList.remove('nav')
// 切换一个类,有就删掉,没有就加上
div.classList.toggle('nav')
3.操作表单元素属性
文本框/单选按钮/多选按钮…
表单在很多情况下也需要修改属性,比如点击眼睛,显示或隐藏密码。
<input type='text' value='电脑'>
<script>
const uname = document.querySelector('input')
//获取表单里的值,innerHTML是得不到值的。
console.log(uname.value)
uname.type='password'
</script>
表单属性中添加就有效果,移除就没有效果,一律使用布尔值表示,比如:disabled、checked、selected
<input type='text' value='电脑'>
<script>
const uname = document.querySelector('input')
unmae.checked = true
</script>
4.自定义属性(h5新增)
(以前的getAttribute设置自定义属性不用了,可读性太差了)
- 在html5中推出专门的data- 自定义属性
- 在标签上一律以data开头
- 在DOM对象上一律以dataset对象方式获取
<div data-id="1" data-spm='x'>1</div>
<div data-id="2">2</div>
<div data-id="3">3</div>
<div data-id="4">4</div>
<script>
const one = document.querySelector('div')
console.log(one.dataset) //data属性集合
console.log(one.dataset.id) // 1
</script>
五、定时器-间歇函数
使用场景:
- 功能:每间隔一段时间需要自动执行一段代码,不需要手动去触发。
- 定时器有两种,此处介绍的是间歇函数。
1.开启定时器
语法:
setInterval(函数,间隔时间)
作用:每间隔一段时间就会调用一下这个函数(间隔时间的单位是毫秒)eg:
setInterval(function(){
console.log('你好')
},1000)
//或者分开写:
function fn(){
console.log('你好')
}
setInterval(fn,1000)
定时器一旦开启不会自己停下来,如果不用匿名函数,那么调用的时候括号里直接写函数名,后面不用加小括号。
定时器返回的是一个数字id(数字型)(定时器排号)。
2.关闭定时器
// 得先拿到定时器的id,存到n里
let n = setInterval(fn,1000)
//关闭定时器
clearInterval(n)
六、事件
1. 事件监听
事件监听就是让程序检测是否有事件的发生,一旦有事件触发,就立即调用一个函数做出响应,也称为绑定事件或注册事件。
事件监听三要素:
- 事件源:获取过来dom元素。
- 事件类型:比如click,mouseover…
- 事件调用函数:要做的事
<button>按钮</button>
<script>
const btn = document.querySelector('button')
btn.addEventListener('click',function(){ // 事件类型要用字符串
alert('点击了')
})
</script>
拓展——事件监听版本
以前的事件监听版本:
DOM L0: xxx.on事件 = function(){}
我们现在用的是L2,以前的L0会出现事件被覆盖的问题,L2不会。还有L0做不了事件捕获。
两种事件监听区别:
2. 事件类型
3. 事件对象
事件对象里有事件触发时的相关信息,比如当鼠标点击的时候,事件对象就存了鼠标点在哪个位置等信息。
应用场景:
- 可以判断用户按下了哪个按键。
- 可以判断鼠标点击了哪个元素,从而做出相应操作。
(1)如何获取事件对象
在事件绑定的回调函数的第一个参数就是事件对象,一般起名叫event或者e。
const btn = document.querySelector('button')
btn.addEventListen('click',function(e){
console.log(e)
})
(2)事件对象的常用属性
- type 获取当前的事件类型
- target 获取触发事件的对象——它的一个属性 tagName 可获取真正触发事件的元素名(大写,如“LI”,“P”)
- clientX / clientY 获取光标相对于浏览器可见窗口左上角的位置
- offsetX / offsetY 获取光标相对于当前DOM元素左上角的位置
- key 用户按下的键盘键的值(以前用keycode,已经废弃了,现在不用了)
4. 事件流
事件流指的是事件完整执行过程中的流动路径,第一阶段是捕获阶段(从大到小),第二阶段是冒泡阶段(从小到大)。
实际开发中大多数都是冒泡,很少用捕获。
(1)事件捕获
事件捕获需要写相应的代码,就是在之前提过的事件监听的基础之上,加一个参数:
DOM.addEventListener(事件类型,事件处理函数,是否使用捕获机制)
// addEventListener的第三个参数传入 true 代表的是捕获阶段去触发(很少使用)
// 若传入false 代表的就是冒泡阶段触发,如果不写第三个参数,默认就是冒泡。
ps:如果是DOM L0,则只有冒泡阶段,没有捕获。
(2)事件冒泡
当一个元素的事件被触发,会依次向上调用所有父级元素的同名事件。
事件冒泡是默认存在的,但是在很多情况下要阻止冒泡,阻止冒泡前提需要拿到事件对象。stopPropagation()
阻止冒泡方法
事件对象.stopPropagation()
这个方法可以阻断事件流的传播,在捕获阶段也有效。
div.addEventListener('click',function(e){
alert('你好')
// 阻止事件流传播
e.stopPropagation()
})
阻止元素默认行为
比如阻止链接的跳转,表单域的跳转等等。
事件对象.preventDefault()
<form action = "http://www.....">
<input type = 'submit' value = '免费注册'>
</form>
<script>
// 当信息有误的时候就要阻止提交
const form = document.querySelector('form')
form.addEventListen('submit',function(e){
e.preventDefault() // 阻止默认行为
})
</script>
5. 解绑事件(用的少)
对addEventListener解绑,需要使用removeEventListener(事件类型,事件处理函数,是否使用捕获机制)
需要注意的是,匿名函数是无法
function fn(){
console.log('你好')
}
// 绑定事件
btn.addEventListener('click',fn)
//解绑
btn.removeEventListener('click',fn)
扩展:鼠标经过事件
- mouseover 和 mouseout 会有冒泡效果。
- mouseenter 和mouseleave 没有冒泡效果(推荐)
6. 事件委托
事件委托是一种技巧,同时给多个元素注册事件。
原理是利用事件冒泡的特征解决的,优点是可以减少注册次数
- 给父元素注册事件,当触发子元素时候,会冒泡到父元素,从而触发父元素的事件。
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ul>
<script>
//要求点击li,当前的li文字变为红色,按事件委托方式
const ul = document.querySelector('ul')
ul.addEventListener('click',function(event){
if(event.target.tagName === 'LI'){
e.target.style.color = 'red'
}
})
// 一般都这么写,实在没懂先记下来。
</script>
7.其他事件
1.页面加载事件
(1) ‘load’
这个是等外部资源加载完毕时触发的事件(如图片、外联CSS、和 JavaScript)
window.addEventListener('load',function(){
............
})
不光可以监听整个页面资源加载完,也可以针对某个资源绑定加载事件,比如:
img.addEventListener('load',function(){
............
})
(2)‘DOMContentLoaded’
给document添加这个事件。这个是等DOM元素加载完就执行。
document.addEventListener('DOMContentLoaded',function(){
............
})
2.元素滚动事件
在滚动条滚动的时候触发。’scroll‘
// 监听整个页面滚动
window.addEventListener('scroll',function(){
............
})
如何知道页面滚动的距离?通过两个属性。
const div = document.querySelector('div')
div.addEventListen('scroll',function(){
console.log(div.scrollTop) // 查看被卷曲的头部距离,得到的是数字型的数据,不带单位。并且可读写
})
想知道整个页面滚动多少的话,需要找到html标签滚动距离
window.addEventListen('scroll',function(){
console.log(document.documentElement.scrollTop)
//这是一种固定语法,document.documentElement可以获取html标签。
})
3.页面尺寸事件
(1)'resize’事件
在浏览器窗口尺寸发生变化的时候触发事件。(了解即可)
window.addEventListen('resize',function(){
.......
})
(2)'client’属性
获取盒子可见部分的宽高(不包含边框、外边距和滚动条)clientWidth 和 clientHeight
const div = document.querySelector('div')
const.log(div.clientWidth)
(3)'offset’属性
offsetWidth 和 offsetHeight,和上面的client基本上一样。
二者区别:
- 这个offset获取的是包含边框的宽高(可视宽高,盒子隐藏了的话获取的是零)
- 这个offset是只读属性,不能改。
这个属性使用的时候有个前提,它获取的是自己定位父级的左、上距离。也就是说受父元素的影响。
七、环境对象this(重点)与回调函数
1. this
指的是函数内部的特殊变量 this ,它代表着当前函数运行时所处的环境。每个函数里面都有this。
粗俗一点理解,this指向的是函数的调用者,函数的调用方式不同,this指代的对象也不同。
2. 回调函数
如果将函数A作为参数传递给函数B时,我们就称A为回调函数。
例子:
function fn(){
console.log('我是回调函数')
}
setInterval(fn, 1000)
一般用匿名函数做回调函数比较常见。
八、节点操作
DOM树里的每个内容都称之为节点,包括元素节点、属性节点、文本节点。
1.查找节点
站在关系的角度去查找。
(1)父节点
parentNode 属性,返回的是最近一级的父节点(对象),(亲爸爸)
const div = document.querySelector('div')
console.log(div.parentNode)
(2)子节点
childNodes属性, 能获得所有的字节点,包括文本节点和注释节点(开发中很少用,了解即可)
children属性(重点),仅获得所有的元素节点(亲儿子)。
用法同上。
(3)兄弟节点
下一个兄弟节点: nextElementSibling属性
上一个兄弟节点:previousElementSibling属性
用法同上。
2.增加节点(重点)
很多情况下,需要在页面中增加元素,比如:点击发布按钮,可以新增一条信息。
那么新增节点一般分两步:
- 创建一个新节点。
- 把创建的新节点放入到指定的元素内部。
第一步、创建节点
document.createElement('div')
第二步、插入节点
- 插入到父元素的最后一个子元素:
父元素.appendChild(要插入的元素)
eg:
const li = document.createElement('li')
const ul = document.querySelector('ul')
li.innerHTML = '我是li'
ul.appendChild(li)
这样就把 li 塞进 ul 里了
- 插入到父元素中某个子元素的前面:
父元素.insetBefore(要插入的元素,在哪个元素前面)
eg:
const li = document.createElement('li')
const ul = document.querySelector('ul')
li.innerHTML = '我是li'
ul.insertBefore(li, ul.children[0]) //永远放在ul里的最前面,保证每次放入都在最前面
3.克隆节点
克隆一个已有的元素节点
元素.cloneNode(布尔值)
这个方法会克隆出一个跟原标签一样的元素,括号里放布尔值(默认是false)
当布尔值是 true 时,代表克隆的时候会包含后代节点一起克隆。(深克隆)
当布尔值是 false 时,代表克隆的时候不包含后代节点。
eg:
const ul = document.querySelector('ul')
const li1 = ul.children[0].cloneNode(true) // 把ul下的第一个li克隆出一份,然后传给li1
ul.appendChild(li1) //在ul最后面加上
4.删除节点
在js的原生DOM中,要删除元素必须通过父元素去删除!
如果父子关系不存在则删除不了,
删除和隐藏是不一样的,删除是在html中删除节点
父元素.removeChild(要删除的元素)
const ul = document.querySelector('ul')
ul.removeChild(ul.children[0]) //把ul下面的第一个li 给删了
九、移动端事件
主要是根据黑马pink老师的讲解和文档查询到的,说实话,不总用原生忘得太快了,忘记的时候查一下叭。