DOM节点介绍

371 阅读12分钟
1.什么是节点:
HTML文档中,一切皆节点(HTML文档本身、标签、属性、注释内容、文本)
2.什么是元素:
元素在HTML中叫做标签,在JS的dom对象中称为元素(可以理解为标签的面向对象的叫法)
3.HTML标签属于节点的一种,叫做元素节点
4.节点三要素:
1.   节点类型:元素、属性、注释、文本
2.   节点名称:p、div、class(标签名)
3.   节点的值:one(属性的值

<body>
 <ul>
    <!-- 我是注释哟 -->
     我是文本哈
    <li>我是班长1</li>
    <li>我是班长2</li>
    <li>我是班长3</li>
    <li>我是班长4</li>
    <li>我是班长5</li>
  </ul>

 <script>
    /* 学习目标: 查询节点
        1.获取子元素 :  元素.children
        2.获取兄弟元素
        3.获取父元素
       */
     //获取元素
    let ul = document.querySelector('ul')
    //获取子节点:元素节点,文本节点,注释节点
    console.log(ul.childNodes); //13个
    //获取子元素:元素节点
    console.log(ul.children) //5个li元素
  </script>

5.兄弟节点

    查询节点
      1.获取兄弟元素 : 
        获取上一次元素 : 元素.previousElementSibling
        获取下一次元素 : 元素.nextElementSibling
     获取元素
     <body>
       <button class="btn">点我操作li2的兄弟节点</button>
<ul>
  <li>我是班长1</li>
  <li id="li2">我是班长2</li>
  <li>我是班长3</li>
  <li>我是班长4</li>
  <li>我是班长5</li>
</ul>
 <script>
      let li2 = document.querySelector('#li2')
     document.querySelector('.btn').onclick = function () {
    //兄弟元素 : 元素节点
    //1 上一个兄弟元素
    console.log(li2.previousElementSibling) //班长1
    li2.previousElementSibling.style.color = 'red'
    //2 下一个兄弟元素
    console.log(li2.nextElementSibling) //班长3
    li2.nextElementSibling.style.color = 'red'
  }
 </script>
 

image.png

image.png

6. 子节点

        1.获取子节点 :  父元素.childNodes
        2.获取子元素节点(重点):   父元素.children
         <ul>
             我是文本哈
           <li>我是班长1</li>
           <li>我是班长2</li>
           <li>我是班长3</li>
           <li>我是班长4</li>
           <li>我是班长5</li>
        </ul>
      <script>
      let ul = document.querySelector('ul')
      //1.获取子节点 : 文本节点 、 注释节点 、 元素节点
       console.log(ul.childNodes) //13  标签之间的换行也算空文本节点
      //2.获取子元素 : 元素节点
       console.log(ul.children) //仅获得5个元素节点
      </script>

7.父节点

        学习目标: 获取父节点 
        子元素.parentNode
<body>
<ul>
  <li>我是班长1</li>
  <li id="li2">我是班长2</li>
  <li>我是班长3</li>
  <li>我是班长4</li>
  <li>我是班长5</li>
</ul>
 <script>
   let li2 = document.querySelector('#li2')
   console.log(li2.parentNode) //ul
   console.log(li2.parentNode.parentNode) //body
   console.log(li2.parentNode.parentNode.parentNode) //html
   console.log(li2.parentNode.parentNode.parentNode.parentNode) //document 
   console.log(li2.parentNode.parentNode.parentNode.parentNode.parentNode) //null
</script>
 </body>
 

8.新增节点

    <body>
    <button class="btn1">添加到最后面</button>
    <button class="btn2">添加到li2前面</button>
    <button class="btn3">添加到最前面</button>
 <ul>
     <li>我是班长1</li>
     <li id="li2">我是班长2</li>
     <li>我是班长3</li>
     <li>我是班长4</li>
     <li>我是班长5</li>
</ul>

<script>
/* 
1.介绍dom中新增元素有三种语法
  1.1 document.write( '字符串' )   : 几乎不用.(可能会覆盖原来的内容)
  1.2 元素.innerHTML  :  少用(使用的时候会有性能问题,低于100个元素就可以使用)
        覆盖操作:   元素.innerHTML = '字符串'
        新增操作:   元素.innerHTML += '字符串'
  1.3 元素.createElement() : dom推荐

2. 重点掌握 createElement三个流程
  (1)在内存中 创建 空标签:  let newLi = document.createElement('标签名')
  (2)设置标签内容
  (3)添加到dom树  :  父元素.appendChild(子元素)

3. 元素添加到最后面 与 最前面
  添加到最后面:   父元素.appendChild(子元素)
  添加到元素前面: 父元素.insertBefore(子元素, 哪个元素前面 )
*/

//获取元素
   let ul = document.querySelector('ul')
   let li2 = document.querySelector('#li2')

//覆盖
  // ul.innerHTML = `<li>我是新来的</li>`
//不覆盖:拼接
  // ul.innerHTML += `<li>我是新来的</li>`

/* ***   重点掌握 createElement三个流程     */

//(1)在内存 创建一个 空标签
let newLi = document.createElement('li')
//(2)设置样式和内容
newLi.innerText = '我是新来的'
console.log(newLi)
//(3)添加到dom树:  父元素.appendChild(子元素)
// ul.appendChild(newLi)


//添加到最后面
document.querySelector('.btn1').onclick = function () { 
  //添加到最后面:   父元素.appendChild(子元素)
  ul.appendChild(newLi)
}
//添加到li2的前面
document.querySelector('.btn2').onclick = function () {
  //添加到元素前面: 父元素.insertBefore(子元素, 哪个元素前面 )
  ul.insertBefore(newLi,li2)
}
//添加到最前面
document.querySelector('.btn3').onclick = function () { 
  //把元素 添加到 第一个儿子 前面
  ul.insertBefore(newLi, ul.children[0] )
}
</script>

image.png

9. 克隆节点

        克隆节点
             ul.cloneNode(布尔类型)
            默认false:不克隆后代节点
            true:克隆后代节点
       .box{
            width: 300px;
            height: 100px;
            border: 1px solid pink;
             margin-top: 10px;
           }
     </style>
         <button class="btn">点我克隆节点</button>
           <div class="box">
         <a href="我是链接"></a>
         <p>我是p标签</p>
     <ul>
          <li>我是ikun1</li>
          <li>我是ikun2</li>
     </ul>
   </div>
    let box = document.querySelector('.box')	
    document.querySelector('.btn').onclick = function(){
        //克隆节点  false:不克隆后代节点  true:克隆后代节点
        let newBox = box.cloneNode(true)
        document.body.appendChild(newBox)
    }
    

image.png

10. 删除节点

        语法: 父元素.removeChild(子元素) 
删除节点注意事项: 删除节点一定是父子关系才能删除,比如ul和li
        <button class="btn">点我删除节点</button>
    <ul>
       <li>我是班长1</li>
       <li id="li2">我是班长2</li>
       <li>我是班长3</li>
       <li>我是班长4</li>
       <li>我是班长5</li>
   </ul>
   <script>
      document.querySelector('.btn').onclick = function () {
        //父元素
        let ul = document.querySelector('ul')
        //子元素
        let li2 = document.querySelector('#li2')

        //移除子元素: 父元素.removeChild(子元素)
        ul.removeChild(li2)
     }
   </script>
   

image.png

display = 'none'和removeChild的区别

display = 'none'只是修改样式,把元素隐藏起来,标签还在document树里面
removeChil是直接删除标签

image.png

11.内置对象Date: 日期对象

      1.创建日期对象    
        let d = new Date()
        console.log(d)

      2.转换日期格式
        console.log( d.toLocaleString() )//2022/1/18 下午3:02:53
        console.log( d.toLocaleDateString() )//2022/1/18
        console.log( d.toLocaleTimeString() )//下午3:03:29

      3.获取 年月日时分秒
        console.log( d.getFullYear() )//2022
         范围下标 0-11 对应 1-12月
        console.log( d.getMonth() )//0 下标  第1个月
        console.log( d.getDate() )//18
         星期下标 0-6 对应 周日-周六
        console.log( d.getDay() )//2
        console.log( d.getHours() )//15
        console.log( d.getMinutes() )//5
        console.log( d.getSeconds() )//44

      4.获取时间戳  : 返回从197011日零点 到此时此刻的 毫秒数
        时间戳作用 : 解决地球不同地区时差问题    
        UTC时区:全球时区   GMT时区:东8区
       console.log( Date.now() )//1642489697575
       console.log( +new Date() )//1642489741950
       console.log( new Date().getTime() )//1642489741950

12. 定时器

12.1-setInterval永久定时器
     1.定时器作用 : 一段代码 间隔时间 重复执行
     2.定时器语法 :
       2.1 setInterval : 永久定时器。 一旦开启,永久重复执行,只能手动清除
        开启:   let timeID = setInterval( function(){} , 间隔时间 )
        关闭:   clearInterval(timeID)
  * @description: 开启定时器
  * @param {function} 一段代码
    * 回调函数 : 如果一个函数的参数也是函数,这个参数函数就叫做回调函数   
  * @param {number} 间隔时间  单位毫秒  1s = 1000ms
  * @return: 定时器id
    * 一个页面可以开启很多定时器,浏览器为了更好管理这些定时器。
    会给每一个定时器一个编号。称之为定时器id    
 <body>
    <button class="btn">移除定时器</button>
    <p id="pp">0</p>
  <script>
       let pp = document.querySelector('#pp')
       
       let timeID =  setInterval( function(){       
        pp.innerText++
        或//pp.innerText = Number( pp.innerText ) + 1
      } ,1000 )
   //点击按钮:关闭定时器
   document.querySelector('.btn').onclick = function(){
    //参数: 定时器id
    clearInterval(timeID)
      }
  </script> 
 </body>
 
 

image.png

12.2-setTimeout一次定时器
    1.定时器作用 : 一段代码 间隔时间 重复执行
    2.定时器语法 :
     2.1 永久定时器 : 一旦开启, 间隔时间永久执行。只能手动清除
         开启:   let timeID = setInterval( function(){} , 间隔时间 )
         关闭:   clearInterval(timeID)
     2.2 一次定时器 : 间隔时间内,只会执行一次。执行完毕后自动清除。
         开启:   let timeID = setTimeout( function(){}, 间隔时间 )
         关闭 :  clearTimeout(timeID)
注:一次定时器如果要关闭,只有在规定时间内关闭才有效果.
例如,下面的定时器只有在5秒内点击 ''移除定时器''才能清除定时器,不让0加1
  * @description: 开启定时器
  * @param {function} 一段代码
    * 回调函数 : 如果一个函数的参数也是函数,这个参数函数就叫做回调函数   
  * @param {number} 间隔时间  单位毫秒  1s = 1000ms
  * @return: 定时器id
    * 一个页面可以开启很多定时器,浏览器为了更好管理这些定时器。
    会给每一个定时器一个编号。称之为定时器id 
 <body>
     <button class="btn">移除定时器</button>
     <p id="pp">0</p>
  <script>
         let timeID = setTimeout( function(){
         document.querySelector('#pp').innerText++
         } , 5000 )
        //点击按钮:关闭定时器
        document.querySelector('.btn').onclick = function(){
        //参数: 定时器id
        clearTimeout(timeID)
        }
</script>
</body>

13.setInterval案例:电商秒杀

   <style>
      span {
            display: inline-block;
            width: 30px;
            height: 30px;
            background-color: #000;
            color: #fff;
            font-size: 22px;
            text-align: center;
            line-height: 30px;
           }
  </style>
 </head>
<body>
  <div>
         <span id="hour">00</span> : <span id="minute">00</span> :
         <span id="second">05</span>
  </div>
 <script>
/* 
   开启永久定时器,间隔时间1s
  (1)获取 时h  分m  秒s 文本innerText
  (2)s--
  (3)如果 s < 0 :  s = 59 , m--
  (4)如果 m < 0 :  m = 59, h--
  (5)如果 m h s 小于10,则补0
  (6)将计算之后的h m s 重新赋值给页面元素innerText
  (7)如果 h == 0 && m == 0 && s == 0 , 则清除定时器
*/
     let timeID = setInterval(function () {
     //(1)获取 时h  分m  秒s 文本innerText
     let h = +document.querySelector('#hour').innerText
     let m = +document.querySelector('#minute').innerText
     let s = +document.querySelector('#second').innerText
     //(2)s--
        s--
     //(3)如果 s < 0 :  s = 59 , m--
     if (s < 0) {
        s = 59
        m--
     }
      //(4)如果 m < 0 :  m = 59, h--
       if( m < 0 ){
        m = 59
        h--
     }
  //(5)如果 m h s 小于10,则补0
      s = s < 10 ? '0' + s : s
      m = m < 10 ? '0' + m : m
      h = h < 10 ? '0' + h : h
  //(6)将计算之后的h m s 重新赋值给页面元素innerText
    document.querySelector('#hour').innerText = h
    document.querySelector('#minute').innerText = m
    document.querySelector('#second').innerText = s
  //(7)如果 h == 0 && m == 0 && s == 0 , 则清除定时器
      if( h == 0 && m == 0 && s == 0){
      clearInterval(timeID)
  }
}, 1000)
 </script>
 </body>
 


image.png

image.png

image.png

14.小米搜索框案例:

      <style>
  * {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
  }

  ul {
    list-style: none;
  }

  .mi {
    position: relative;
    width: 223px;
    margin: 100px auto;
  }

  .mi input {
    width: 223px;
    height: 48px;
    padding: 0 10px;
    font-size: 14px;
    line-height: 48px;
    border: 1px solid #e0e0e0;
    outline: none;
    transition: all 0.3s;
  }

  .mi .search {
    border: 1px solid #ff6700;
  }

  .result-list {
    display: none;
    position: absolute;
    left: 0;
    top: 48px;
    width: 223px;
    border: 1px solid #ff6700;
    border-top: 0;
    background: #fff;
  }

  .result-list a {
    display: block;
    padding: 6px 15px;
    font-size: 12px;
    color: #424242;
    text-decoration: none;
  }

  .result-list a:hover {
    background-color: #eee;
  }
</style>
</head>

<body>
<div class="mi">
  <input type="search" placeholder="小米笔记本" />
  <ul class="result-list">
    <li><a href="#">全部商品</a></li>
    <li><a href="#">小米11</a></li>
    <li><a href="#">小米10S</a></li>
    <li><a href="#">小米笔记本</a></li>
    <li><a href="#">小米手机</a></li>
    <li><a href="#">黑鲨4</a></li>
    <li><a href="#">空调</a></li>
  </ul>
</div>

<script>
  /* 
  1.介绍键盘事件(一般给表单元素注册)
    oninput : 键盘输入
    onfocus : 成为焦点.    鼠标点击表单,出现光标,此时可以在表单输入文本
    onblur  : 失去焦点.    鼠标点击空白区域,光标消失,此时 不可以在表单输入文本
  
  2.小米搜索框思路
    2.1 输入框成为焦点:  (1)输入框添加类名  search   (2)显示ul
    2.2 输入框失去焦点:  (1)输入框移除类名  search   (2)隐藏ul
  */

  //1.获取元素
  let input = document.querySelector("input")
  let ul = document.querySelector(".result-list")

  //2.注册事件

  //2.1 表单成为焦点
  input.onfocus = function() {
    console.log("鼠标点击表单,出现闪烁光标。此时可以键盘输入")
    //(1)输入框添加类名  search  
    input.classList.add('search') 
    //(2)显示ul
    ul.style.display = 'block'
  }
  //2.2 表单失去焦点
  input.onblur = function() {
    console.log("鼠标点击空白区域,闪烁光标小时。此时不可以键盘输入")
    //(1)输入框移除类名  search  
    input.classList.remove('search') 
    //(2)隐藏ul
    ul.style.display = 'none'
  }
</script>
</body>
 

image.png

15.this指向

this : 环境对象. 一般用在函数中,规则是 :谁调用我,我就指向谁
在事件处理函数中, this指向事件源,简单来说这个事件是谁的,this就代表谁
说人话: this相当于中文'我', 这个字是谁说的,就代表谁

image.png

16.案例:点击 'x' 关闭广告

   <style>
    .box {
        border: 1px solid #D9D9D9;
        margin: 100px auto;
        position: relative;
        width: 107px;
    }

    #x {
        border: 1px solid #D9D9D9;
        width: 14px;
        height: 14px;
        line-height: 14px;
        color: #D6D6D6;
        cursor: pointer;
        position: absolute;
        top: 0;
        left: -15px;
    }
