JS-Web-API(DOM、BOM、事件)

一、DOM

  • DOM,全称是Document Object Model 文档对象模型
  • DOM的本质是一棵节点树

1. 节点

  • 节点:Node,是构成HTML文档最基本的单元
  • 通常可以分为四类:
    • 文档节点:整个HTML文档
    • 元素节点:html中的标签
    • 属性节点:元素的属性
    • 文本节点:标签中的文本内容

2. 节点的属性

-nodeNamenodeTypenodeValue
文档节点#document9null
元素节点标签名1null
属性节点属性名2属性值
文本节点#text3文本内容

3. 获取DOM节点的方法

方法描述补充
document.getElementById()通过id获取一个元素在实际开发中较少使用,选择器中多用class, id一般只用在顶级层存在 不能太过依赖id
document.getElementsByTagName();通过标签名获取元素集合返回符合tagName的所有元素的类数组对象,尽管只找到一个元素也会存到类数组
document.getElementsByClassName();通过类名获取元素集合返回符合className的所有元素的类数组对象
document.getElementsByName();name属性值一般不用
document.querySelector();css选择符模式返回与该模式匹配的第一个元素,结果为一个元素;如果没找到匹配的元素,则返回null
document.querySelectorAll()css选择符模式返回与该模式匹配的所有元素,结果为一个类数组

4. 节点间的关系

关系考虑所有节点只考虑元素节点
子节点childNodeschildren
父节点parentNodeparentNode
第一个子节点firstChildfirstElementChild
最后一个子节点lastChildlastElementChild
前一个兄弟节点previousSiblingpreviousElementSibling
后一个兄弟节点nextSiblingnextElementSibling
<div class="box">
  <p class="item">段落1</p>
  <p class="item">段落2</p>
  <p class="item">段落3</p>
</div>
<script>
  let box = document.querySelector('.box')
  // 所有子节点,包含文本节点(空格也是文本节点)
  console.log(box.childNodes) // NodeList(7) [text, p.item, text, p.item, text, p.item, text]
  // 所有的元素子节点(IE9+)
  console.log(box.children); // HTMLCollection(3) [p.item, p.item, p.item]

  // 第一个子节点
  console.log(box.firstChild) // #text
  // 第一个元素子节点
  console.log(box.firstElementChild); // <p class="item">段落3</p>

  // 最后一个子节点
  console.log(box.lastChild); // #text
  // 最后一个元素子节点
  console.log(box.lastElementChild); // <p class="item">段落3</p>
</script>

4.1 封装常见的节点关系函数

  1. 返回元素的所有子元素节点(兼容到IE6)
  /**
   * 获取所有子元素节点
   * 兼容IE6
  */
 function getChildren(node) {
  //  最终结果
  let children = []
  // 遍历node的所有子节点
  for(let i = 0; i < node.childNodes.length; i++) {
    // 判断遍历的子节点的 nodetype 是否为1,如果是1就存入结果数组children
    if(node.childNodes[i].nodeType === 1){
      children.push(node.childNodes[i])
    }
  }
  return children
 }
  1. 获取元素前一个兄弟元素节点,类似于 previousElementSibling
 /**
  * 获取前一个兄弟元素节点
  * 兼容IE6
 */
function getElementPrevSibling(node) {
  // node节点的前一个兄弟节点存在
  while(node.previousSibling !== null) {
    // 前一个兄弟节点的nodeType为1,说明是元素节点,则直接返回
    if(node.previousSibling.nodeType === 1) return node.previousSibling
    // 将前一个节点赋值给node
    node = node.previousSibling
  }
}
  1. 获取所有兄弟元素节点
function getAllElementSibling(node) {
  // 前面的兄弟元素节点
  let prevs = []
  // 后面的兄弟元素节点
  let nexts = []
  while(node.previousSibling !== null) {
    if(node.previousSibling.nodeType === 1) {
      prevs.unshift(node.previousSibling)
    }
    node = node.previousSibling
  }
  while(node.nextSibling !== null) {
    if(node.nextSibling.nodeType === 1) {
      nexts.push(node.nextSibling)
    }
    node = node.nextSibling
  }
  // 合并数组
  return prevs.concat(nexts)
}

