1. 配置环境
在终端用 yarn 安装 parcel: yarn global add parcel
启动服务器: parcel src/index.html
2. 对象风格(命名空间风格)封装 DOM 操作
window.dom 是我们提供的全局对象,在src目录中创建index.html, dom.js 和 main.js
3. 功能:获取 / 查找节点
(1) 获取标签
- dom.js 中调用
document.querySelectorAll获取所有标签
find(selector){
return document.querySelectorAll(selector)
} // 不管选择器里有几个元素,全部都返回
- main.js 中运行
dom.find,获取所有div id为test的元素,并打印出这个div
const testDiv = dom.find('#test')[0]
console.log(testDiv)
效果图⬇️
- 适配
在 dom.js 中设定
(scope || document)如果有scope的话,就在scope中调用querySelectorAll,如果没有就在document中调用。
find(selector, scope){
return (scope || document).querySelectorAll(selector)
}
例如在index.html中
<div id="test">
<span>test</span>
<p class="red">红色的test</p>
</div>
<div id="test2">
<span>test2</span>
<p class="red">红色的test2</p>
</div>
更新main.js,在 class='red' 的元素中,只获取id名为test2的,不获取test
const testDiv = dom.find('#test')[0]
const test2 = dom.find('#test2')[0]
dom.find('.red', test2)
console.log(dom.find('.red', test2)[0])
控制台打印内容如下 ⬇️
(2) 获取父 / 子元素(parent/children)
- dom.js
parent(node){
return node.parentNode
} // 获取父元素
children(node){
return node.children
} // 获取子元素
- main.js
console.log(dom.parent(test));
获取到了 test 的父元素
(3) 获取所有兄弟姐妹元素(siblings)
- dom.js 中调用
.parentNode.children查找父母的所有孩子(包括自己),然后filter掉自己,得到所有兄弟姐妹
siblings(node){
return Array.from(node.parentNode.children)
.filter(n => n !== node)
}
- 在 index.html 中添加
<div id="family">
<div id="bro">bro</div>
<div id="sis">sis</div>
<div id="target">target</div>
</div>
- 在 main.js 中获取 target 的兄弟姐妹,并打印出他们如图 ⬇️
const findSib = dom.siblings(dom.find('#target')[0])
console.log(findSib)
(3) 获取同父母的上一个 / 下一个元素
- dom.js 中使用
.nextSibling获取节点类型为文本(nodeType === 3)的元素,如果节点存在下一个 / 存在弟弟,且类型为文本,则返回该节点,并继续找下一个弟弟;查找上一个节点同理,使用.previousSibling
next(node){
let x = node.nextSibling
while(x && x.nodeType === 3){
x = x.nextSibling
}
return x
},
previous(node){
let x = node.previousSibling
while(x && x.nodeType === 3){
x = x.previousSibling
}
return x
}
其他节点类型的对应数字,详见 MDN文档-节点类型常量
- main.js 中寻找sis的下一个元素
const preSib = dom.previous(dom.find('#sis')[0])
console.log(preSib)
const nextSib2 = dom.next(dom.find('#sis')[0])
console.log(nextSib2)
如图,控制台打印出 sis 上面的 bro 和下面的 target ⬇️
- ⚠️ 这里不能直接用
.nextSibling,因为节点后面有回车,返回的是文本 ⬇️
// dom.js ❌ 实例
next(node){
return node.nextSibling
}
此时返回的是文本 #text
(4) 遍历所有节点
- 在 index.html 中新增
div
<div id="travel">
<div id="t1">杭州~</div>
<div id="t2">西雅图~</div>
<div id="t3">慕尼黑~</div>
</div>
- dom.js 中用
.call()调用并返回 nodeList (this的位置用null占位)
each(nodeList, fn){
for(let i = 0; i< nodeList.length; i++){
fn.call(null, nodeList[i])
}
}
- main.js 中对于找到 travel 的所有子元素,对其进行
dom.each操作遍历,将style属性更改为color: blue'
const t = dom.find('#travel')[0]
dom.each(dom.children(t), (n)=> dom.style(n, 'color', 'blue'))
得到的页面效果如图 ⬇️
(5) 获取排名
- dom.js
index(node){
const list = dom.children(node.parentNode)
let i
for(i=0; i<list.length; i++){
if(list[i] === node){
break
}
}
return i
}
- main.js 中 调用
dom.find获取 sis 的排名
const sis = dom.find('#sis')[0]
console.log(dom.index(sis));
如图⬇️ , 所以 sis 的排名是第2名 (第一名index为0,第二名为1,etc.)
手写 DOM 库系列结束,完结撒花~
Reference List | 参考资料
MDN 节点常量: developer.mozilla.org/zh-CN/docs/…
MDN .call(): developer.mozilla.org/zh-CN/docs/…