练习:手写封装 DOM 库之新增节点

404 阅读2分钟

1. 配置环境

在终端用 yarn 安装 parcel: yarn global add parcel
启动服务器: parcel src/index.html

2. 对象风格(命名空间风格)封装 DOM 操作

window.dom 是我们提供的全局对象 在src目录中创建index.html, dom.js 和 main.js

<!--index.html-->
<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>手写 DOM 封装</title>
</head>
<body>
Halo
<script src="dom.js"></script>
<script src="main.js"></script>
<!--引入dom和main.js-->
</body>
</html>
// dom.js
window.dom = {
  create(string){
    const container = document.createElement('template');
    container.innerHTML = string.trim();  // .trim() 用于把 string 两边多余的空格去掉
    return container.content.firstChild;
  }
}
// main.js
// 由于 dom 是 window 上但全局属性,所以可以在 main.js 上直接用 dom.create
const div = dom.create(`<td>HI!</td>`)
console.log(div)

main.js 中也可以用<div>包裹<span>标签等内容,但是<td>不能包在<div>里,所以这里用到了<template>
HTML内容模版元素<template>,在加载页面时不会呈现,但随后可能会在运行时使用JavaScript实例化(may be instantiated subsequently)

3. 功能:创建节点

(1) 创建新节点

dom.create(`<td>HI!</td>`),控制台打印出如下字样

(2) 在后面新增一个节点

index.html 中添加 <div id="test">test</div>

// ...dom.js中添加
after(node, node2){
        node.parentNode.insertBefore(node2, node.nextSibling);
    } 

.parentNode.insertBefore(node2, node.nextSibling):新增node的弟弟node2 === 新增一个爸爸的小儿子node2 === node2是小儿子,但是由于insertBefore只能新增哥哥,所以此时新增的node2是哥哥,node后面有node.nextSibling,所以把node2插到node和node.nextSibling之间即可

// main.js
const div = dom.create('<div>弟弟</div>');
console.log(div);
dom.after(test, div);

成功在test后面新增了一个节点

(3) 在前面新增一个节点

相当于新增一个哥哥,类比上面的方法

// ...dom.js中添加
    before(node,node2) {
        node.parentNode.insertBefore(node2, node);
    }
// ...main.js中添加
const div2 = dom.create('<div>哥哥</div>')
console.log(div2);
dom.before(test,div2);

成功在前面新增一个节点

(4) 新增一个子节点

// ...dom.js中添加
    append(parent, node){
        parent.appendChild(node)
    }

parent.appendChild() 用于新增子节点

// ...main.js中添加
const div3 = dom.create('<div>孩子</div>');
console.log(div3);
dom.append(test,div3);

效果如图

(3) 新增一个父节点(parent)

// ...dom.js中添加
    wrap(node, parent){
        dom.before(node,parent)
        dom.append(parent, node)
    }

这里先用dom.before把新节点插到test前面,成为test的哥哥;然后用dom.append给新节点涨了辈分,让test变成新节点的儿子,听上去贵圈真乱,为了更好理解,我们重写main.js如下:

// main.js
const div = dom.create('<div>test的弟弟</div>');
const div2 = dom.create('<div>test的哥哥</div>');
const div3 = dom.create('<div>test的孩子</div>');
const div4 = dom.create('<div>test的妈妈</div>');

dom.after(test, div);
dom.before(test,div2);
dom.append(test,div3);
dom.wrap(test,div4);

此时他们的关系如图
当然,你也可以使用dom.after,让新节点先当test的弟弟,再当test的爸妈,为了尽可能减少迷幻色彩,还是长兄为父,让他哥当他妈好了

~本系列未完待续~

Reference List | 参考资料
template MDN : developer.mozilla.org/en-US/docs/…