JavaScript之DOM(1)

383 阅读5分钟

之前已经有了很多JS知识的铺垫,此时,针对之前的HTML,我们开始DOM的学习。

DOM树

前面已经说过,HTML其实是以树状结构分布的,而JS自然对这一点很好的做了一次利用,用document对HTML形成的网页树状结构进行操作,这个操作提供的一系列API就叫做DOM。全称是document Object Model。这是对应的DOM树的图形结构

<html lang="en">
<head>
	<title>文档标题</title>
</head>
<body>
	<a href="">我的文本链接</a>
    <h1>我的标题</h1>
</body>

但是DOM很难记很难用,所以这篇文章主要注重一个DOM的方法的总结,实际开发中并不使用(事实上很多DOM的操作都用jQuery来代替了)。

DOM获取元素

首先,DOM如何获取元素:

老三招:
document.getElementById('xxx')
document.getElementsByTagName('div')
document.getElementsByClassName('red')
新时代的三招:
HTML上写好id="xxx",然后JS里面直接用xxx.起手就好了
document.querySelector('#xxx')
document.querySelectorAll('#xxx')[0]

工作中如果有要用DOM的地方,请果断新三招,但是第一招最好自己调试的时候用,被人看到了会疑惑的(老师说的,错了别怪我),如果要兼容IE,对不起,老老实实老三招。
但是!!!,对一些特别的元素,DOM有它特定的方法,这也是DOM比较难用的地方,因为老是要忘记。

获取html
document.documenetElement
获取head
document.head
获取body
document.body
获取窗口
window

特别的,任何浏览器都有一个document.all的方法,但是这个IE的表现情况和其他浏览器不同
IE的表现 非IE的表现 很奇怪是吧,但是这是真的,所以用这个就能判断这个浏览器是不是IE啦! 最后,讲一下document获取到的元素是什么吧。 在控制台打印一个试试,发现有个原型,再点开它的原型,发现是,这样一层层的下去,依次是,最后终于找到了它的原型链的根源.所以针对上面的,我做了个原型链的图:

  • 依次对每一层原型做一个概述
    • 第一层原型:HTMLDivElement.prototype 这是所有的div的共有属性,不用细看
    • 第二层原型:HTMLElement 这是所有的HTML的共有属性,也不用细看
    • 第三层原型Element.prototype 这里面是所有XML,HTML标签等的共有属性。 在这里主要对属性的操作的方法有:
      getAttribute/setAttribute, removeAttribute, querySelector/querySelector, scrollBy/scrollTo
    • 第四层原型是Node.prototype 这里面是所有节点共有属性,节点包括: appendChild, removeChild, replaceChild, cloneNode, contains, insertBefore
    • 第五层的原型是EventTarget addEventListener,removeEventlistener,dispatchEvent 这里面最重要的是addEventListener
    • 最后的Object那就看原型链去吧 所以,彻底明白了吧,所有的DOM元素,其实就是一堆原型链链接的Object而已。
      得到的元素都有自己的属性,可以用nodeType来查看得到的属性的值。这边只要记住两个,nodeType为1表示是Element,3表示是Text
      这是实际操作的代码

节点的增删改查

  • 创建一个标签节点
    • document.createElement('style')
    • document.createElement('script')
    • document.createElement('li')
  • 创建一个文本节点
    • text = document.createTextNode('你好')
  • 标签里面插入文本
    • appendChild(text)
    • innerHTML或者textContent(注意这个方法的性能,当innerHMTL过多的时候,页面会卡顿)
  • 在页面中插入
    • 首先在JS线程中创建标签
    • 必须把它插入到head或者body中,它才能生效
    • 方法还是appendChild
注意,appendChild,如果对同一个标签,插入两个一样的div,那么效果是插入到你最后加的元素内
html:
 <div id="div1"></div>
  <div id="div2"></div>
css:
#div1{
  height: 100px;
  width:100px;
  background-color: red;
}
#div2{
  background-color: yellow;
   height: 100px;
  width:100px
}
JavaScript:
let div = document.createElement("div");
div.innerHTML = "nihao"
div1.appendChild(div);
div2.appendChild(div);


请看此时,新创建的div只出现在div2中,而没有出现在div1中,虽然div1同样增加了一个div。

  • 下列是删除的方法:
    • 删除自己的子节点:parenetNode.removeChild(childNode)
    • 删除本节点:selfNode.remove()
    • 删除本身的属性:selfNode.removeAttribute() 此时,当我们删除节点上本身的子节点的时候,不会造成JS内创建的子节点的消失。
JavaScript:
    +	div2.removeChild(divNew)
    +   console.log(divNew)

  • class
    • 改clss:div.className = "red blue";
    • 改class:div.classList.add('red')
    • 改style:div.style='width:100px'
    • 改style的一部分:div.style.width='200px',这个改动的时候,有时候要注意大小写,比如style.backgroundColor
    • 改data-*属性:div.dataset.x='xiaoznz'
      事件的处理函数
  1. 默认点击div不会有任何事情发生,很多事件的处理函数默认值都是null.
  2. 当我们对事件处理函数进行赋值函数的时候,就是将这个函数的地址值传给了事件处理函数。
  3. 当事件被触发的时候,浏览器就会调用这个函数,此时默认浏览器会给函数传一个this,this就是绑定函数的本身DOM元素。
  4. 然后浏览器会给这个函数传一个event的参数,它包含了点击时间的所有信息,比如坐标
  • 有两种给事件处理函数赋值的方法:
    • div.onclick
    • div.addEventListener('type','options','useCapture') 对应这个,type是绑定的实践类型,options传定义的方法以及其他参数信息,useCaoture用于事件冒泡
      HTML内容的修改: 修改文本的内容 div.innerText = 'xxx', div.textContent = 'xxx'
      这两个之前说过了,就跟之前一样

  • HTML
    • 父类 node.parentNode或者node.parentElement
    • 爷爷 node.parentNode.parenetNode
    • 查子代 node.childNodes或者node.children 对childNodes来说,这个得到一堆子节点,包括文本节点 对children来说,只得到他对应HTML的三个子节点
    • 查兄弟姐妹 嵌套之前的得到父类和子代就可以了
    • 查看大孩子,最小的孩子 node.firstChild,node.lastChild
    • 查看上一个下一个节点 node.previousSibling,node.nextSibling
    • 查看类: div.classList,div.getAttribute('class'),div.className
    这边有个坑,就是a.href。如果不一般的,我们去取a.href,会得到一个完整的基于你的根路径的链接,但是很可能你的链接内容并不是这么写的
    
    最后因为DOM是一棵树,所以我们用遍历二叉树的方法来写一个遍历DOM的算法吧
    foreach = (node)=>{
            console.log(node)
            if (node.children){
                for (let i = 0; i < node.children.length; i++) {
                    foreach(node.children[i])
                }
            }
        }
        foreach(main)