DOM系列:修改DOM

栏目: CSS3 · 发布时间: 8年前

内容简介:通过前面的学习,我们都知道,DOM并不一定要由存在于HTML中的元素组成。我们仅需要使用几行JavaScript代码就可以将HTML元素添加到你的DOM中。而且你也有能力移动周围的元素,甚至删除它们。除了这一切之外,我们还可以动态地创建和修改DOM中的元素,而且这一DOM操作也是很重要的一个特性,同时也能满足Web网站或应用程序的一些操作。在今天的教程中,我们将继续学习DOM中的一些基础知识。在今天中,我们将研究如何创建元素、删除元素和克隆元素等。简单的说,今天的内容涉及到一些DOM的修改。正如前面提到的

通过前面的学习,我们都知道,DOM并不一定要由存在于HTML中的元素组成。我们仅需要使用几行JavaScript代码就可以将HTML元素添加到你的DOM中。而且你也有能力移动周围的元素,甚至删除它们。除了这一切之外,我们还可以动态地创建和修改DOM中的元素,而且这一DOM操作也是很重要的一个特性,同时也能满足Web网站或应用程序的一些操作。

在今天的教程中,我们将继续学习DOM中的一些基础知识。在今天中,我们将研究如何创建元素、删除元素和克隆元素等。简单的说,今天的内容涉及到一些DOM的修改。

创建元素

正如前面提到的,动态地创建HTML元素是DOM中非常常见的操作。如果这是你第一次听到的,也不用担心,因为今天要涉及到内容并不复杂。

在DOM的操作中,我们可以使用 createElement 方法来创建任何你想要创建的HTML元素。 createElement 的工作方式非常简单。你可以通过 document 对象来调用 createElement ,并将希望创建的HTML元素传递给它。比如下面的代码,你可以创建一个 p 元素:

document.createElement('p')

如果运行上面这行代码,它将会创建一个 p 元素。需要注意的是,这个时候只是创建了一个 p 元素,但在HTML中并看不到你所添加的 p 元素。因为这个时候你只是创建了 p 元素,并没有放到你需要放置的地方,言外之意, 咱们动态创建的 p 元素现在只是漫无目的的四处游荡!

DOM系列:修改DOM

出于这种原因是因为DOM并没有意识到这个元素的存在。为了使用元素成为DOM的一部分,需要做以下两件事:

appendChild

比如下面这个示例:

<body>
    <h1 id="theTitle" class="highlight summer">What's happening?</h1>

    <script>
        let newElement = document.createElement('p')
        newElement.textContent = '新创建的p元素'

        document.body.appendChild(newElement)
    </script>
</body>

上面的代码中,通过 document.body 访问的到父元素是 body 元素。也就是说,在 body 元素上调用 appendChild() 方法,并在这个方法中传递一个参数,这个参数就是我们新创建的元素,也就是示例中的 newElement 。或许你已经发现了,在执行 document.body.appendChild(newElement) 之间,虽然使用 document.createElement('p') 创建了 p 元素,但在HTML中并看不到。所以说,要在HTML文档中想要看到 document.createElemet() 方法创建的HTML元素,还需要使用类似 appendChild() 这样的方法。

下图就是一个简单的DOM树,即使用 createElement() 方法和 appendChild() 给HTML新添加的 p 元素(新添加的 p 元素位于 </body> 之前):

DOM系列:修改DOM

有一个细节需要注意,使用 appendChild() 函数将新创建的元素添加到指定的父元素下,都将成为该父元素的最后一个子元素,也就是 lastChild 。比如说上面的示例, body 元素已经有了 h1script 元素。新创建的 p 将作为 body 的最后一个子元素,被追加到 script 之后,也就是 </body> 标签之前。

前面提到过,使用 createElement 创建的元素,是在DOM的世界中游离,并未存在HTML的DOM世界当中,而且也说了,将新创建的HTML元素插入到DOM中, appendChild 仅是一种方式,其实我们还有别的方式。比如,想在 h1 标签之后插入新创建的元素 newElement (事实是就是新创建的 p 元素),那么可以通过在指定的父节点上调用 insertBefore() 函数来实现。 insertBefore() 函数接受两个参数。第一个参数是要插入的元素(比如 newElement ),第二个参数是你想插入元素的位置,比如 h1 元素之后(但在 script 元素之前)。那么我们可以这样做:

<body>
    <h1 id="theTitle" class="highlight summer">What's happening?</h1>

    <script>
        var newElement = document.createElement("p");
        newElement.textContent = "I exist entirely in your imagination.";

        var scriptElement = document.querySelector("script");
        document.body.insertBefore(newElement, scriptElement);
    </script>
</body>

运行上面的代码之后,所得到的DOM树如下所示:

DOM系列:修改DOM