5. 节点的操作

5.1 改变元素节点的内容

属性说明
innerHTMLHTMl语法设置节点内容
innerText纯文本形式设置节点内容

5.2 改变css样式

  • 语法:元素.style.属性名 = '属性值',属性名是驼峰格式的
  let box = document.querySelector('.box')
 box.style.color = 'skyblue'
 box.style.fontSize = '18px'

5.3 改变元素节点的HTML属性

  • 更改标准W3C属性(如src、herf等):元素.属性名 = '属性值'
 let img = document.getElementById('img')
 img.src = 'https://img.mukewang.com/szimg/620b43350928ec7140000576.jpg'
  • 更改非标准W3C属性,要使用 setAttribute、getAttribute

5.4 节点的创建、移除、克隆

方法说明
document.createElement(‘tagName’)创建一个指定tagName的HTML元素(孤儿节点)
父节点.appendChild(孤儿节点)将孤儿节点插入父节点的最后,使其成为最后一个子节点
父节点.insertBefore(孤儿节点,标杆节点)将孤儿节点插入到标杆节点前面,使其成为标杆节点的前一个兄弟节点
新父节点.appendChild(已经有父亲的节点)将节点移动到新父节点
新父节点.insertBefore(已有父亲的节点, 标杆子节点)将节点移动到新父节点
父节点.removeChild(子节点)将子节点从父节点中删除
cloneNode()克隆节点,克隆出的节点是孤儿节点。参数表示是否要深度克隆,如果参数为true表示该节点及其后代节点都会被克隆,参数为false表示只克隆节点本身

6. DOM 性能优化

  • 对DOM进行缓存
  • 将频繁的操作改为一次操作或少量操作

二、BOM

  • BOM(Browser Object Model,浏览器对象模型),JS与浏览器窗口交互的接口

1. window 对象

  • window对象,是当前JS脚本运行所在的窗口
  • window.document对象,即document对象
  • 全局变量是window对象的属性,多个JS文件之间共享全局作用域,不会有作用域隔离
  • 内置函数一般都是window的方法,如setInterval()、alert()

1.1 窗口尺寸相关属性

属性描述
innerHeight浏览器窗口内容区的高度,包含水平滚动条
innerWidth浏览器窗口内容区的宽度,包含垂直滚动条
outerHeight浏览器窗口的外部高度
outerWidth浏览器窗口的外部宽度
document.documentElement.clientHeight窗口不包含滚动条的高度
document.documentElement.clientWidth窗口不包含滚动条的宽度
scrollY垂直方向滚动的距离(只读)
document.documentElement.scrollTop垂直方向滚动的距离
offsetTop当前元素到定位祖先元素的垂直距离
  • 获取垂直方向滚动距离
scrollTop = window.screenY || document.documentElement.scrollTop

1.2 resize事件

  • 窗口大小改变后会触发resize事件
  • window.onresizewindow.addEventListener('resize') 绑定窗口改变事件

1.3 scroll事件

  • 窗口滚动时会触发scroll事件
  • window.onscrollwindow.addEventListener('scroll') 绑定scroll事件

2. Navigator 对象

  • window.navigator 包含浏览器的相关属性和标识
属性说明
appName浏览器官方名称
appVersion浏览器版本
userAgent浏览器用户代理(内核信息和封装壳信息等)
platform用户操作系统

3. history对象

  • window.hstory 浏览器会话历史
  • 浏览器回退:history.back()history.go(-1)

4.location 对象

  • window.location 当前所在的网址,可以通过给该属性赋值进行页面跳转
  • window.location.reload() 重新加载当前页面,可以设置参数,当参数为 true 表示强制从服务器加载
  • widow.location.search 给当前浏览器的get请求查询参数

5. 案例一 —— 返回顶部

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link rel="stylesheet" href="https://at.alicdn.com/t/font_3279057_d1pzygibna.css">
  <title>Document</title>
  <style>
    html {
      height: 5000px;
    }
    .top-box {
      width: 50px;
      height: 50px;
      text-align: center;
      line-height: 50px;
      border-radius: 50%;
      background-color: #fff;
      box-shadow: 0 2px 4px 0 rgba(0,0,0,.05);
      cursor: pointer;
      position: fixed;
      right: 20px;
      bottom: 20px;
      display: none;
    }
  </style>
