js中最重要的就是对DOM的操作

要想操作DOM,我们先理解以下几个名称的意思

  1. 元素就是标签,只是叫法不同;< p >可以称为p标签,也可以叫p元素
  2. 节点包括元素和文本;通俗的来说:p标签和它里面的文字,合一块叫做节点

操作DOM元素就是对节点的增删改查

什么是 DOM?

DOM就是文档对象模型 ,一个网页就可以看作一个文档

DOM 将文档解析为一个由节点和对象(包含属性和方法的对象)组成的结构集合;它提供了对文档的结构化的表述,并定义了一种方式可以使从程序中对该结构进行访问,从而改变文档的结构,样式和内容。

获取元素的几种方式

  1. <p id="p1" class="p2">Hello World!</p>
  2. //获取p元素的几种方式
  3. document.getElementById("p1") :根据ID查找元素,大小写敏感,如果有多个结果,只返回第一个;
  4. document.getElementsByClassName("p2") :根据类名查找元素,多个类名用空格分隔,返回一个数组
  5. document.getElementsByTagName("p") :根据标签查找元素, * 表示查询所有标签,返回一个 HTMLCollection
  6. document.getElementsByName :根据元素的name属性查找,返回一个 NodeList
  7. document.querySelector("#p1") :括号里面是#id名或者.class名;返回单个NodeIE8+(含),如果匹配到多个结果,只返回第一个。
  8. document.querySelectorAll() :返回一个 NodeList IE8+(含)。

这就是打印出来的元素
DOM操作 - 图1

操作DOM

创建元素

创建一个节点,并把它添加到页面中

  1. //创建一个标签
  2. let div1 = document.createElement('div')
  3. //创建一个文本节点
  4. text1 = document.createTextNode('你好')
  5. //把文本插入标签节点
  6. div1.appendChild(txet1)

你创建的标签默认处于JS线程中
你必须把它插到head或者body里面,它才会生效

  1. document.body.appendChild('div1')

或者插入已在页面中的元素

  1. 已在页面中的元素.appendChild('div1')

同一个标签不能同时插入到两个页面标签里,如果想同时存在,需要克隆
参数为true时是深拷贝,会把div1里的所有后代全都复制一遍
不写默认是浅拷贝,只复制此节点

  1. let div2 = div1.cloneNode(true)

删除

删除有两种方法
新方法

  1. 父元素.childChild(子元素)

老方法

  1. 要移除的元素.remove()

修改属性

  1. 写标准属性
  2. classdiv.className ='red blue'(全覆盖)
  3. classdiv.classList.add'red'
  4. stylediv.style ='width100pxcolorblue
  5. style的一部分:div.style.width ='200px'
  6. 大小写:div.style.backgroundColor ='white'
  7. data-*属性:div.dataset.x ="dong"
  8. 读标准属性
  9. div.classList/a.href
  10. div.getAttribute('class')/a.getAttribute'href'
  11. 两种方法都可以,但值可能稍微有些不同

改内容

  1. 改文本内容
  2. div.innerText ='xxx'
  3. div.textContent='xxx'
  4. 两者几乎没有区别
  5. HTML内容
  6. div.innerHTML='<strong>重要内容</strong>'
  7. 改标签
  8. div.innerHTML="//先清空
  9. div.appendChild(div2)//再加内容

标签.childNodes.length 是计算标签的子元素的(回车也算)
标签.children.length 是计算子元素(不含回车)

  1. 查爸爸
  2. node.parentNode 或者node.parentElement
  3. 查爷爷
  4. node.parentNode.parentNode
  5. 查子代
  6. node.childNodes或者node.children
  7. 查兄弟姐妹
  8. node.parentNode.childNodes还要排除自己
  9. node.parentNode.children还有排除自己

遍历一个div里所有的元素

  1. travel = (node, fn) =>{
  2. fn(node)
  3. if(node.children){
  4. for(let i=0; node.children.length;i++){
  5. travel(node.children[i], fn)
  6. }
  7. }
  8. }
  9. travel(div1, (node) => console.log(node))

DOM捕获阶段和冒泡阶段

DOM事件流:事件流描述的是从页面中接收事件的顺序。(事件传播的过程就是事件流)

包括三个阶段:
事件捕获阶段:该阶段的主要作用是捕获截取事件
处于目标阶段:一般地,该阶段具有双重范围,即捕获阶段的结束,冒泡阶段的开始;
事件冒泡阶段:主要作用是将目标元素绑定事件执行的结果返回给浏览器,处理不同浏览器之间的差异,主要在该阶段完成


捕获 当用户点击按钮,浏览器会从 window 从上向下遍历至用户点击的按钮,逐个触发事件处理函数。

冒泡 浏览器从用户点击的按钮从下往上遍历至 window,逐个触发事件处理函数。

DOM操作 - 图2

什么是捕获阶段?

当监听事件 addEventLister 的第三个参数为true则处于捕获阶段

事件捕获阶段:如果上级有事件,则就会执行先执行上级的事件,再执行点击事件(执行顺序为:爷爷事件——>爸爸事件——>儿子事件)

什么是冒泡阶段?

第三个参数不填或为false

事件冒泡阶段:先执行被点击的元素事件,再一层一层执行上级事件(执行顺序为:被点击事件——>爸爸事件——>爷爷事件)

是想执行冒泡阶段和还是捕获阶段?

  1. //IE浏览器是执行冒泡阶段
  2. IE5*:baba.attachEvent'onclick'fn
  3. //捕获
  4. 网景:baba.addEventListener'click'fn
  5. //现在都使用w3c的标准,由第三个参数控制冒泡还是捕获,不填或者false就是冒泡阶段
  6. W3Cbaba.addEventListener'click;,fn,bool)

阻止冒泡的方法

使用 e.stopPropagation() 可以中断冒泡

但是有些事件此方法没有效果,比如说 scroll滚动事件

阻止滚动事件的方法

阻止scroll默认动作没有用,因为有滚动才有滚动事件,要想阻止滚动,需要阻止whell和touchstart的默认动作

禁用滚动事件

  1. 元素.addEventListener('whell',(e)=>{
  2. e.preventDefault()
  3. })

此时使用鼠标滚轮没有用了,但是还有滚动条
把滚动条隐藏

  1. ::-webkit-scrollbar {
  2. width: 0 !important
  3. }

禁用手机端的滚动事件

  1. 元素.addEventListener('touchstart',(e)=>{
  2. e.preventDefault()
  3. })

事件委托

当监听子元素时,事件冒泡会通过目标元素向上传递到父级,直到document,如果子元素不确定或者动态生成,可以通过监听父元素来取代监听子元素。

  1. function on(eventType, element, selector, fn) {
  2. if (!(element instanceof Element)) {
  3. element = document.querySelector(element)
  4. }
  5. element = addEventListener(eventType, (e) => {
  6. const t = e.target
  7. if (t.matches(selector)) {
  8. fn(e)
  9. }
  10. })
  11. }
  12. on('click', '#div1', 'button', () => {
  13. console.log('buton被点击了')
  14. })

target与currentTarget

e 会在事件结束之后自动消亡,如果在setTimeout定时操作里使用e,则会报错:如下代码则会报错

  1. x1.addEventListener('click', (e) => {
  2. setTimeout(() => {
  3. e.currentTarget.classList.remove('x')
  4. }, 1000)
  5. })

解决方法:就是把e记下来

  1. x1.addEventListener('click', (e) => {
  2. const t = e.currentTarget
  3. setTimeout(() => {
  4. t.classList.remove('x')
  5. }, 1000)
  6. })

target是被操作(被点击)的元素

currentTarget是程序员监听的元素