</style>

</head>
<body>

<div class="box">
    <img src="images/taobao.jpg" alt="" />
    <span id="x">×</span>
</div>

 <script>
    /* 点击x : 隐藏box */

    //1.获取元素
    // let box = document.querySelector('.box')
    let x = document.querySelector('#x')

    //2.点击x
    x.onclick = function(){
        // this : 事件源x按钮
        // this.parentNode : x的父元素box
        //3.隐藏box
        // box.style.display = 'none'
        this.parentNode.style.display = 'none'
    }    
 </script>
 

image.png

17.innerHTML和createElement性能问题

 <body>
<button class="btn">点我啊</button>
<script>

    document.querySelector('.btn').onclick = function () {
        // innerHTML: 少用(新增超过100个元素,会有性能问题)
        // for (let i = 1; i <= 200; i++) {
        //     document.body.innerHTML += `<p>我是第${i}个p标签</p>`
        // }

        for (let i = 1; i <= 1000; i++) {
            //createElement:推荐使用,性能最高
            //(1)在内存创建空标签
            let p = document.createElement('p')
            //(2)设置内容
            p.innerText = `我是第${i}个p标签`
            //(3)添加到页面
            document.body.appendChild(p)
        }
    }

 </script>

image.png

18.自动消失广告

  <style>
  img {
    position: absolute;
    right: 0;
    bottom: 0;
  }