</head>
<body>
  <!-- 返回顶部按钮 -->
  <div class="top-box">
    <span class="iconfont icon-top"></span>
  </div>
  <script>
    let oTop = document.querySelector('.top-box')
    window.onscroll = function() {
      // 获取窗口高度
      let height = document.documentElement.clientHeight
      // 获取滚动的高度
      let scrollTop = window.screenY || document.documentElement.scrollTop
      // 窗口高度小于滚动高度时显示返回顶部按钮
      if(height < scrollTop) {
        oTop.style.display = 'block'
      }else {
        oTop.style.display = 'none'
      }
    }
    let timer
    // 滚动按钮的点击事件
    oTop.onclick = function() {
      // 避免累加
      clearInterval(timer)
      // 定时器 + css 设置返回顶部动画
      timer = setInterval(() => {
        // 减少scrollTop
        document.documentElement.scrollTop -= 200
        // 当scrollTop值小于0,清除定时器
        if(document.documentElement.scrollTop <= 0) clearInterval(timer)
      }, 20);
    }
  </script>
</body>
</html>

6. 案例 —— 楼层导航

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    * {
      padding: 0;
      margin: 0;
    }
    li {
      list-style: none;
    }
    body {
      font: 12px/1.5 Microsoft YaHei,Heiti SC,tahoma,arial,Hiragino Sans GB,"\5B8B\4F53",sans-serif;
      color: #666;
    }
    .right-menu {
      position: fixed;
      right: 20px;
      top: 100px;
      z-index: 19;
      width: 50px;
      background-color: #fff;
      box-shadow: 0 2px 4px 0 rgba(0,0,0,.05);
      padding: 5px;
      text-align: center;
    }
    .menu-item {
      cursor: pointer;
      line-height: 30px;
    }
    .menu-item.active {
      color: tomato;
    }
    .line {
      width: 30px;
      height: 1px;
      margin: 0px auto;
      background-color: #eee;
    }
    .content-part {
      width: 800px;
      height: 500px;
      background-color: tomato;
      margin: 30px auto;
      font-size: 20px;
      color: #fff;
    }
  </style>
</head>
<body>
  <!-- 楼层导航 -->
  <ul class="right-menu">
    <li data-n="导航1" class="menu-item active">导航1</li>
    <li class="line"></li>
    <li data-n="导航2" class="menu-item">导航2</li>
    <li class="line"></li>
    <li data-n="导航3" class="menu-item">导航3</li>
    <li class="line"></li>
    <li data-n="导航4" class="menu-item">导航4</li>
    <li class="line"></li>
    <li data-n="导航5" class="menu-item">导航5</li>
  </ul>
  <!-- 内容区 -->
  <div class="container">
    <div data-n="导航1" class="content-part">内容区1</div>
    <div data-n="导航2" class="content-part">内容区2</div>
    <div data-n="导航3" class="content-part">内容区3</div>
    <div data-n="导航4" class="content-part">内容区4</div>
    <div data-n="导航5" class="content-part">内容区5</div>
  </div>

  <script>
    let oMenu = document.querySelector('.right-menu')

    // 事件委托
    oMenu.onclick = function(e) {
      // 判断是否点击li标签
      if(e.target.tagName.toLowerCase() === 'li') {
        // 获取data-n的属性值
        let n = e.target.getAttribute('data-n')
        // 查找内容区中对应的data-n
        let contentPart = document.querySelector(`.content-part[data-n=${n}]`)
        // 获取对应的内容的offseTop并滚到到对应位置
        document.documentElement.scrollTop = contentPart.offsetTop
      }
    }

    // 页面加载完毕时,将所有内容区的 offsetTop 存入数组
    let menuArr = []
    // 获取所有内容区盒子
    let conParts = document.querySelectorAll('.content-part')
    // 遍历所有内容盒子,获取对应高度
    for(let i = 0; i< conParts.length; i++) {
      menuArr.push(conParts[i].offsetTop)
    }
    // 避免最后一项出错,最后一项存入一个无穷大
    menuArr.push(Infinity)


    // 当前楼层
    let curFloor = -1
    // 获取导航的li
    let lis = document.querySelectorAll('.menu-item')

    // 监听滚动
    window.onscroll = function() {
       // 获取滚动的高度
       let scrollTop = window.screenY || document.documentElement.scrollTop
      //  遍历数组,判断当前的scrollTop 位于哪两个楼层之间
      for(let i = 0; i < menuArr.length; i++) {
        if(scrollTop >= menuArr[i] && scrollTop < menuArr[i+1]) break
        // 退出循环时的 i就是楼层数(节流写法)
        if(curFloor != i) {
          curFloor = i
          // 设置导航栏下标
          for(let j = 0; j < lis.length; j++) {
            if(j === i) {
              lis[j].className = 'menu-item active'
            }else {
              lis[j].className = 'menu-item'
            }
          }
        }
      }
      

    }
  </script>