或许你会说,既然有 insertBefore() 方法,应该也会有一个 insertAfter() 方法。事实证明,事实并非如此。 在 DOM 操作中并没有一个内置的方法在DOM元素之后插入你想要插入的元素。 在DOM的操作当中,如果你想在一个元素之后插入你想要插入的元素,可以借助 insertBefore() 函数来实现,比如在上面的示例中,我们要把新创建的元素添加到 h1script 之间,当然,使用 insertBefore(newElement, scriptElement) 很容易实现,但我们还可以借助其他的方式,来个曲线救国,比如 h1 的下一个元素,即 h1Element.nextSibling 。那么我们可以这样写我们的代码:

<body>
    <h1 id="theTitle" class="highlight summer">What's happening?</h1>

    <script>
        var newElement = document.createElement("p");
        newElement.textContent = "I exist entirely in your imagination.";

        var h1Element = document.querySelector("h1");
        document.body.insertBefore(newElement, h1Element.nextSibling);
    </script>
</body>

用下图来阐述,更易于帮助大家理解:

DOM系列:修改DOM

就上面的示例而言, h1Element.nextSibling 调用到的是 script 元素。将 newElement 新创建的元素插入到 script 元素之前,事实上也实现了在 h1 元素之后插入新创建的元素 newElement 。如果目标没有兄弟元素呢?这个例子中的 insertBefore 函数非常聪明,它会自动将你想要的元素追加到末尾。

阅读到这里,你可能已经清楚了,在JavaScript中操作DOM元素,并没有我们想像中要的 insertAfter 函数,但你可能很多时候需要这样的一个特性,就是在指定元素之后插入你想要插入的元素,那么咱们可以自己定义一个函数,来达到类似的一个功能。比如下面这个自定义的 insertAfter 函数:

function insertAfter(target, newElement) {
    target.parentNode.insertBefore(newElement, target.nextSibling)
}

是的,这样的做法其实就是一种曲线救国的方式,但是它确实地有效。

除此之外,将子元素添加到父元素的一种更通用的方法是通过实现父元素将子元素视为数组条目。要访问这一系列的子节点( children ),需要有 childrenchildNodes 属性。 children 属性只返回HTML元素,而 childNodes 属性返回的是更通用的节点,这些节点代表了许多我们并不关系的东西。

删除元素

你可能已经意识到了,既然能在DOM中创建一个新元素,那应该也可以从DOM中删除一元素吧。前面我们了解了 createElement 方法创建元素。接下来,咱们来看看怎么从DOM中删除一个已有元素。在DOM中,咱们可以使用 removeChild 来删除已有的DOM元素。

比如下面这个示例:

<body>
    <h1 id="theTitle" class="highlight summer">What's happening?</h1>

    <script>
        var newElement = document.createElement("p");
        newElement.textContent = "I exist entirely in your imagination.";

        document.body.appendChild(newElement);

        document.body.removeChild(newElement);
    </script>
</body>

通过 appendChild 方法将新创建的 p 元素 newElement 添加到 body 元素中。如果阅读了前面的内容,你应该清楚其中的一切。如果要删除这个元素,则可以在 body 中调用 removeChild 方法,并将指针传递给希望删除的元素,也就是 newElement 元素。一旦执行 removeChild ,DOM就会不知道 newElement 的存在。

需要注意的是,如果希望从子节点的父节点中调用 removeChild 来删除你想要删除的元素。此方法不会遍历DOM。假设没有直接访问元素的父元素,并且不想浪费时间来查找它。那可以通过 parentNode 属性,也可以很轻易的删除该元素。比如下面这个示例:

<body>
    <h1 id="theTitle" class="highlight summer">What's happening?</h1>

    <script>
        var newElement = document.createElement("p");
        newElement.textContent = "I exist entirely in your imagination.";

        document.body.appendChild(newElement);

        newElement.parentNode.removeChild(newElement);
    </script>
</body>

克隆元素

通过前面学习,咱们知道怎么在DOM中添加一个新元素和删除一个已有的元素。事实上,除此之外,还可以克隆一个元素。

在DOM中克隆一个元素方式也很简单,在希望克隆的元素上调用 cloneNode 函数,并提供一个 truefalse 的参数,以指定是否想克隆元素或元素及其所有子元素。

比如下面这个简单的示例:

<!DOCTYPE HTML>
<html>
    <body>
        <div id="outerContainer">
            <div>
                <h1>This one thing will change your life!!!</h1>
            </div>
        </div>
        <div id="footer">
            <div class="share">
                <p>Something</p>
                <img alt="#" src="blah.png"/>
            </div>
        </div>

        <script>
            var share = document.querySelector(".share");
            var shareClone = share.cloneNode(false);

            document.querySelector("#footer").appendChild(shareClone);
        </script>
    </body>
</html>

上面的代码把类名 sharediv 赋值给一个 share 的变量。接着使用 cloneNode 函数克隆这个 div