</style>
</head>
<body>
<img src="./images/ad.png" alt="转存失败,建议直接上传图片文件">

<script>
    //页面3秒后自动关闭广告
    setTimeout(function(){
      let img = document.querySelector('img')
      // 父元素.removeChild(子元素)
      img.parentNode.removeChild(img)
    },3000)
</script>

19.对象和字符串关于赋值的区别:

image.png

image.png

image.png

image.png

image.png

20.微博发布

<style>
* {
  margin: 0;
  padding: 0;
}

ul {
  list-style: none;
}

.w {
  width: 900px;
  margin: 0 auto;
}

.controls textarea {
  width: 878px;
  height: 100px;
  resize: none;
  border-radius: 10px;
  outline: none;
  padding-left: 20px;
  padding-top: 10px;
  font-size: 18px;
}

.controls {
  overflow: hidden;
}

.controls div {
  float: right;
}

.controls div span {
  color: #666;
}

.controls div .useCount {
  color: red;
}

.controls div button {
  width: 100px;
  outline: none;
  border: none;
  background: rgb(0, 132, 255);
  height: 30px;
  cursor: pointer;
  color: #fff;
  font: bold 14px '宋体';
  transition: all 0.5s;
}

.controls div button:hover {
  background: rgb(0, 225, 255);
}

