你可以看到
什么叫封装
对象风格的-增
-删
-改
-查
要说的话
本文从代码、本不应该的大量小白(我)也能看懂的注释和示例结果图来看懂DOM封装。
--资料来源于饥人谷
源码所在地
github.com/woshidw/dom…
什么叫封装
可以理解为把一个复杂的东西打包成一个服务,只需要用一些简单的命令就可以操作它。
- 举例
电脑笔记本就是CPU、内存、硬盘、主板、显卡的封装,用户只需要接触显示器、键盘、鼠标、触控板等设备即可操作复杂的计算机。
- 接口
被封装的东西需要暴露一些功能给外部,这些功能就是接口,如USB接口、HDMI接口。设备只要支持这些接口,即可与被封装的东西通讯,比如键盘、鼠标支持USB接口;显示器支持HDMI接口
两图对应
一些术语
- 库
我们把提供给其他人用的工具代码叫做库
比如jQuery、Underscore
- API
库暴露出来的函数或属性叫做API(应用编程接口,英文Application Programming Interface)
- 框架
当你的库变得很大,并且需要学习才能看懂,那么这个库就叫框架,比如Vue / React
- 注意
编程界的术语大部分都很随便,没有固定的解释,所以意会即可
用对象风格封装DOM操作
- 也叫命名空间风格。
window.dom是我们提供的全局对象。在html里先添加
<script src="dom.js"></script>
<script src="main.js"></script>
增
- dom.create(`<div>hi</div>`) 用于创建节点。
-
- 创建一个标签节点
在创建的dom.js文件里封装DOM编程里的增方法
window.dom = {
create (tagName){
return document.createElement(tagName);
//封装创建一个标签节点。用DOM编程里增方法,创建这个元素,然后把元素(标签名)return回去
}
};
//window.dom等于一个空对象
main.js里进行调用代码
//没封装之前就是document.createElement('div')
let div = dom.create("div");
console.log(div);
//在main.js这里调用刚刚封装的创建标签元素 create(tagName)
调用结果
-
- 创建任意元素
dom.js
window.dom = {
create (string){
const container = document.createElement("template");//template是专门用来容纳所有元素的,不会显示到页面
container.innerHTML = string.trim();//trim()去掉空格。把字符串变成容器里的内容
return container.content.firstChild;//用template元素不能通过children拿到
//把一段html写到标签里,这段html自动变成了html元素
},
};
main.js
//没封装之前就是document.createElement('div')
const div = dom.create(" <tr><td>hi</td><tr>");
console.log(div);
结果
- dom.after(node, node2)用于新增弟弟
html里加一个id为test,内容为test的div。在test元素后再新增一个元素
dom.js
//新增弟弟
//在node节点后新加node2。
//没有insertAfter,只有insertBefore.
//下一节点为空,依然可以插入进来。
after(node, node2){
console.log(node.nextSibling);//可以看下一节点是什么
node.parentNode.insertBefore(node2, node.nextSibling);
//找到node节点的爸爸,然后调用爸爸的insertBefore方法,把node2插到node下一个节点的前面。
}
main.js调用
//没封装之前就是document.createElement('div')
const div = dom.create("<div>newDiv</div>");
console.log(div);
dom.after(test, div);//把1.创建节点创建的div插入到test元素后面
可以看到插入成功了
- dom.before(node, node2)用于新增哥哥
dom.js封装insertBefore
//新增哥哥
before(node,node2){
node.parentNode.insertBefore(node2, node);//node支持的一个接口
}
- dom.append(parent, child)用于新增儿子
dom.js
//新增儿子
append(parent , node){
parent.appendChild(node);//直接用appendChild
}
- dom.wrap(`<div></div>`)用于新增爸爸
dom.js
//新增爸爸
//在一个节点外面,加一个爸爸。
wrap(node, parent){
before(node,parent)
append(parent,node)
}
用图来说明关系
现有div1和儿子div2,现在需要把div3插入两者之间。用封装的dom.wrap(div2,div3),先用dom.before(div2,div3)把div3放到div2前面,两者是兄弟关系,然后用dom.append(div3,div2),把div2append成div3的儿子(append如果插入别的地方,就会在原来的地方移开)
main.js
const div3 = dom.create('<div id="parent"></div>');
dom.wrap(test,div3);//给test新增一个爸爸div3
成功
删
- dom.remove(node)用于删除节点
dom.js
remove(node){//用跟古老的接口
//用这个节点的爸爸从树中删除这个儿子节点。
node.parentNode.removeChild(node)
return node//还能保留节点的引用,方便操作
},
- dom.empty parent)用于删除后代
在html中添加empty元素
<div id="empty">
<div id="e1"></div>
<div id="e2"></div>
<div id="e3"></div>
</div>
dom.js
//删除所有后代
empty(node){//干掉这个节点的所有儿子,不能出现在树里面。可以调用儿子一个个删
//node.innerHTML = ''//可以删,但获取不到节点的引用
const {childNodes} = node//const childNodes = code.childNodes。从node获取到它的childNodes
const array = []
let x = node.firstChild
while(x){//当x存在就把它移除并放到数组里
array.push(dom.remove(node.firstChild))//dom.remove移除会返回node节点,这直接push掉
x = node.firstChild
//然后把x指向firstChild,上面已经移除了第一个节点,这里firstChild相当于第二个节点
}
return array
},
main.js中打印出删掉的后代
const nodes = dom.empty(window.empty)//找到html中empty元素,删掉,然后把它所有儿子都弄出来
console.log(nodes)//然后打印出所有儿子
移除的东西
改
- dom.attr(node, 'title',?)用于读写属性。(attr是attribute的缩写)
dom.js
attr(node, name, value){ //重载,根据参数个数写不同的代码
if(arguments.length === 3){
//如果参数长度为3,就设置它的属性名和值。写操作
node.setAttribute(name, value)
}else if(arguments.length === 2){
//如果参数长度为2,就相当于读,就返回。读操作
return node.getAttribute(name)
}
},
main.js
dom.attr(test, 'title', 'Hi, I am dw')//参数长度为3,设置。写
const title = dom.attr(test, 'title')//参数长度为2,读。获取test元素的title属性,并赋给变量title。读
console.log(`title: ${title}`)//title值为title
读写结果
- dom.text(node,?)用于读写文本内容
改文本内容 dom.js
//适配
text(node, string) {
//给节点,告诉新传的文本是什么
if (arguments.length === 2) {
if ("innerText" in node) {
node.innerText = string; //IE
} else {
node.textContent = string; //Chrome,Firefox等等。
//但两种方式浏览器都支持,如果想所以浏览器都支持可以用innerText
}
} else if (arguments.length === 1) {
if ("innerText" in node) {
return node.innerText;
} else {
return node.textContent;
}
}
},
main.js。选择改不同内容,可以加个span再改
dom.text(test, '你好,这是新的内容')
结果
- dom.html(node,?)用于读写HTML内容
dom.js
html(node, string){
if(arguments.length === 2){
node.innerHTML = string
}else if(arguments.length === 1){
return node.innerHTML
}
},
- dom.style(node, {color: 'red'})用于修改style
dom.js
style(node, name, value) {
if (arguments.length === 3) {
//如dom.style(div, 'color' , 'red')
node.style[name] = value;
} else if (arguments.length === 2) {
if (typeof name === "string") {
//如dom.style(div, 'color')
return node.style[name];
} else if (name instanceof Object) {
//dom.style(div,{color: 'red'})
const object = name;
for (let key in object) {
//key: border /color 这个key是个变量,比如可能是border或者color
//正常代码
//node.style.border = ...
//node.style.color = ...
node.style[key] = object[key]; //不能用.key(这会变成一个字符串)。变量做key的话要用[]
}
}
}
},
main.js
dom.style(test,{border: '1px solid red', color: 'blue'})//有一个test节点,里面有属性名,后面是属性值
console.log(dom.style(test, 'border'))//读。第二个参数可能是对象也可能是字符串。如果是对象就是设置,是字符串就是读
dom.style(test, 'border', '1px solid black')//也可以三个参数读
- dom.class.add(node, 'blue')用于添加class
dom.js
class:{
add(node, className){
node.classList.add(className)
},
}
在html里添加一个red类,比如
.red{
background: red;
}
main.js
dom.class.add(test, 'red')//在test元素上添加一个类名red
最后添加成功
- dom.class.remove(node, 'blue')用于删除class
dom.js
class:{
remove(node,className){
node.classList.remove(className)
},
}
main.js
dom.class.remove(test, 'red')//又删除了red类
- dom.class.has(node, className)用于知道node元素有没有指定的className
dom.js
class:{
//要知道node节点元素有没有指定的className
has(node, className){
return node.classList.contains(className)
}
},
main.js
console.log(dom.class.has(test,'red'))//检查test元素里有没有red类名
- dom.on(node, 'click', fn)用于添加事件监听
dom.js
on(node, eventName, fn){//告诉节点,事件名,事件处理函数
node.addEventListener(eventName, fn)
},
main.js
const fn = ()=>{
console.log('点击了')
}
dom.on(test, 'click', fn)//点击test这个div,执行打印
- dom.off(node, 'click', fn)用于删除事件监听
html里添加
<div>
<div id="test"><span>test1</span>
<p class="red">段落标签3</p>test2
</div>
<div id="test2">
<p class="red">段落标签3</p>test2
</div>
</div>
dom.js
//移除这个监听
off(node, eventName, fn){
node.removeEventListener(eventName, fn)
}
main.js
dom.off(test, 'click' , fn)//移除监听
查
- dom.find('选择器')用于获取标签或标签们
dom.js
find(selector, scope){//给我一个选择器,在范围里进行查找,返回对应元素
return (scope || document).querySelectorAll(selector)
//如果有范围scope,则在scope里调用querySelector,如果没有scope则在document里调用
},
main.js
const testDiv = dom.find('#test')[0]//找到id为test的元素,获取第0个
console.log(testDiv)//没有范围
const test2 = dom.find('#test2')[0]
console.log(dom.find('.red', test2)[0])//两个参数,指定在找的范围是什么(默认是在document找)
打印出了
- dom.parent(node)用于获取父元素
dom.js
parent(node){
return node.parentNode
},
- dom.children(node)用于获取子元素
dom.js
children(node){
return node.children
},
- dom.siblings(node)用于获取兄弟姐妹元素
html 在html里添加
<div id="siblings">
<div id="s1"></div>
<div id="s2"></div>
<div id="s3"></div>
</div>
dom.js
siblings(node){//返回节点的兄弟姐妹(兄弟姐妹不能包括自己)
//children是伪数组,要变成数组才可以用filter
return Array.from(node.parentNode.children)
.filter(n=>n!==node)//在伪数组编程数组后对它进行过滤,只要这个元素不等于当前这个节点就把它放到数组里
},
main.js
console.log(dom.siblings(dom.find('#s2')[0]))//找到e2,再获取它的兄弟节点
获取到兄弟姐妹
- dom.next(node)用于获取弟弟,nodeType MDN
dom.js
next(node){
let x = node.nextSibling
while(x && x.nodeType === 3){//看如果是文本,是就下一个。。,如果下一个节点不是就返回
x = x.nextSibling
}
return x
},
main.js
const s2 = dom.find('#s2')[0]
console.log(dom.siblings(s2))
console.log(dom.next(s2))
- dom.previous(node)用于获取哥哥
dom.js
previous(node) {
let x = node.previousSiblings;
while (x && x.nodeType === 3) {
//看如果是文本,是再往前。。,如果不是就返回
x = x.previousSiblings;
}
return x;
},
- dom.each(nodes, fn)用于遍历所有节点
在html里添加
<div id="travel">
<div id="t1">t1</div>
<div id="t2">t2</div>
<div id="t3">t3</div>
</div>
dom.js
each(nodeList, fn) {//给我一个节点列表,函数
for (let i = 0; i < nodeList.length; i++) {
fn.call(null, nodeList[i]);
}
},
main.js
const t = dom.find('#travel')[0]//find返回的是一个数组,找到第一个元素
dom.each(dom.children(t),(n)=>dom.style(n, 'color' ,'red'))
//遍历它的子元素,对子元素进行一个each操作,每一个用n站位,n的color为red
- dom.index(node)用于获取排行老几
dom.js
index(node){
const list = dom.children(node.parentNode)//用list获取到爸爸的儿子
let i
for(i=0;i<list.length;i++){
if(list[i] === node){//每一个与它作对比,看list(i)是否等于node,如果等于就是第i+1个
break
}
}
return i
}
main.js
console.log(dom.index(s2))
从0开始,为第二个
--continue
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!