JavaScript DOM编程

目录

    说明

节点

节点的类型

节点的层级

nodeName

nodeValue

节点的关系

childNodes

parentNode

 previousSibling 和 nextSibling

firstChild 和 lastChild

 hasChildNodes ()

ownerDocument

操作节点

appendChild ()

insertBefore ()

replaceChild ()

removeChild ()

cloneNode ()

normalize ()


    说明

  1. DOM:文档对象模型 Document Object Model
  2. 通过 DOM 我们可以添加、删除、修改页面的各个部分,实现交互效果。
  3. 任何 HTML 页面都可以用 DOM 表达为一个由节点构成的层级结构。
  4. 在 HTML 页面中 Document 节点就是所有节点的根节点。
  5. 而 <html> 元素则是 Document 节点的唯一子节点,我们将 <html> 元素称为文档元素。
  6. 文档元素是文档最外层的元素,其它元素都在该元素之内,在HTML页面中文档元素就是<html> 元素。

节点

  1. html 文件当中的所有内容都可以称之为是节点包括:注释、文本、标签、换行符、属性等。
  2. 在 JavaScript 中所有节点类型都继承自 Node 类型,所以所有节点类型都共享相同的基本属性和方法。
  3. 节点的类型由 JavaScript 定义在 Node 类型上的12个数值表示。

节点的类型

常量nodeType 值描述状态
Node.ELEMENT_NODE1标签节点,例如:<p> <span>
Node.ATTRIBUTE_NODE2元素属性已弃用
Node.TEXT_NODE3元素或属性中的文本内容
Node.CDATA_SECTION_NODE4XML 中的 文档中的 CDATA 部分
Node.ENTITY_REFERENCE_NODE5XML 中的 实体引用已弃用
Node.ENTITY_NODE6XML 中的 实体已弃用
Node.PROCESSING_INSTRUCTION_NODE7XML 中的 处理指令
Node.COMMENT_NODE8 注释
Node.DOCUMENT_NODE9表示整个文档 Document 也就是 DOM 树的根节点
Node.DOCUMENT_TYPE_NODE10XML中的 表示文档型网页的节点
Node.DOCUMENT_FRAGMENT_NODE11表示一个节点,但它不是 DOM 树的一部分,只相当于一个储存其它节点的变量,所以它的变化不会触发 DOM 树的重新渲染,可以通过调用 appendChild 方法来将该节点添加到 DOM 树中。
Node.NOTATION_NODE12XML 中的 代表 DTD 中声明的符号已弃用

节点的层级

<html>
  <head>
    <title>Sample Page</title>
  </head>
  <body>
    <h1>have a good time oneself!</h1>
  </body>
</html> 
  • 在DOM中HTML文档可以表示为一个由节点构成的层级结构,比如上面这段代码:
    • <head> 元素是 <html> 元素的子元素
    • <html> 元素是 <head> 元素的父元素
    • <head> 元素和 <body> 元素则是兄弟元素他们有共同的父元素 <html>

  nodeType

  • 每个节点都有 nodeType 属性,表示该节点的类型。节点类型由定义在 Node 类型上的 12 个数值常量表示。
  •   <div id="box">
        <ul id="list">
          <li>aaaaa</li>
          <li>aaaaa</li>
          <li>aaaaa</li>
          <li>aaaaa</li>
          <li>aaaaa</li>
        </ul>
      </div>
      <script>
        const list = document.getElementById('list')
    	console.log(list.nodeType)
        // 1
      </script>

nodeName

  • 每个节点都有 nodeName 属性,该属性表示节点的名称。
    • 元素节点的 nodeName,将返回标签名称。
    • 属性节点的 nodeName,将返回属性名称。
    • 文本节点的 nodeName,将返回 #text。
    • 文档节点的 nodeName,将返回 #document。
    • 对于其它节点类型,则会返回不同的名称。
  •   <div id="box">
        <ul id="list">
          <li>aaaaa</li>
          <li>aaaaa</li>
          <li>aaaaa</li>
          <li>aaaaa</li>
          <li>aaaaa</li>
        </ul>
      </div>
      <script>
        const list = document.getElementById('list')
    	console.log(list.nodeName)
        // UL
      </script>

