project from jirengu.com fangyinghang Frontend class
背景储备:有两种风格封装DOM操作;分别是对象风格和链式风格。
本文主要介绍对象风格,也叫命名空间风格,首先window.dom是我们提供的全局对象。
- 新建一个项目示例:新建文件夹
dom-1,用vscode打开文件夹,新建src文件夹,在其中分别新建index.html,main.js,dom.js文件,dom.js主要是用来封装的,main.js主要是直接用封装好的代码来进行DOM操作的。
2.初始化index.html,并添加script标签,引入main.js和dom.js
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Dom 1</title>
</head>
<body>
示例
<script src="dom.js"></script>
<script src="main.js"></script>
</body>
</html>
- 用parcel建立服务器,并能显示页面,新建终端,
parcel src/index.html,并开始封装:
window.dom = {} //window.dom对象 = 空对象
window.dom.create = function (){};
//也可以写成如下格式:
window.dom = {
create:function(){
};
}
//再一步简化,把function删掉:
window.dom = {
create(){};
}
- 接受一个标签名tagName,返回一个标签:
window.dom ={
create(tagName){
return document.createElement(tagName);
}
};
- 用main.js来直接调用元素,就可以在控制台直接打印出div标签:
const div =dom.create('<div>');
console.log(div);
- 如果在div里面加一个span标签,怎么能实现呢,直接写在div里面是不能实现的,但是dom是没有直接给接口的,无法调用。
const div =dom.create('<div><span>1</span></div>'); //定义一个变量div,让dom.create('div')获取到的div赋值给这个变量
const span =dom.create('span');
div.appendChild(span);
console.log(div);
//简化为如下:
const div =dom.create('<div><span>1</span></div>');
console.log(div);
- 那么该如何实现呢?
window.dom ={
create(string){
const div =document.createElement('div');
div.innerHTML = string
return div.children[0]
},
}
用container代替div,重新写为:
window.dom ={
create(string){
const container =document.createElement('div');
container.innerHTML = string
return container.children[0]
},
}
- 但是div标签是有局限性的,比如里面放hi标签,就不能加上,而新标签template却可以容纳任意标签,在index里面添加,不会显示在页面中;同时,不能用children拿到trtd标签,需要用
.content.firstChild来获取:
window.dom ={
create(string){
const container =document.createElement
('template');
container.innerHTML = string.trim();
return container.content.firstChild
},
}
8.1 上面的代码中string.trim(),是为了避免main.js中写标签时两边有空格的话,可以直接转化为正常,举例:
const div =dom.create(' <tr><td>1<tr></td>');
上面代码有很多空格,直接执行的话,页面就会显示>#text,但是加上string.trim(),即便是有空格,也都会正常显示。
- 在一个node节点后面再插入一个节点,用after来实现:
window.dom ={
after(node,node2){ node.parentNode.insertBefore(node2,node.nextSibling);
},
}
const div =dom.create('<div>newDiv</div>');
console.log(div);
dom.after(test,div);
- 看起来非常简单的接口,实际上有比较恶心繁琐的实现,其他增加接口实现代码如下,
window.dom ={
create(string){
const container =document.createElement
('template');
container.innerHTML = string.trim();
return container.content.firstChild
},
after(node,node2){
node.parentNode.insertBefore(node2,node.nextSibling);
},
before(node,node2){
node.parentNode.insertBefore(node2,node);
},
append(parent,node){
parent.appendChild(node)
},
wrap(node,parent){ //用于新增爸爸
dom.before(node,parent)
dom.append(parent,node)
},
}
const div =dom.create('<div>newDiv</div>');
console.log(div);
dom.after(test,div);
const div3 =dom.create('<div id="parent"></div>')
dom.wrap(test,div3)
- 删除节点
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Dom 1</title>
</head>
<body>
示例
<div>
<div id="test">test</div>
</div>
<div id="empty">
<div id="e1"></div>
<div id="e2"></div>
<div id="e3"></div>
</div>
<script src="dom.js"></script>
<script src="main.js"></script>
</body>
</html>
window.dom ={
remove(node){ //删除节点
node.parentNode.removeChild(node)
return node
},
empty(node){
//const childNodes = node.childNodes 等价于下面的一行代码
const {childNodes}=node
const array =[]
let x =node.firstChild
while(x){
array.push(dom.remove(node.firstChild))
x = node.firstChild
}
return array
},
}
const nodes=dom.empty(window.empty)
console.log(nodes)
- 改节点
window.dom ={
attr(node,name,value){ //重载,根据参数个数写不同的代码,就是重载
if(arguments.length===3){
node.setAttribute(name,value)
}else if(arguments.length===2){
return node.getAttribute(name)
}
},
text(node,string){ //适配
if(arguments.length===2){
if('innerText' in node){
node.innerText = string //支持IE
}else{
node.textContent = string //支持firfox,chrome
}
}else if(arguments.length===1){
if('innerText' in node){
return node.innerText
}else{
return node.textContent
}
}
},
html(node,string){
if(arguments.length===2){
node.innerHTML = string
}else if(arguments.length===1){
return node.innerHTML
}
},
style(node,object){
for (let key in object){ //遍历一下object,把里面所有的key都读到
node.style[key] = object[key]
}
},
//key不确定,可能key:border 也可能key:color
//正常代码是node.style.border = ...
// 或是node.style.color = ...
//现在border和color是不确定的,变量,变量做key的话,必须放在中括号[]里面,因为nide.style.key就变成字符串
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:red})
return node.style[name]
}else if(name instanceof Object){
const object = name
for (let key in object){ //遍历一下object,把里面所有的key都读到
node.style[key] = object[key]
}
}
}
},
class:{
add(node,className){
node.classList.add(className)
}
},
remove(node,className){
node.classList.remove(className)
},
has(node,className){
return node.classList.contains(className)
},
}
dom.attr(test,'title',"Hi,I am 96") //三个参数实现了改属性名及属性值
const title = dom.attr(test,'title') //两个参数实现了读,把读的结果返回给变量title
console.log('title:${title}')
dom.text(test,'你好,这是新的内容')
dom.text(test)
dom.style(test,{border: '1px solid red',color:'blue'}) //共2个参数,第2个参数是对象,就是设置参数值
console.log(dom.style(test,'border'))
//dom.style(test,'border') //共2个参数,第2个参数是字符串,那就是读取参数值或者写
dom.style(test,'border','1px solid black') //共3个参数
dom.class.add(test,'red')
dom.class.add(test,'blue')
dom.class.remove(test,'blue')
console.log(dom.class.has(test,'blue'))