.controls div button:disabled {
  background: rgba(0, 225, 255, 0.5);
}

.contentList {
  margin-top: 50px;
}

.contentList li {
  padding: 20px 0;
  border-bottom: 1px dashed #ccc;
  position: relative;
}

.contentList li .info {
  position: relative;
}

.contentList li .info span {
  position: absolute;
  top: 15px;
  left: 100px;
  font: bold 16px '宋体';
}

.contentList li .info p {
  position: absolute;
  top: 40px;
  left: 100px;
  color: #aaa;
  font-size: 12px;
}

.contentList img {
  width: 80px;
  border-radius: 50%;
}

.contentList li .content {
  padding-left: 100px;
  color: #666;
  word-break: break-all;
}

.contentList li .the_del {
  position: absolute;
  right: 0;
  top: 0;
  font-size: 28px;
  cursor: pointer;
}

 </style>
 </head>


<div class="w">
<!-- 操作的界面 -->
<div class="controls">
  <img src="./images/9.6/tip.png" alt="转存失败,建议直接上传图片文件"><br>
  <!-- maxlength 可以用来限制表单输入的内容长度 -->
  <textarea placeholder="说点什么吧..." id="area" cols="30" rows="10" maxlength="200"></textarea>
  <div>
    <span class="useCount" id="useCount">0</span>
    <span>/</span>
    <span>200</span>
    <button id="send">发布</button>
  </div>
