1. 认识DOM
文档对象模型(Document Object Model)
- 文档:一个页面就是一个文档,DOM中使用document表示
- 节点:页面中的所有内容,在文档树中都是节点(标签、属性、文本、注释等),使用node表示
- 标签节点:网页中所有的标签,通常称为元素节点,有简称为"元素",使用element表示
2. 获取元素
2.1 通过标签名获取
// get方式获取一组元素的都是伪数组
// 返回HTMLCollection,它是即时更新的,当其所包含的文档结构发生改变时,它会自动更新。
let lis = document.getElementsByTagName(tag)
2.2 通过ID获取
// 选择第一个匹配的元素
let div = document.getElementById(id)
2.3 通过类名获取
// 也是实时更新
let lis = document.getElementsByClassName(class)
2.4 H5新增的获取方式
// 选择第一个匹配的元素(css怎么获取它就怎么获取)
let div = document.querySelector(css选择器)
// 选择一组元素(类数组)
// 返回NodeList(静态的不会实时更新),它是H5以后新增的可以使用forEach去遍历
// 通过这种方式获取的才是静态的,但是通过实时更新的父元素点出来的孩子们,即使是NodeList也是实时的
let div = document.querySelectorAll(css选择器)
2.5 特殊元素的获取
// 获取 html 文档对象
document.documentElement
// 获取页面 title
document.title
// 获取 head 标签
document.head
// 获取 body 标签
document.body
3. 事件
3.1 事件三要素
- 事件源(谁要触发事件):触发事件的元素
- 事件类型(触发什么事件):例如 click 点击事件
- 事件处理程序(触发对应事件后要干什么):触发事件后执行的函数
3.2 事件类型
-
鼠标事件
// 1.鼠标左键按下(点击事件) btn.onclick = function(){} // 2.鼠标右键点击(在右键菜单显示前触发) contextmenu // 3.鼠标双击事件 dblclick // 4.鼠标按下事件 mousedown // 5.鼠标抬起事件 mouseup // 6.鼠标移入事件 mouseover // 7.鼠标移入事件(不冒泡,目标元素不冒给自己,其他元素的相同事件不会触发自己) mouseenter // 8.鼠标移动触发 mousemove // 9.鼠标移出事件 mouseout // 10.鼠标移出事件(不冒泡) mouseleave // 11.在鼠标上触发任意按钮触发 mouseup // 12.鼠标滚轮事件 wheel // 15.文档视图或者一个元素在滚动时触发,鼠标键盘都可以 scroll
-
表单事件
// 1.元素获得焦点 focus // 2.元素失去焦点 blur // 3.输入事件(每次输入都会触发) input // 4.当用户更改表单,并提交时触发 change // 5.剪切 cut // 6.拷贝 copy // 7.粘贴 paste
-
键盘事件
// 键盘按下,keyCode不区分字母大小写 keydown // 键盘按下(它不识别功能键 ctrl,shift等) keypress // 键盘抬起 keyup // 三个事件的执行顺序 keydown -- keypress -- keyup
-
移动端事件
// 手指触摸到一个DOM元素时触发(按下) touchstart // 手指在一个DOM元素上滑动时触发 touchmove // 手指从一个DOM元素上移开时触发(抬起) touchend
-
全局事件
// document开头的事件
3.3 注册事件
-
传统注册方式
- 利用 on 开头的事件 onclick
- 注册事件具有唯一性
- 同一个元素设置重复的事件,只会执行最后面的事件
-
监听注册方式
-
w3c 标准推荐方式
-
addEventListener() 它是一个方法,不需要加 on
-
IE9 之前的IE不支持此方法,可以使用attachEvent() 代替,需要加 on
-
同一个元素可以注册多个监听器,按注册顺序依次执行
element.addEventListener("click",funcion,事件流)
-
3.4 派发事件
- EventTarget.dispatchEvent(event):手动去派发事件
- 可以派发自定义事件,也可以派发原有事件(原有事件还可以正常使用)
- 必须要传入一个事件对象,可以通过 new Event(事件类型),创造一个自定义事件
3.5 删除事件
-
传统方式:element.onclick = null
-
监听方式:element.removeEventListener(“click”,function)
兼容性的删除方式:detachEvent(“onclick”,function)
这里的function必须和添加事件的function是同一个
3.6 事件流
- 在触发事件时会经历三个阶段
注意,事件流是元素父子关系(元素嵌套关系),而不是层叠关系
- 捕获阶段:document—Element html—Element body—Element div
- 目标对象:Element div
- 冒泡阶段:Element div—Element body—Element html—document
- 注意:捕获阶段不会触发事件,获取到目标对象后向上冒泡,才会触发父元素的事件
-
默认事件为冒泡事件(从内向外)
// addEventListener 一共有三个参数 element.addEventListener("click",funcion,事件流) // 事件流,默认为false,为事件冒泡(先执行自己的,在执行父元素的) // 如果为true,那么就为事件捕获(先执行父元素的,在执行自己的)
3.7 鼠标事件对象
在使用事件方法时,可以传入一个参数event(事件对象)
- event.type:返回事件类型
- event.target:返回目标对象
- event.currentTarget:返回注册事件的对象,不一定是目标事件,可能是冒泡的,等同于this
- event.preventDefault():阻止默认事件,比如a元素的跳转
- event.stopPropagation():阻止事件冒泡(都是给目标对象添加)
this与event.target的区别:this是函数调用者,event.target是目标对象(比如给ul添加事件使用this改变样式的话,只能改变ul的样式,用target的话点哪个li就只改变哪个li)
鼠标事件属性 | 说明 |
---|---|
event.clientX | 返回鼠标相对于浏览器窗口,可视区域的 X 坐标( 浏览器窗口 ) |
event.clientY | 返回鼠标相对于浏览器窗口,可视区域的 Y 坐标 |
event.pageX | 返回鼠标相对于文档页面 X 坐标,IE9+支持( 文档内容 ) |
event.pageY | 返回鼠标相对于文档页面 Y 坐标,IE9+支持 |
event.screenX | 返回鼠标相对于电脑屏幕的 X 坐标( 电脑屏幕 ) |
event.screenY | 返回鼠标相对于电脑屏幕的 Y 坐标 |
3.8 键盘事件对象
- keydown不区分大小写,keypress区分大小写( keyCode:编码 )
- 也可以通过 key 去判断按的什么键( key:字符串 )
3.9 触摸事件对象
触摸列表 | 说明 |
---|---|
touches | 正在触摸屏幕的所有手指的一个列表 |
targetTouches | 正在触摸当前DOM元素上的手指的一个列表 |
changedTouches | 手指状态发生了改变的列表,从无到有,从有到无变化 |
3.10 事件委托(事件代理)
事件委托是利用了事件冒泡的特征
还拿ul举例子,比如我想给ul下面很多个li标签添加事件,可以只给ul添加事件,就相当于利用冒泡的特性给每一个li都加了事件(这里要注意,目标对象的事件不一定是自己的事件,也可以是父元素给委托的事件)
4. 元素自定义属性
4.1 默认的自定义属性
// 获取标签结构中的自定义属性值,也可以获取标签自身的属性值
element.getAttribute("自定义属性名")
// 为标签添加(修改)自定义的属性名和属性值,有就修改,没有就添加
element.setAttribute("自定义属性名", "自定义属性值")
// 删除标签中的自定义属性
element.removeAttribute("自定义属性名")
4.2 h5新增的自定义属性
// 注意:设置的时候必须以 data-xxx的格式
// 所有以data-开头的属性都可以使用dataset去增删改查
// 获取
element.dataset.xxx
// 修改(添加)
element.dataset.xxx = value
// 删除
delete element.dataset.xxx
5. 节点操作
5.1 节点类型
- 元素节点,nodeType 为 1
- 属性节点,nodeType 为 2
- 文本节点,nodeType 为 3
- 注释节点,nodeType 为 8
- Document 节点,nodeType 为 9
- DocumentFragment 节点,nodeType 为 11
5.2 节点自身的信息
- nodeType:当前节点类型
- nodeValue:节点文本内容
- nodeName:ele节点标签,会返回大写的
5.3 获取父元素
- parentElement:父元素
- parentNode:父元素节点
5.4 获取子元素
- children:子元素(元素)
- childNodes:子元素节点(包括元素、属性、文本、注释等)
- firstChild:获取第一个子元素节点
- firstElementChild:获取第一个子元素
- lastChild:获取最后一个子元素节点
- lastElementChild:获取最后一个子元素
5.5 获取兄弟元素
- nextSibling:获取下一个兄弟节点
- previousSibling:获取上一个兄弟节点
- nextElementSibling:获取下一个兄弟元素(H5新增)
- previousElementSibling:获取上一个兄弟元素(H5新增)
5.6 添加节点对象
-
创建(三种方式)
// 创建节点对象(这个时候还没上树) document.createELement("标签名") // 创建文档片段,会创建一个空白的文档,可以用来装载元素 document.createDocumentFragment() // 会覆盖node中原有的内容 // innerText和innerHTML差不多,只是innerText不能识别标签 // textContent和outerHTML和上面两个都是差不多的,textContent兼容性好一些 node.innerHTML = 标签内容 // 对整个页面进行重绘 document.write(标签内容)
-
追加
// 追加节点对象(上树) parentNode.append("元素对象或字符串") // 如果是字符串就是添加文本节点 parentNode.appendChild("元素对象") // 只能是元素对象 parentNode.prepend() // 和 append 一样不过是添加到最前面
-
插入
// 第一种 // 插入指定元素之前(上树) parentNode.insertBefore(ele,指定元素)
// 第二种 // 这个方法不会覆盖之前的html内容 // position,有四个参数 // 'beforebegin':元素自身的前面。 // 'afterbegin':插入元素内部的第一个子节点之前。 // 'beforeend':插入元素内部的最后一个子节点之后。 // 'afterend':元素自身的后面。 // text:要插入的HTML元素 // 这三个的插入方法都是差不多的 // 使用 insertAdjacentHTML 插入用户输入的HTML内容的时候,需要转义之后才能使用 element.insertAdjacentHTML(position, text); // 插入的元素 element.insertAdjacentElement(position, element); // 插入的文本 element.insertAdjacentText(position, text);
<!-- 这里的p标签是目标元素 --> <!-- beforebegin --> <p> <!-- afterbegin --> foo <!-- beforeend --> </p> <!-- afterend -->
// 第三种 // 插入当前目标元素之前或之后 element.before("元素对象或字符串") element.after("元素对象或字符串")
5.7 删除节点
- parentNode.removeChild(“指定元素”):返回被删除的节点
- node.remove():删除当前元素,不会返回
5.8 克隆节点
// 当为true时为深层克隆,克隆当前节点和子节点,并返回克隆的节点
node.cloneNode(true)
// 当为false时为浅层克隆,只克隆当前节点(标签、属性和类名)
node.cloneNode(false)
5.9 替换节点
Node.replaceChild(newChild, oldChild)
5.10 移动节点
// externalNode:需要提取的节点
// 然后把 node 插入到新的位置
node = document.adoptNode(externalNode);
6. 获取元素属性
6.1 偏移量 offset
offset 翻译过来就是偏移量, 我们使用 offset系列相关属性可以动态的得到该元素的位置( 偏移 )、大小等。
- 获得元素距离带有定位父元素的位置
- 获得元素自身的大小(宽度高度)
- 注意:返回的数值都不带单位
offset系列属性 | 作用 |
---|---|
ele.offsetParent | 返回具有定位元素的父级元素,如果上层一直没有则返回body |
ele.offsetTop | 返回元素相对带有定位父元素上方的偏移,子border到父border |
ele.offsetLeft | 返回元素相对带有定位父元素左方的偏移,如果没有就是body |
ele.offsetWidth | 返回自身content+padding+border的宽度,返回值不带单位 |
ele.offsetHeight | 返回自身content+padding+border的高度,返回值不带单位 |
6.2 offset 与 style 区别
6.2.1 offset
- offset 可以得到任意样式表中的样式值
- offset 系列获得的数值是没有单位的
- offsetWidth 包含padding+border+width
- offsetWidth 等属性是只读属性,只能获取不能赋值
- 所以,我们想要获取元素大小位置,用offset更合适
6.2.2 style
- style 只能得到行内样式表中的样式值
- style.width 获得的是带有单位的字符串
- style.width 获得不包含padding和border 的值
- style.width 是可读写属性,可以获取也可以赋值
- 所以,我们想要给元素更改值,则需要用style改变
6.3 元素可视区 client
client 翻译过来就是客户端,我们使用 client 系列的相关属性来获取元素可视区的相关信息。通过 client 系列的相关属性可以动态的得到该元素的边框大小、元素大小等。
client系列属性 | 作用 |
---|---|
ele.clientTop | 返回该元素上边框的大小 |
ele.clientLeft | 返回该元素左边框的大小 |
ele.clientWidth | 返回自身content+padding的宽度,返回值不带单位 |
ele.clientHeight | 返回自身content+padding的宽度,返回值不带单位 |
6.4 元素滚动 scroll
scroll 翻译过来就是滚动的,我们使用 scroll 系列的相关属性可以动态的得到该元素的大小、滚动距离等。
scroll系列属性 | 作用 |
---|---|
ele.scrollTop | 返回自身被卷去上侧的距离 |
ele.scrollLeft | 返回自身被卷去左侧的距离 |
ele.scrollWidth | 返回自身content的宽度 |
ele.scrollHeight | 返回自身content的高度 |
ele.scrollTo(x,y),手动滚动dom元素
7. 操作css
7.1 类名与ID
// 像类名与ID直接元素点就可以使用,一般其他的样式要style点才可以
// 类名
className // 返回类名,可读可写
classList // 将属性作为列表来返回
/*
classList 可以使用
add(class):添加类名
remove(class):删除类名
toggle(class):切换类名,如果有类名删除没有就添加
contains(class):判断是否存在类名,返回布尔值
*/
// ID
id // 返回id,可读可写
7.2 行内样式
// 1. 通过属性修改
// 上面说到 DOM 提供的有很多获取元素宽高等一些属性
// 但是 style 可以获取行内样式,也可以添加行内样式
// background-color:像这种样式需要转为大驼峰
element.style.backgroundColor = "red" // 可读可写
// 2. 通过 API 修改
/*
propertyName:需要添加或修改的属性,有则修改无则添加,和 css 一样写法
value(可选):需要修改或填的属性值,如果不填为空
priority(可选):设置 css 优先级 "important"
css 变量通过 js 去设置,需要使用这种方式,直接 style 点不行
*/
element.style.setProperty(propertyName, [value], [priority]);
7.3 全部样式
<div class="box"></div>
<script>
// 获取box元素
let box = document.querySelector(".box")
// 获取box的全部样式(计算后的样式)
let boxStyle = window.getComputedStyle(box)
// 获取box伪元素的全部样式
let afterStyle = window.getComputedStyle(box, "::after")
// 这种方式是只读的
</script>