nodeValue

  • 文本节点的 nodeValue 属性包含文本,对于属性节点的 nodeValue 属性包含属性值。
  • 文档节点和标签节点的 nodeValue 属性是不可用的。
  • <div id="box">
        <ul id="list">
            <li id="content">aaaaa</li>
        </ul>
    </div>
    <script>
        const content = document.getElementById('content')
        console.log(content.nodeValue)
        // undefined
        console.log(content.childNodes[0].nodeValue)
        // aaaaa 
        // childNodes 可以获取该标签的子元素数组从而来获得其中的 aaaaa 文本
    </script>

节点的关系

childNodes

  • 每个节点都有一个 childNodes 属性,其中包含一个 NodeList 类数组对象。
  • NodeList 用于有序的,存储该节点的子节点。其拥有 length 属性,length 属性的值可以用来表示当前 NodeList 中的节点数量。
  • 当 DOM 结构发生变化时 NodeList 也发生相对的变化。
  • <div id="box">
        <ul id="list">
            <li id="content">aaaaa</li>
            <li>aaaaa</li>
        </ul>
    </div>
    <script>
        const list = document.getElementById('list')
        const content = document.getElementById('content')
    
        console.log(list.childNodes)
    
        // NodeList(5)
        //   0: text
        //   1: li#content
        //   2: text
        //   3: li
        //   4: text
        //   length: 5
        //   [[Prototype]]: NodeList
    
        console.log(content.childNodes)
    
        // NodeList(1)
        //   0: text
        //   length: 1
        //   [[Prototype]]: NodeList
    
        console.log(content.childNodes[0].nodeValue)
    
        // aaaaa
    
    </script>

parentNode

  • 每个节点都有一个 parentNode 属性,指向他 DOM 树中的父元素。
  • childNodes 中的所有节点都拥有同一个父元素,所以他们的 parentNode 属性指向同一个元素
  • <div id="box">
        <ul id="list">
            <li id="content">aaaaa</li>
            <li id="details">aaaaa</li>
        </ul>
    </div>
    <script>
        const content = document.getElementById('content')
        const details = document.getElementById('details')
    
        console.log(content.parentNode)
    
        // <ul id="list"></ul>
    
        console.log(details.parentNode)
    
        // <ul id="list"></ul>
    
    </script>

 previousSibling 和 nextSibling

  • childNodes 列表中的每个节点,都是同一列表中,其它节点的同胞节点。
  • previousSibling 属性是当前节点在同一列表中的上一个节点。
  • nextSibling 属性是当前节点在同一列表中的下一个节点。
  • 所以 childNodes 列表中,第一个节点的 previousSibing 属性是 null,最后一个节点的 nextSibling 属性是 null。
  • 如果 childNodes 列表中只有一个节点,那么该节点的 previousSibling 属性和 nextSibling 属性都是 null。
  • <div id="box"><ul id="list"><li id="content">aaaaa</li><li id="details">aaaaa</li><li id="matter">aaaaa</li></ul></div>
    <!-- 之所以将代码写成一行是因为换行符也是节点 -->
    <script>
        const content = document.getElementById('content')
    
        console.log(content.previousSibling)
        // null
        console.log(content.nextSibling)
        // <li id="details">aaaaa</li>
    
        const details = document.getElementById('details')
    
        console.log(details.previousSibling)
        // <li id="content">aaaaa</li>
        console.log(details.nextSibling)
        // <li id="matter">aaaaa</li>
    
        const matter = document.getElementById('matter')
    
        console.log(matter.previousSibling)
        // <li id="details">aaaaa</li>
        console.log(matter.nextSibling)
        // null
    
        const list = document.getElementById('list')
    
        console.log(list.previousSibling)
        // null
        console.log(list.nextSibling)
        // null
    
    </script>