</div>
<!-- 微博内容列表 -->
<div class="contentList">
  <ul id="list"></ul>
</div>
</div>
 <li hidden>
<div class="info">
  <img class="userpic" src="./images/9.6/03.jpg" />
  <span class="username">死数据:百里守约</span>
  <p class="send-time">死数据:发布于 2020120500:07:54</p>
</div>
<div class="content">死数据:111</div>
</li>

<script>
// maxlength 是一个表单属性, 作用是给表单设置一个最大长度
// 模拟数据
let dataArr = [
  { uname: '司马懿', imgSrc: './images/9.5/01.jpg' },
  { uname: '女娲', imgSrc: './images/9.5/02.jpg' },
  { uname: '百里守约', imgSrc: './images/9.5/03.jpg' },
  { uname: '亚瑟', imgSrc: './images/9.5/04.jpg' },
  { uname: '虞姬', imgSrc: './images/9.5/05.jpg' },
  { uname: '张良', imgSrc: './images/9.5/06.jpg' },
  { uname: '安其拉', imgSrc: './images/9.5/07.jpg' },
  { uname: '李白', imgSrc: './images/9.5/08.jpg' },
  { uname: '阿珂', imgSrc: './images/9.5/09.jpg' },
  { uname: '墨子', imgSrc: './images/9.5/10.jpg' },
  { uname: '鲁班', imgSrc: './images/9.5/11.jpg' },
  { uname: '嬴政', imgSrc: './images/9.5/12.jpg' },
  { uname: '孙膑', imgSrc: './images/9.5/13.jpg' },
  { uname: '周瑜', imgSrc: './images/9.5/14.jpg' },
  { uname: '老夫子', imgSrc: './images/9.5/15.jpg' },
  { uname: '狄仁杰', imgSrc: './images/9.5/16.jpg' },
  { uname: '扁鹊', imgSrc: './images/9.5/17.jpg' },
  { uname: '马可波罗', imgSrc: './images/9.5/18.jpg' },
  { uname: '露娜', imgSrc: './images/9.5/19.jpg' },
  { uname: '孙悟空', imgSrc: './images/9.5/20.jpg' },
  { uname: '黄忠', imgSrc: './images/9.5/21.jpg' },
  { uname: '百里玄策', imgSrc: './images/9.5/22.jpg' }
]