</body>
</html>

三、事件

  • 事件,浏览器和用户之间的交互行为

1. DOM0 级事件监听: onxxx

  1. 直接在HTML标签内部书写
<button onclick="alert('hello,你找我有啥事啊?')">点我</button>
  • 这种方式称为结构和行为的耦合,不方便维护
  1. 通过绑定处理函数的形式
<button class="btn" id="btn">点我</button>
<script>
  // 获取元素
  let btn = document.querySelector('.btn')
  // 绑定事件
  btn.onclick = function() {
    alert('你好!!')
  }
</script>

1.1 常见的鼠标事件

事件描述
onclick单击
ondblclick双击
onmousedown按下鼠标
onmouseup松开鼠标
onmousemove移动鼠标
onmouseenter鼠标移入(相似事件onmouseover)
onmouseleave鼠标移出(相似事件onmouseout)
onmousewheel鼠标滚动
  • onmouseenter和onmouseover 都表示鼠标移入,但onmouseenter 不会冒泡,onmouseover 会冒泡

1.2 常见的键盘事件

事件描述
onkeypress按下键盘按钮,不能识别系统按钮,如:箭头键、功能键等
onkeydown按下键盘按钮,可以识别系统按钮,且先于keypress
onkeyup按键被松开

1.3 常见的表单事件

事件描述
onchange内容改变
onfocus获得焦点时
onblur失去焦点
onsubmit提交表单
onreset重置表单

1.4 常见的页面事件监听

事件描述
onload页面或图像加载完毕
onunload退出页面

2. DOM2 级事件监听:addEventListener

