夜听城嚣 夜听城嚣
首页
  • 学习笔记

    • 《JavaScript高级程序设计》
    • 前端基建与架构
  • 专题分享

    • Git入门与开发
    • 前端面试题汇总
    • HTML和CSS知识点
  • 项目实践
  • 抓包工具
  • 知识管理
  • 工程部署
  • 团队规范
bug知多少
  • 少年歌行
  • 青年随笔
  • 文海泛舟
  • 此事躬行

    • 项目各工种是如何协作的
    • TBA课程学习
收藏

dwfrost

前端界的小学生
首页
  • 学习笔记

    • 《JavaScript高级程序设计》
    • 前端基建与架构
  • 专题分享

    • Git入门与开发
    • 前端面试题汇总
    • HTML和CSS知识点
  • 项目实践
  • 抓包工具
  • 知识管理
  • 工程部署
  • 团队规范
bug知多少
  • 少年歌行
  • 青年随笔
  • 文海泛舟
  • 此事躬行

    • 项目各工种是如何协作的
    • TBA课程学习
收藏
  • 第1章 什么是JavaScript
  • 第2章 HTML中的JavaScript
  • 第3章 语言基础
  • 第4章 变量、作用域与内存
  • 第5章 基本引用类型
  • 第6章 集合引用类型
  • 第7章 迭代器与生成器
  • 第8章 对象、类与面向对象编程
  • 第9章 代理与反射
  • 第10章 函数
  • 第11章 异步编程
  • 第12章 BOM
  • 第14章 DOM
  • 第15章 DOM扩展
  • 第16章 DOM2和DOM3
    • 第17章 事件
    • 第18章 动画与Canvas图形
    • 第19章 表单脚本
    • 第20章 JavaScript API
    • 第21章 错误处理与调试
    • 第23章 JSON
    • 第24章 网络请求与远程资源
    • 第25章 客户端存储
    • 第26章 模块
    • 第27章 工作者进程
    • 第28章 最佳实践
    • 《JavaScript高级程序设计》
    frost
    2022-01-16

    第16章 DOM2和DOM3

    # DOM的演进

    isNameNode():比较两个完全相同的节点,即引用同一个对象。

    isEqualNode():比较相等的节点,即节点类型相同,属性相等,也有类似的childNodes。

    # 样式

    # 存取元素样式

    css属性表示:连字符分隔,如font-family。

    js属性表示:小驼峰形式,如style.fontFamily。

    js读取和修改css方式如下:

    console.log(div.style.width)
    div.style.width = '100px' // 必须写单位
    
    1
    2

    DOM style属性和方法有:

    • cssText,包含style属性中的css代码。

    • length,应用给元素的css属性数量。

    • getPropertyValue(propertyName),返回属性propertyName的值。

    • item(index),返回索引为index的css属性名。

    • setProperty(propertyName,value,priority),设置css属性。

    • removeProperty(propertyName),从样式中移除css属性。

    计算样式:document.defaultView.getComputedStyle(element,after)可以获得元素及其伪元素的样式信息。

    # 操作样式表

    document.styleSheets:表示文档中可用的样式表集合。

    CSSRule列表表示样式表中的规则集合。

    insertRule():添加新规则。

    deleteRule():删除规则。

    # 元素尺寸

    注意元素下面3类尺寸都是只读的,每次访问都会重新计算,注意性能。

    # 1.偏移尺寸

    表示元素在屏幕上占用的所有视觉空间,属性如下:

    • offsetHeight,元素在垂直方向上占用的尺寸,包括高度、水平滚动条高度和上下边框的高度。
    • offsetLeft,元素左边框外侧到包含元素的父盒子左边框内侧的距离。
    • offsetTop,元素上边框外侧到包含元素的父盒子上边框内侧的距离。
    • offsetWidth,元素在水平方向上占用的尺寸,包括宽度、垂直滚动条宽度和左右边框的高度。

    offset

    # 2.客户端尺寸

    表示元素内容及其内边距所占用的空间。

    • clientWidth,内容宽度加左右内边距宽度。
    • clientHeight,内容高度加上下内边距高度。

    client

    # 3.滚动尺寸

    表示元素内容滚动距离的信息。

    • scrollHeight,元素内容的总高度。
    • scrollLeft,内容左侧隐藏的距离,设置这个属性可以改变元素的水平滚动位置。
    • scrollTop,内容顶部隐藏的距离,设置这个属性可以改变元素的垂直滚动位置。
    • scrollWidth,元素内容的总宽度。

    scroll

    # 4.确定元素尺寸

    每个元素都有getBoundingClientRect()方法,返回DOMRect对象,包含left/right,top/bottom,width/height总共6个属性,表示元素在页面中相对于视口的位置。

    # 遍历DOM

    有2个类型可以对DOM结构进行深度优先遍历。

    # NodeIterator

    document.createNodeIterator(root,whatToShow,filter,false)创建实例,可以进行遍历。

        <ul class="ul">
          <li class="li">1</li>
          <li class="li">2</li>
          <li class="li">3</li>
          <li class="li">4</li>
          <li class="li">5</li>
          <li class="li">6</li>
          <li class="li">7</li>
        </ul>
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
      const ul = document.querySelector('ul')
    
      let iterator = document.createNodeIterator(
        ul,
        NodeFilter.SHOW_ELEMENT,
        null,
        false
      )
    
      let node = iterator.nextNode()
      while (node !== null) {
        console.log(node.tagName) // 输出所有标签名
        node = iterator.nextNode()
      }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14

    # TreeWalker

    假如只遍历li标签,则需要加上filter。

      const ul = document.querySelector('ul')
    
      const filter = function (node) {
        return node.tagName.toLowerCase() === 'li'
          ? NodeFilter.FILTER_ACCEPT
          : NodeFilter.FILTER_SKIP
      }
      let iterator = document.createNodeIterator(
        ul,
        NodeFilter.SHOW_ELEMENT,
        filter,
        false
      )
    
      let node = iterator.nextNode()
      while (node !== null) {
        console.log(node.tagName) // 输出LI标签名
        node = iterator.nextNode()
      }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19

    是否有更简单的方法,省去过滤的操作?就是TreeWalker。因为它新增了DOM结构中向各个方向遍历的方法。

    • parentNode(),遍历到当前节点的父节点。
    • firstChild(),遍历到当前节点的第一个子节点。
    • lastChild(),遍历到当前节点的最后一个子节点。
    • nextSibling(),遍历到当前节点的下一个同胞节点。
    • previousSibling(),遍历到当前节点的上一个同胞节点。

    这赋予了TreeWalker在DOM结构中游走的能力。

      const ul = document.querySelector('ul')
    
      let walker = document.createTreeWalker(
        ul,
        NodeFilter.SHOW_ELEMENT,
        null,
        false
      )
    
      let node = walker.firstChild()
      while(node !== null){
        console.log(node.tagName)
        node =walker.nextSibling()
      }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14

    # 范围

    范围用于在文档中选择内容,而不用考虑节点之间的界限。

    # DOM范围

    使用createRange()可以创建DOM范围对象,如

    let range = document.createRange()
    
    1

    这个范围对象不能在文档中直接使用,但可以对范围的内容执行一些操作,比如选择,插入,移除等等。

    range实例的属性如下:

    • startContainer,包含选区起始点的父节点
    • endContainer,包含选区终点的父节点(如果在复杂选择中跨元素了,那起始和终点的父节点就不是同一个了)
    • startOffset,范围起点在startContainer中的索引,即第几个节点
    • endOffset,范围终点在startContainer终点索引

    # 简单选择

    • selectNode(),选择整个节点,包括其后代节点。
    • selectNodeContents(),只选择节点的后代。

    举个例子:

      <body>
        <p id="p1"><b>hello</b> world!</p>
      </body>
    
    1
    2
    3
      let range1 = document.createRange(),
        range2 = document.createRange(),
        p1 = document.querySelector('#p1')
      range1.selectNode(p1)
      range2.selectNodeContents(p1)
    
      console.log(range1)
      console.log(range2)
    
    1
    2
    3
    4
    5
    6
    7
    8

    selectNode

    这个例子中:

    range1 range2
    startContainer body p#p1
    startOffset 1(前面有个空白文本节点) 0
    endOffset 2 2

    此外,选择范围后可以调用方法,从而实现更精细的控制。

    • setStartBefore(refNode),把范围的起点设置到refNode之前,从而让refNode成为选区的第一个子节点。
    • setStartAfter(refNode),把范围的起点设置到refNode之后,从而将refNode排除在选区之外。
    • setEndBefore(refNode),把范围的终点设置到refNode之前,从而将refNode排除在选区之外。
    • setEndAfter(refNode),把范围的终点设置到refNode之后,从而让refNode成为选区的最后一个子节点。

    # 复杂选择

    • setStart(refNode,offset),refNode(参照节点)会成为startContainer,offset(偏移量)赋值给startOffset。
    • setEnd(refNode,offset),参照节点会成为endContainer,偏移量赋值给endOffset。

    假设要选择上文中的"llo"到" wo"部分,代码如下:

      let range = document.createRange(),
        p1 = document.querySelector('#p1'),
        helloNode = p1.firstChild.firstChild,
        worldNode = p1.lastChild
    
      range.setStart(helloNode, 2)
      range.setEnd(worldNode, 3) // 注意要选择不属于选区的第一个字符的位置,这里是r的位置
      console.log(range)
    
    1
    2
    3
    4
    5
    6
    7
    8

    # 操作范围

    前面说了简单和复杂选择两种选中范围的方式,后面就是对选区进行操作了。

    如果是复杂选择导致选区缺少开始或结束标签,后台会动态补上,即

    <p><b>He</b><b>llo</b> world!</p>
    
    1

    并且“ world!”文本节点也会被拆分成2个文本节点。

    • deleteContents(),删除选区。

        range.deleteContents()
      
      1

      效果如下

      <p id="p1"><b>he</b>rld!</p>
      
      1
    • extractContents(),删除选区,会返回删除选区的文档片段。

        const remain = range.extractContents()
        console.log(remain)
      
      1
      2
    • cloneContents(),创建副本,这样就不会删除文档了。

        const clone = range.cloneContents()
        const div = document.createElement('div')
        div.appendChild(clone)
        document.body.appendChild(div)
      
      1
      2
      3
      4

    # 范围插入

    有2种方式想范围插入内容:

    • insertNode(),在范围选区的开始位置插入一个节点。

        ...  
        let span = document.createElement('span')
        span.style.backgroundColor = 'red'
        span.textContent = 'inserted text'
        range.insertNode(span)
      
      1
      2
      3
      4
      5

      最终得到如下html

      <p id="p1"><b>he<span style="background-color: red;">inserted text</span>llo</b> world!</p>
      
      1
    • surroundContents(),对选区内容进行包裹。

        let range = document.createRange(),
          p1 = document.querySelector('#p1'),
          helloNode = p1.firstChild.firstChild
      
        range.selectNode(helloNode)
      
        let span = document.createElement('span')
        span.style.backgroundColor = 'red'
        range.surroundContents(span)
      
      1
      2
      3
      4
      5
      6
      7
      8
      9

      得到如下html

      <p id="p1"><b><span style="background-color: red;">hello</span></b> world!</p>
      
      1

    # 范围折叠

    • collapse(boolean),true表示折叠到起点,false表示折叠到终点。

    # 范围比较

    • compareBoundaryPoints(),确定范围之间是否存在公共边界。

    # 复制范围

    • cloneRange()

    # 清理

    • detach(),从文档中剥离范围,解除对范围的引用。
    #读书笔记
    上次更新: 2022/01/23, 17:44:06
    第15章 DOM扩展
    第17章 事件

    ← 第15章 DOM扩展 第17章 事件→

    最近更新
    01
    提交代码时修改commit消息
    04-09
    02
    如何快速定位bug
    02-20
    03
    云端web项目开发踩坑
    08-25
    更多文章>
    Theme by Vdoing | Copyright © 2021-2025 dwfrost | 粤ICP备2021118995号
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式
    ×