var shareClone = share.cloneNode(false);

上面的代码把新克隆的内容赋值给 shareClone 。注意,这里传给 cloneNode 的值是 false 。这意味着只克隆了类名为 sharediv

调用 cloneNode 后的操作步骤与使用 createElement 的步骤相同。在下一行代码中,把新克隆的元素添加到 div#footer 中。执行上面的代码之后,DOM树就变成下图这样:

DOM系列:修改DOM

接下来修改一下上面的代码,把其中的 false 修改为 true

var shareClone = share.cloneNode(true);

执行完这一行代码,和前面结果不同之处是,这里克隆的不仅是 div.share 这个元素,还克隆了该元素的所有后代元素。这个时候的DOM结构如下:

DOM系列:修改DOM

正如你所看到的, div.share 后面的子元素 pimg 元素也被克隆了。

替换元素

在DOM操作中,咱们还可以使用 replaceChild() 方法用一个新的DOM节点来替换当前节点。 replaceChild 同样的接收两个参数,第一个参数是新节点,第二个参数就是旧节点(也就是需要被替代的元素节点)。比如前面的示例,用新创建的 newElement (使用 createElement 创建的一个新 p 元素)来替代已有的 oldElement (即,DOM中 divshare 的)。

let newElement = document.createElement('p')
newElement.textContent = '新创建的p元素'

let oldElement = document.querySelector('.share')

oldElement.parentNode.replaceChild(newElement, oldElement)

这个时候DOM的结构变成了:

DOM系列:修改DOM

创建文本节点

DOM中除了元素节点之外,还有文本节点,前面看到的相关操作都是针对DOM元素节点的,比如说创建元素,删除元素和克隆元素等。这一小节,来看文本节点的创建。

在DOM中如果需要创建文本节点,可以使用 document.createTextNode() 来创建新文本节点。这个方法接受一个参数,即, 要插入节点中的文本 。与设置已有文本节点的值一样,作为参数的文本也将按照HTML或XML的格式进行编码。

let textNode = document.createTextNode('Hello JavaScript!')

在创建新文本节点的同时,也会为其设置 ownerDocument 属性。不过,除非把新节点添加到文档树中已经存在的节点中,否则我们不会在浏览器窗口中看到新节点。比如下面这个示例:

<body>

    <div class="alert"></div>

    <script>
        let newElement = document.createElement('div')
        newElement.className = 'message'

        let textNode = document.createTextNode('Hello JavaScript')

        newElement.appendChild(textNode)

        let alertBox = document.querySelector('.alert')

        alertBox.appendChild(newElement)
    </script>
</body>

这个时候DOM变成这样:

DOM系列:修改DOM

在《DOM节点属性》和《理解DOM》都知道, innerHTMLinnerTexttextContent 都可以创建DOM的文本节点之类。其中 innerHTML 可以识别标签,而 textContent 无法识别标签。事实上:

  • innerHTML 可以识别标签,而 createTextNode 会将内容全部转化为字符串
  • innerTexttextContent 事实上和 createTextNode 的基本用法是一样的,都无法识别标签并转化为HTML。但 innerText 是一次修改,会将标签里所有内容修改, createTextNode 可以逐条插入,避免整体修改。

来简单的看一个小示例:

<body>

    <div class="inner-box"></div>
    <div class="text-box"></div>
    <div class="node-box"></div>

    <script>
        let innerHTMLBox = document.querySelector('.inner-box')
        let textContentBox = document.querySelector('.text-box')
        let textNodeBox = document.querySelector('.node-box')

        innerHTMLBox.innerHTML = 'Hello <strong>JavaScript</strong>! innerHTML'
        textContentBox.textContent = 'Hello JavaScript! textContent'
        textNodeBox.appendChild(document.createTextNode('Hello JavaScript! createTextNode'))

        let anotherTextNode = document.createTextNode('Yippee!')

        textNodeBox.appendChild(anotherTextNode)
    </script>
</body>

直接看结果吧:

DOM系列:修改DOM

prepend/append/before/after

其中 prepend()append()before()after() 等都是新增的DOM API。有关于它们更详细的介绍,可以阅读 @张鑫旭 老湿写的博文 ,这篇博文章详细介绍他们怎么使用以及差异。

这里只是简单的来看看这几个API:

  • node.append(...nodes or string) :在 node 节点的末端附加节点或字符串
  • node.prepend(...node or string) :在 node 节点的开头添加新插入的节点或字符串
  • node.before(...node or string) :在 node 节点前插入节点或字符串
  • node.after(...node or string) :在 node 节点后插入节点或字符串
  • node.replaceWith(...node or string) :用给定的节点或字符串来替找 node 节点

来看一个简单的示例:

<ol id="ol">
    <li>0</li>
    <li>1</li>
    <li>2</li>