2.1 事件传播

  • 事件传播是先从外到内(捕获阶段),再从内到外(冒泡阶段
  • onxxx只能监听冒泡阶段

2.2 addEventListener

  • 语法: 元素.addEventListener('事件名',function(){},true)

    • 第一个参数是要触发的事件,此时不加 on
    • 第二个参数是事件处理函数
    • 第三个参数为布尔值,true表示监听捕获阶段,false监听冒泡阶段
  • 最内部元素不在区分捕获和冒泡,会先执行前面的监听,后执行后面的监听

  • 同名时,DOM0 中后面的会覆盖前面的;DOM2 级会按顺序执行

3. 事件对象

  • 事件处理函数中提供了一个形参(e 或 event),该形参封装了本次事件的细节,称为“事件对象”

3.1 鼠标位置的相关属性

属性描述
clientX鼠标指针相对于浏览器的水平坐标
clientY鼠标指针相对于浏览器的垂直坐标
pageX鼠标指针相对于整张网页的水平坐标
pageY鼠标指针相对于整张网页的垂直坐标
offsetX鼠标指针相对于事件源元素的水平坐标
offsetY鼠标指针相对于事件源元素的垂直坐标

3.2 键盘事件中的相关属性

属性描述
e.charCode返回 onkeypress 事件中用户输入字符的字符码
e.keyCodeonkeydown、onkeyup中,用户按下的键码
  • charCode 字符码
字符字符码
数字 0 ~ 948 ~ 57
大写字母 A ~ Z65 ~ 90
小写字母 a ~ z97 ~ 122
  • keyCode 键码
按键键码
数字 0 ~ 948 ~ 57
不分大小写的字母 a ~ z65 ~ 90
方向键 ← ↑ → ↓37、38、39、40
回车键13
空格键32
<body>
  <div id="box" class="box"></div>
  <script>
    let box = document.getElementById('box')
    // 全局left、top
    let l = 200
    let t = 50
    // 监听document的键盘按下
    document.onkeydown = function(e) {
      switch(e.keyCode) {
        case 37:
          l -= 5
          break
        case 38:
          t -= 5
          break
        case 39:
          l += 5
          break
        case 40:
          t += 5
          break
      }
      box.style.left = l + 'px'
      box.style.top = t + 'px'
    }
  </script>
</body>

3.3 e.perventDefault()

  • 作用:阻止默认行为

3.4 e.stopPropagation()

  • 作用:阻止冒泡

4. 事件委托

  • 事件委托:利用事件冒泡机制,将后代元素的事件委托给祖先元素
  • 事件委一般要和 e.target 搭配使用
属性描述
target触发此事件最早的元素,即“事件源元素”
currentTarget事件处理程序附加到的元素
  • 应用场景:批量事件监听、新增元素动态绑定事件
  • 事件委托不能委托给不冒泡的(如onmouseenter)
  • 使用事件委托时,最内层元素不能再有额外元素

5. 定时器和延时器

5.1 定时器

  • setInterval(),定时器可以重复调用一个函数,每次调用之间的时间间隔固定
  • 语法:setInterval(()=>{},time),第一个参数是函数,第二个参数是时间间隔,单位为毫秒,1000ms = 1s,从第三个参数开始表示要传入第一个函数的参数
  • 清除定时器: clearInterval()
  <h3 class="info">0</h3>
  <button class="btn start-btn">开始</button>
  <button class="btn end-btn">暂停</button>
  <script>
    let oInfo = document.querySelector('.info')
    let oStart = document.querySelector('.start-btn')
    let oEnd = document.querySelector('.end-btn')
    let a = 0
    let timer
    oStart.onclick = function() {
      // 避免定时器叠加,所以先清除一次
      clearInterval(timer)
      timer = setInterval(() => {
        oInfo.innerHTML = ++a
      },1000)
    }
    oEnd.onclick = function() {
      clearInterval(timer)
    }
  </script>

5.2 延时器

  • setTimeout(),到达指定时间后会执行一次,不再重复
  • clearTimeout(),清除延时器

5.3 案例 —— 无缝连续滚动特效动画

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    * {
      padding: 0;
      margin: 0;
    }
    li {
      list-style: none;
    }
    .container {
      width: 300px;
      height: 50px;
      margin: 50px auto;
      overflow: hidden;
    }
    .animation-box {
      width: 2200px;
      height: 500px;
      margin: 0 auto;
      position: relative;
    }
    .animation-item {
      width: 50px;
      height: 30px;
      line-height: 30px;
      text-align: center;
      border: 1px solid tomato;
      float: left;
      margin-right: 10px;
    }
  </style>
</head>
<body>
  <div class="container">
    <ul class="animation-box">
     <li class="animation-item">1</li>
     <li class="animation-item">2</li>
     <li class="animation-item">3</li>
     <li class="animation-item">4</li>
     <li class="animation-item">5</li>
    </ul>
  </div>
  <script>
    let container = document.querySelector('.container')
    let listBox = document.querySelector('.animation-box')
    // 复制一份列表
    listBox.innerHTML += listBox.innerHTML
    let left = 0
    let timer 
    function move() {
      // 防止累积
      clearInterval(timer)
      timer = setInterval(() => {
        left -= 4
        if(left < -300) left = 0
        listBox.style.left = left + 'px'
      },50)
    }
    move()
    // 鼠标移入,暂停
    container.onmouseenter = function() {
      clearInterval(timer)
    }
    // 鼠标移出,继续
    container.onmouseleave = function() {
      move()
    }
  </script>
</body>
</html>
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值