firstChild 和 lastChild

  • 如果想要获取父节点的第一个子节点或,最后一个子节点可以使用专门的属性:
    • firstChild 指向 childNodes 中的第一个子节点。
    • lastChild 指向 childNodes 中的最后一个子节点。
  • 如果该父节点只有一个子节点,那么 firstChild 和 lastChild 指向同一个节点。
  • 如果该父节点没有子节点,那么 firstChild 和 lastChild 都是 null。

上述这些节点之间的关系为我们操作文档树时,节点之间的导航提供了方便,这些关系用下图表现的更加明了。

 hasChildNodes ()

  • 由上文可知我们可以通过判断节点 childNodes 属性的 length ,来判断该节点是否有子节点。
  • 但是还有一个更加便利的方法:hasChildNodes 方法,如果该方法返回 true 则说明该节点有一个或多个子节点,如果返回 false 则说明该节点没有子节点。
  • <body>
      <div id="a">
        <div id="b">Hello World</div>
        <div id="c"></div>
      </div>
    </body>
    <script>
      const $ = (e) => document.getElementById(e)
      const a = $('a')
      const b = $('b')
      const c = $('c')
      console.log(a.childNodes.length)
      // 5
      console.log(b.childNodes.length)
      // 1
      console.log(c.childNodes.length)
      // 0
      console.log(a.hasChildNodes())
      // true
      console.log(b.hasChildNodes())
      // true
      console.log(c.hasChildNodes())
      // false
    </script>

ownerDocument

  • ownerDocument 属性,该属性会以 Document 对象的形式返回节点的 owner document。
  • 在 HTML 中元素的 ownerDocument 属性始终是 HTML 文档本身

操作节点

  • 上述所有的属性、方法都是只读的,DOM 另外提供了专门操作节点的方法。

appendChild ()

  • appendChild 方法用于在 childNodes 列表的末尾处添加节点。添加的节点会更新相关的关系。
  • 如果操作的节点是与存在的节点,那么这个节点会从之前的位置被转移到新的位置,一个节点不会再文档中同时出现两个或多个地方。
  • 如果
  • <body>
      <span id="c"> World </span>
      <div id="a"><span id="b"> Hello </span></div>
    </body>
    <script>
      const $ = (e) => document.getElementById(e)
      const a = $('a')
      const b = $('b')
      const c = $('c')
      a.appendChild(c)
    
      console.log(a.lastChild)
      //  <span id="c"> World </span>
    
    </script>

insertBefore ()

  • 如果想把节点放到特定的位置可以使用 insertBefore 方法,该方法接收两个参数:需要插入的节点和参照节点。
  • 调用该方法后需要插入的节点,会插入到参照节点的前面。成为参照节点的前一个同胞节点。
  • <body>
      <span id="d"> d </span>
      <div id="a"><span id="b"> b </span><span id="c"> c </span></div>
    </body>
    <script>
      const $ = (e) => document.getElementById(e)
      const a = $('a')
      const b = $('b')
      const c = $('c')
      const d = $('d')
    
      a.insertBefore(d, null)
      console.log(a.lastChild)
      // <span id="d"> d </span>
    
      a.insertBefore(d, a.firstChild)
      console.log(a.firstChild)
      // <span id="d"> d </span>
    
      a.insertBefore(d, a.lastChild)
      console.log(a.childNodes[a.childNodes.length - 2])
      // <span id="d"> d </span>
    
    </script>

