为什么需要组件化?
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操作一起写,但是完成了组件化。
下一篇我们就组件化与复用进行优化。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。