/* 思路分析
1.输入框输入事件 : oninput
  * 获取输入框文本长度  赋值给 span标签的innerText

2.点击发布
  2.1 新增li元素
    (1)创建空标签
    (2)设置标签内容
    (3)添加到ul
  
*/

//1.获取元素
let area = document.querySelector('#area')
let useCount = document.querySelector('.useCount')

//2.1 输入框输入事件
area.oninput = function(){
  //3.获取输入框文本长度  赋值给 span标签的innerText
  useCount.innerText = area.value.length
}

//2.2 点击发布
let send = document.querySelector('#send')
let list = document.querySelector('#list')

send.onclick = function(){
  //3.新增li元素
  //(1)创建空标签
  let newLi = document.createElement('li')
  //(2)设置标签内容
  //数组随机下标
  let index = parseInt(Math.random()*dataArr.length)

  newLi.innerHTML = `<div class="info">
  <img class="userpic" src="${dataArr[index].imgSrc}" />
  <span class="username">${dataArr[index].uname}</span>
  <p class="send-time">${ new Date().toLocaleString() }</p>
  </div>
  <div class="content">${area.value}</div>`
  //(3)添加到ul : 添加到最前面
  list.insertBefore(newLi , list.children[0] )

  //3.2 清空输入框和span文本
  area.value = ''
  useCount.innerText = 0
}

image.png