修改文件


浏览器解析完 HTML 后,创建的 DOM 元素会组成树状结构,浏览器上呈现的画面,就是根据 DOM 树绘制出来,只要改变 DOM 树,浏览器就会根据改变后的 DOM 树重绘画面,而这就构成动态修改文件的基本原理。

底下这个范例示范如何动态新增与删除图片:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width">
</head>
<body>

    <input id="src" type="text"><button id="add">新增图片</button>
    <div id="images"></div>

<script type="text/javascript">
    document.getElementById('add').onclick = function() {
      let img = document.createElement('img');

      img.src = document.getElementById('src').value;
      img.onclick = function() {
          document.getElementById('images').removeChild(this);
      };

      document.getElementById('images').appendChild(img);
    };

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

按我看执行结果

在原本的 HTML 中,并没有任何的<img>元素,当在文本框中输入图片的网址并按下按钮时,会使用documentcreateElement来动态创建元素,此时这个元素并没有绑定至 DOM 树,所以还不会出现在画面上。

接着你设定创建的图片元素src为输入的网址,并注册按下图片时,使用removeChild将图片本身(this)从idimages<div>中移除。

最后,将这个动态创建的图片元素使用appendChild附加至idimages<div>元素成为其子元素,此时浏览器根据 DOM 树结构重绘画面。

当使用 JavaScript 动态改变 DOM 树时,在浏览器的检视网页源码中,是看不到动态调整后的 HTML(那是一开始加载的静态 HTML),你要使用浏览器中的开发者工具,才能看到动态的 DOM 画面。例如 Chrome 的「开发人员工具」:

修改文件

每个节点都只能有一个父节点,如果直接获取 DOM 树中既有的节点,并使用appendChild将之附加至另一个节点,则表示节点会从原有的父节点脱离,再附加至另一节点。例如:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
</head>
<body>  
    容器一:
    <div id="container1">
        <img id="image" src="https://openhome.cc/Gossip/images/caterpillar_small.jpg"/>
    </div><br>
    容器二:
    <div id="container2"></div>  

<script type="text/javascript">
    document.getElementById('image').onclick = function() {
        let container1 = document.getElementById('container1');
        let container2 = document.getElementById('container2');
        if(this.parentNode === container1) {
            container2.appendChild(this);
        }
        else {
            container1.appendChild(this);
        }
    };
</script>  
</body>
</html>

按我看执行结果

在这个例子中,点选图片,会将图片来回附加于两个<div>之间,由于一个节点只能有一个父节点,所以appendChild的动作,会使被附加的节点从原父节点脱离。

createElement是用来创建标签对应的元素,如果要创建文本节点,必须使用createTextNode,如果要动态创建属性,则使用createAttribute(少用)。

例如,若有个<div id="console"></div>,想要在其中附加文本,可以如下:

let text = document.createTextNode('your text ....');
document.getElementById('console').appendChild(text);

也可以使用insertBeforereplaceChild等方法来调整 DOM 树上的节点,各种方法的说明可以参考〈JavaScript and HTML DOM Reference〉。

要注意的是,只要你将节点附加至 DOM,浏览器就会重绘画面,若有大量的节点要创建,每次创建就附加至 DOM 树,则会有性能的问题。建议在背景准备好节点树片段,等树片段准备好,再将树片段的根节点绑定至 DOM 树,如此会有比较好的性能。

除了自行创建片段之外,也可以使用createDocumentFragment来创建DocumentFragment,利用它在背景作树片段组织,再一次将DocumentFragment附加至 DOM 树。

DOM 元素有个非标准的innerHTML特性,你可以用之获取标签中内含的 HTML,也可以指定字符串给innerHTML,浏览器会解析这个字符串,并创建对应的 DOM 元素安插至元素中,过去它不是标准特性,但几乎每个浏览器都支持,而 HTML 5 已将innerHTML纳入标准。

例如,要在上面提及的<div>中创建<b>哈啰</b>,可以如下:

document.getElementById('console').innerHTML = '<b>哈啰</b>';




展开阅读全文