replaceChild ()

  • 前两种方法并不会删除任何已有节点,而 replaceChild 方法会用插入的节点,替换并返回目标节点。
  • replaceChild 方法接收两个参数:需要插入的节点和被替换的节点。使用该方法插入一个节点后,目标节点的所有关系指针都会被替换的节点复制过来。虽然被替换节点仍被同一文档拥有,文档中已经没有了他的位置。
  • <body>
      <span id="flower"> flower </span>
      <div id="a"><span id="life"> life </span><span id="love"> love </span></div>
    </body>
    <script>
      const $ = (e) => document.getElementById(e)
      const a = $('a')
      const life = $('life')
      const flower = $('flower')
      const love = $('love')
    
      const d1 =  a.replaceChild(flower, a.firstChild)
      console.log(a.firstChild)
      // <span id="flower"> flower </span>
      console.log(d1)
      // <span id="life"> life </span>
    
      a.replaceChild(d1, a.firstChild)
      const d2 =  a.replaceChild(flower, a.lastChild)
      console.log(a.lastChild)
      // <span id="flower"> flower </span>
      console.log(d2)
      // <span id="love"> love </span>
    
    </script>

removeChild ()

  • 当我们想移除节点而不是替换节点的时候可以使用 removeChild 方法。该方法只接收一个参数:需要移除的节点。移除节点的同时也会返回被移除节点。
  • 和上面的 replaceChild 方法一样,通过 removeChild 方法移除的节点,仍被当前文档所拥有,但是文档中已经没了改节点的位置。
  • <body>
      <div id="a"><span id="life"> life </span><span id="flower"> flower </span><span id="love"> love </span></div>
    </body>
    <script>
      const $ = (e) => document.getElementById(e)
      const a = $('a')
      const life = $('life')
      const flower = $('flower')
      const love = $('love')
    
      const d1 =  a.removeChild(a.firstChild)
      console.log(a.firstChild)
      // <span id="flower"> flower </span>
      console.log(d1)
      // <span id="life"> life </span>
    
      a.insertBefore(d1, a.firstChild)
      const d2 =  a.removeChild(a.lastChild)
      console.log(a.lastChild)
      // <span id="flower"> flower </span>
      console.log(d2)
      // <span id="love"> love </span>
    
    </script>

上述四种方法都用于操作某个父节点的子节点。如果想要使用他们就要先获取父节点。而如果操作的节点没有子节点或者不支持子节点,那么会导致程序抛出错误。

所有的节点类型共享了两个方法:cloneNode 和 normalize

cloneNode ()

  • cloneNode 方法会返回与调用该方法节点,一模一样的节点。
  • cloneNode 方法接收一个参数为布尔值,表示是否开启深复制。当传入 true 时会进行深度复制,即复制节点及其整个子DOM树。如果传入的是 false,那么只会复制调用该方法的节点。
  • 复制到的节点属于当前文档,但是并未指定父节点,所以可以称之为孤儿节点。可以使用上述的 appendChild 、insertBefore 、replaceChild 方法将孤儿节点添加到文档当中去。
  • <body>
      <ul id="a">
        <li>a</li>
        <li>b</li>
        <li>c</li>
      </ul>
    </body>
    <script>
      const $ = (e) => document.getElementById(e)
      const a = $('a')
      const b = a.cloneNode(true)
      console.log(b)
      //<ul id="a">
      //  <li>a</li>
      //  <li>b</li>
      //  <li>c</li>
      //</ul>
      const c = a.cloneNode(false)
      console.log(c)
      // <ul id="a"></ul>
    
    </script>

normalize ()

  • 该方法会将当前节点和他的后代节点规范化。规范化后的 DOM 树中将不会出现空的文本节点。如有两个文本节点相邻那么会被合并为一个文本节点。 
  • <body>
      <span id="a"> hello world </span>
    </body>
    <script>
      const $ = (e) => document.getElementById(e)
      const a = $('a')
      const b = a.childNodes[0].cloneNode()
      a.insertBefore(b, a.childNodes[0])
      console.log(a.childNodes)
      // NodeList(2) [text, text]
      a.normalize()
      console.log(a.childNodes)
      // NodeList [text]
    </script>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值