共计 5492 个字符,预计需要花费 14 分钟才能阅读完成。
为什么需要组件化?
1.web 的发展因为 HTML CSS Javascript 分工造成了协作,所以需要标准和接口,所以需要组件化。
2. 追求效率,重复使用。
怎么实现复用?
我们总不能把同事的代码拷贝过来,拷贝 css,拷贝 js,最后改里面文字。这样也忒费劲了,而且不可持续化。接下来我们就说下怎么组件化。我们先不用 react。先说原生。
为什么说原生。
1. 简单。
2. 我们能够从原生 js 中真的会用 react 组件化,不懂原理只会 react 组件化语法,遇到实际项目也棘手。
1. 我们遇到这么一个实际问题。
你同事写了一个星星评分,你想复用,原始代码如下,怎么办?我们这里简化一下,说五个星星部分。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title> 星星评分 </title>
<style type="text/css">
.starbox span {
width: 27px;
height: 28px;
display: inline-block;
background: url(images/star.gif) no-repeat 0px 0px;
cursor: pointer;
float: left;
}
.starbox strong {
float: left;
padding-top: 6px;
padding-left: 10px;
}
.starbox .on {background-position: 0px -29px;}
</style>
<script>
window.onload = function(){var aStar = document.querySelectorAll('.starbox span');
var oS = document.querySelector('.starbox .score');
for(let i =0;i<aStar.length;i++){aStar[i].onclick = function(){for(let j =0;j<aStar.length;j++){aStar[j].className = '';
}
for(let j =0;j<=i;j++){aStar[j].className = 'on';
}
oS.innerHTML = (i+1)+'分';
};
}
};
</script>
</head>
<body>
<div class='starbox'>
<span data-index="0"></span>
<span data-index="1"></span>
<span data-index="2"></span>
<span data-index="3"></span>
<span data-index="4"></span>
<strong class='score'>0 分 </strong>
</div>
</body>
</html>
2. 组件化结构
我们先让这个组件能够显示我们的 html 结构跟样式。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
.starbox span {
width: 27px;
height: 28px;
display: inline-block;
background: url(images/star.gif) no-repeat 0px 0px;
cursor: pointer;
float: left;
}
.starbox strong {
float: left;
padding-top: 6px;
padding-left: 10px;
}
.starbox .on {background-position: 0px -29px;}
</style>
<script>
window.onload = function () {
//2. 但是没有,所以我们搞一个 Class
class RatingStar {
// render 专门用来决定显示什么东西的
render() {
return `
<div class='starbox'>
<span data-index="0"></span>
<span data-index="1"></span>
<span data-index="2"></span>
<span data-index="3"></span>
<span data-index="4"></span>
<strong class='score'>0 分 </strong>
</div>
`;
}
}
var oBox = document.getElementById('box');
//1. 假设有一个 Class RatingStar 它就是一个组件,包含所有组件信息
var oStar = new RatingStar();
oBox.innerHTML = oStar.render();};
</script>
</head>
<body>
<div id="box">
</div>
</body>
</html>
我们先按照注释思路走,但是有个问题:事件不好用。
return `
<div class='starbox'>
<span data-index="0"></span>
<span data-index="1"></span>
<span data-index="2"></span>
<span data-index="3"></span>
<span data-index="4"></span>
<strong class='score'>0 分 </strong>
</div>
`;
因为上面是 return 的字符串不好加事件,我们直接在外面包一层 div,再添加事件。
3. 添加事件
外面包一个 div。
// 创建一个元素
const createDOMFromString = (domString) => {const div = document.createElement('div')
div.innerHTML = domString
return div
}
我们现在到原来的例子里面加事件。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
.starbox span {
width: 27px;
height: 28px;
display: inline-block;
background: url(images/star.gif) no-repeat 0px 0px;
cursor: pointer;
float: left;
}
.starbox strong {
float: left;
padding-top: 6px;
padding-left: 10px;
}
.starbox .on {background-position: 0px -29px;}
</style>
<script>
window.onload = function () {const createDOMFromString = (domString) => {const div = document.createElement('div')
div.innerHTML = domString
return div;
}
class RatingStar {
// render 专门用来决定显示什么东西的
render() {
this.el = createDOMFromString(`
<div class='starbox'>
<span data-index="0"></span>
<span data-index="1"></span>
<span data-index="2"></span>
<span data-index="3"></span>
<span data-index="4"></span>
<strong class='score'>0 分 </strong>
</div>
`);
this.el.addEventListener('click', ()=>{console.log(this);
}, false);
return this.el;
}
}
var oBox = document.getElementById('box');
var oStar = new RatingStar();
oBox.appendChild(oStar.render());
};
</script>
</head>
<body>
<div id="box">
</div>
</body>
</html>
重点是加事件
this.el.addEventListener('click', ()=>{console.log(this);
}, false)
4. 添加数据与逻辑
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
.starbox span {
float: left;
width: 27px;
height: 28px;
display: inline-block;
background: url(images/star.gif) no-repeat 0px 0px;
cursor: pointer;
}
.starbox strong {
float: left;
padding-top: 6px;
padding-left: 10px;
}
.starbox .on {background-position: 0px -29px;}
</style>
<script>
window.onload = function () {const createDOMFromString = (domString) => {const div = document.createElement('div')
div.innerHTML = domString
return div;
}
class RatingStar {constructor() {this.state = { score: 0}
}
changeScore(ev) {const aStar = document.querySelectorAll('.starbox span');
const oS = document.querySelector('.starbox .score');
this.state.score = Number(ev.target.dataset.index) + 1;
for (let i = 0; i < aStar.length; i++) {aStar[i].className = '';
}
for (let i = 0; i <= Number(ev.target.dataset.index); i++) {aStar[i].className = 'on';
}
oS.innerHTML = this.state.score + '分';
}
// render 专门用来决定显示什么东西的
render() {
this.el = createDOMFromString(`
<div class='starbox'>
<span data-index="0"></span>
<span data-index="1"></span>
<span data-index="2"></span>
<span data-index="3"></span>
<span data-index="4"></span>
<strong class='score'>0 分 </strong>
</div>
`);
this.el.addEventListener('click', this.changeScore.bind(this), false);
return this.el;
}
}
var oBox = document.getElementById('box');
var oStar = new RatingStar();
oBox.appendChild(oStar.render());
};
</script>
</head>
<body>
<div id="box">
</div>
</body>
</html>
注意,请不要陷入细节:
this.el.addEventListener('click', this.changeScore.bind(this), false);
先注意明白这里调用了 changeScore 就行了,先别考虑什么矫正 this,或者事件对象什么的,我们先了解 react 原理。
这里修改 DOM 方法很暴力,react 是用 virtualDOM 和 diff 算法优化了这块,现在我们实现了组件化。
总结:
1. 我们从实际问题出发,用 class 封装了一个初始的类。
2. 添加事件;
3. 我们在事件里面加了具体逻辑,虽然数据和 DOM 操作一起写,但是完成了组件化。
下一篇我们就组件化与复用进行优化。