</ol>

<script>
    ol.before('before');
    ol.after('after');

    let prepend = document.createElement('li');
    prepend.innerHTML = 'prepend';
    ol.prepend(prepend);

    let append = document.createElement('li');
    append.innerHTML = 'append';
    ol.append(append);
</script>

结果是这样的:

DOM系列:修改DOM

下图用来描述对就的方法:

DOM系列:修改DOM

insertAdjacentHTML/Text/Element

多年前,微软提出了称为 insertAdjacentHTML() 的方法,将一个HTML或XML文本的指定字符串插入到DOM的特点位置。 insertAdjacentHTML() 接受两个参数。第一个定义了你想放HTML的位置,相对于目标元素来说。可以是以下4个字符串类型的值之一:

beforebegin
afterbegin
beforeend
afterend

同样,这些都是字符串值,不是关键字 ,所以他们必须放在单引号或双引号内。

第二个参数是你要插入的,也放在引号内(否则这将是一个已定义的字符串型的变量)。请注意,它应该是一个字符串,而不是一个DOM元素或元素集合,因此,它可能仅仅是文本,不是实际的标签。

如在 Mozilla Hacks介绍的一样 , insertAdjacentHTML() 有一些更常用的优点,像 innerHTML() :它不会破坏现有的DOM元素,并且运行得更好。

同样来看一个小示例:

<div id="div"></div>
<script>
    div.insertAdjacentHTML('beforebegin', '<p>Hello</p>');
    div.insertAdjacentHTML('afterend', '<p>Bye</p>');
</script>

浏览器渲染出来的结果如下:

DOM系列:修改DOM

这就是我们如何将任意HTML附加到页面的方法。下图是插入变量的示意图:

DOM系列:修改DOM

我们可以看到,上图和前面的图片有相似之处。

DOM系列:修改DOM

插入点实际上是相同的,但是这个方法插入HTML。该方法有两种使用方式:

elem.insertAdjacentText(where, text)
elem.insertAdjacentElement(where, elem)

它们的存在主要是为了使用语法“ 统一 ”。在实践中,大部分时间只使用 insertAdjacentHTML() ,因为它可以插入文本和HTML元素,而 append()prepend()before()after() 这几个方法,API更简短,他们可以插入节点和文本片段。

有关于这方面更详细的介绍,可以阅读《 DOM appendHTML 实现及 insertAdjacentHTML 》和《 JavaScript在box内的一些实用方法 》。

总结

今天我们主要学习了如何修改DOM。涉及到的内容也比较多,简单的做一下小总结。

创建新节点的方法:

  • document.createElement(tag) :创建一个HTML元素(通过你想要的HTML标签来创建)
  • document.createTextNode(value) : 创建一个文本节点(有点类似于 textContent
  • elem.cloneNode(deep) :克隆节点(元素),其中 deep 是一个布尔值,如果值为 true ,那么 elem 的所有后代都会被克隆

上面创建的元素和节点,如果不去做插入的操作,是不是在DOM中渲染,所以在DOMk 还有一些插入和删除节点的DOM API。先来看从父节点做的相关操作:

parent.appendChild(node)
parent.insertBefore(node, nextSibling)
parent.removeChild(node)
parent.replaceChild(newElem, node)

上面这些方法返回都是 node 。再来看看给定一个节点和字符串的相关操作:

node.append(...nodes or strings)
node.prepend(...nodes or strings)
node.before(...nodes or strings)
node.after(...nodes or strings)
node.replaceWith(...nodes or strings)
node.remove()

除此之外,还可以根据把给出的一段HTML,通过 elem.insertAdjacentHTML(where, html) 方法和下面的API,指定HTML片段插入的位置:

beforebegin
afterbegin
beforeend
afterend

有关于上述的DOM API具体的使用方式和细节,可以查阅前面相关的内容。如果文章中有整理的不对之处,或者说你有这方面更多的经验,欢迎在下面的评论中与我们一起分享。

DOM系列:修改DOM

大漠

常用昵称“大漠”,W3CPlus创始人,目前就职于手淘。对HTML5、CSS3和Sass等前端脚本语言有非常深入的认识和丰富的实践经验,尤其专注对CSS3的研究,是国内最早研究和使用CSS3技术的一批人。CSS3、Sass和Drupal中国布道者。2014年出版《 图解CSS3:核心技术与案例实战 》。

如需转载,烦请注明出处: https://www.w3cplus.com/javascript/modifying-document.html


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Math Adventures with Python

Math Adventures with Python

Peter Farrell / No Starch Press / 2018-11-13 / GBP 24.99

Learn math by getting creative with code! Use the Python programming language to transform learning high school-level math topics like algebra, geometry, trigonometry, and calculus! In Math Adventu......一起来看看 《Math Adventures with Python》 这本书的介绍吧!

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具