前言
本文主要是关于webpack+es6+react的基础页面实例的讲解,通过这个简单的单页面的讲解,当掌握单页面的用法后,实现具体项目是也就是通过控制台调用不同的页面,本文为基础帖到实战帖的过度,适合有react基础的小伙伴,大神请绕行哦。
ok我们废话不多讲直接上图,先给大家看下完成后的效果图,是不是很丑,没关系啦!懂得原理剩下的交给css去做啦,什么配色呀,图片添加呀,大多都是ui的事情,你都懂了不就是抢了别人饭碗了吗,不过吧有一个好的页面鉴赏和规划能力也是必不可少的,但是大家都是菜鸟就不拘小节一下下啦,忍住往下看。
页面整体
使用react制作页面时,我觉得吧应该从对页面划分开始,那么我就先简单的对页面进行划分,其中head和foot主要是为了让大家更好的体会关于页面模块化,在本页面中并没有什么卵用,它们会在本鸟后续的博客中体现自己的威力。
图中可以看出页面是由三层嵌套关系也就是代码中的嵌套,绿色的是爷爷辈,红色自然就是儿子啦,小蓝就是孙子啦,我们发现爷爷有三个儿子,分别是header、ItemPanel、Footer,只有ItemPanel到了结婚年纪了生下了小蓝Item,因此js之间的关系也就非常明了了,然后我们去看下面的实现过程。
页面容器App.js
在爷爷辈的App.js中通过import引入自己的三个儿子,注意import不是react特有的方法,他和export以及class都是es6中添加的,这个超级爽如果熟悉java的小伙办就会觉得超级熟悉有没有,定义方法和使用规则简直和java一样有没有,我们针对任意一个引入进行讲解:import Header from './Header.js';就是引入同级目录下的Header.js文件并且起了个别名叫个Header,这个用处就是在后续的render()函数中当做标签使用,并且可以在<Header/>标签中添加属性,通过属性props可以进行数据流传递。
import './App.css';
import React from 'react';
import Header from './Header.js';
import ItemPanel from './ItemPanel.js';
import Footer from './Footer.js';
import Store from './Store.js';
class App extends React.Component {
constructor(props){
super(props);
this.state={
store:new Store
}
}
removeItem=(key)=>{
//对状态进行修改
this.setState({
store:this.state.store.removeItem(key)
});
}
render(){
return (
<div>
<Header/>
<ItemPanel items={this.state.store.store} removeItem={this.removeItem}/>
<Footer/>
</div>
);
}
}
export default App;
跳过Footer和Header直接奔向最争气的小儿子ItemPanel
因为Footer和Header实在没什么好说的,因此接下来出场的就是ItemPanel他们一家人了,也是根据代码来看看,通用的引入,在这里有必要简单的说下这个export了,export其实是讲构建好的模板进行抛出,让其他js进行引用,最顶层的是可以不需要这个东西的。除此之外他有很多种抛出方式,export一个完整的class、单独抛出方法或者变量,具体细节不熟悉的小伙伴可以自行百度,看看大神的解释。细心的伙伴一定发现了,爷爷头上也有这个东西,那是因为我这里使用了create-react-app进行脚手架搭建,为了方便直接把它抛给了index.js,也就是说你写的这个页面,只要想被别人应用都可以通过加上export进行抛出,这风格有点像seajs中的写法,当然这也是es6的一大亮点,添加了类似与seajs等前端的模块化加载框架的功能。
import React from 'react';
import Item from './Item.js';
export default class ItemPanel extends React.Component{
constructor(props){
super(props);
}
render(){
let items = [];
if(this.props.items && this.props.items.length!=0){
this.props.items.forEach((item,index) => {
items.push(<Item item={item} index={index} key={item.key} removeItem={this.props.removeItem}/>);
});
}else{
items.push(<tr><th colSpan="5" className="tempEmpty">暂无用户</th></tr>);
}
return (
<table className='itemPanel'>
<thead>
<th className='itemTd'>姓名</th>
<th className='itemTd'>年龄</th>
<th className='itemTd'>职位</th>
<th className='itemTd'>性别</th>
<th className='itemTd'>操作</th>
</thead>
<tbody>{items}</tbody>
</table>
);
}
}
现在拿看出上面的代码通过一个循环使用上了他的小蓝Item.js,也就是我摘的这一段,react中有一个厉害的东西就是props大家一定要区分他和state的使用,在这里就是通过props将ItemPanel从App中获得的参数参数传给个了Item,是不是稍微有点点绕,我的理解就是state就是用来表示状态的,一般项目中都会对它置顶处理,也就是放到类似于爷爷辈,中间数据、函数的传输全部都使用props。
if(this.props.items && this.props.items.length!=0){
this.props.items.forEach((item,index) => {
items.push(<Item item={item} index={index} key={item.key} removeItem={this.props.removeItem}/>);
});
}else{
items.push(<tr><th colSpan="5" className="tempEmpty">暂无用户</th></tr>);
}
绑定数据的小蓝Item登场
接下来终于轮到我们的小蓝登场了,因为已经是最底层的了所以就没有引入除了react之外的其他东西,就是一个单一的模板了,用过layui的朋友对此一定不陌生,小蓝的作用就类似于layui的template也就是模板的绑定,主要用于对数据的一个绑定,当然他绑定的数据也是通过props从爷爷辈App.js哪里获得的,至于App.js的数据获取方法就比较多样了,可以直接写静态数据给他,也可以通过引入'该页面的js'(这里的不太明白的话可以往下继续看下)来获得数据。
import React from 'react';
export default class Item extends React.Component{
handlerDel(){
this.props.removeItem(this.props.item.key);
}
render(){
return (
<tr style={{'cursor': 'pointer'}}>
<td className='itemTd'>{this.props.item.info.name}</td>
<td className='itemTd'>{this.props.item.info.age}</td>
<td className='itemTd'>{this.props.item.info.status}</td>
<td className='itemTd'>{this.props.item.info.sex}</td>
<td className='itemTd'>
<a className="itemBtn" onClick={this.handlerDel.bind(this)}>删除</a>
</td>
</tr>
);
}
}
放置页面逻辑方法以及数据源的js还有3″到达
是不是有点奇怪,怎么从头到尾都特么没见到我们的数据,被我吃了呀,别急么,这不就出来了么,duang duang duang 大家请看下面的代码,没错它就是一个模拟的数据源以及逻辑代码的编写的js。
class Item{
constructor(item) {
this.info={};
this.info.name=item.name;
this.info.age=item.age;
this.info.status=item.status;
this.info.sex=item.sex;
++Item.key;
this.key = Item.key;
}
}
Item.key=0;
export default class Store {
constructor() {
this.allStore = [];
if(Store.rawData && Store.rawData.length!=0){
Store.rawData.forEach(
item=>{
this.allStore.push(new Item(item));
}
)
}
this.store=this.allStore;
}
removeItem(key){
let newStore=this.store.filter(item=>{
return item.key!=key;
})
this.store=newStore;
return this;
}
}
Store.rawData= [{ sex: '男', age: 18, name: '曹操', status: '主公'},
{ sex: '女', age: 19, name: '郭嘉', status: '谋士'},
{ sex: '女', age: 23, name: '张辽', status: '将军'},
{ sex: '女', age: 18, name: '张颌', status: '将军'},
{ sex: '男', age: 22, name: '荀彧', status: '谋士'},
{ sex: '男', age: 41, name: '司马懿', status: '谋士'},
{ sex: '男', age: 12, name: '典韦', status: '将军'},
{ sex: '男', age: 33, name: '夏侯惇', status: '将军'},
{ sex: '男', age: 50, name: '夏侯渊', status: '将军'},
{ sex: '男', age: 12, name: '邓艾', status: '将军'},
{ sex: '男', age: 22, name: '于禁', status: '将军'}]
这里我对着段js做一个详细的讲解,按我的理解大家都要把这么个js之所以独立出来,就是为了方便代码的管理,他就有点像之前使用js+html中的js,数据源只是因为没有后端代码模拟的一个东西,大家可以理解为通过ajax从后台获取的,这个js主要承担的爷爷也就是App.js的大部分动态操作
下面就是对这个可恶的js的分段介绍
下面这段代码就是创建了一个Item的model,constructor就是初始化,他的思路和java中基本一样,相当于以后会new一个有参数的对象,对象的参数也是一个对象(map),就是为了方便后续对数据的增删改查,如果只是数据展示,完全没有必要这样你搞,直接用最底下的rawData也是一样的。
class Item{
constructor(item) {
this.info={};
this.info.name=item.name;
this.info.age=item.age;
this.info.status=item.status;
this.info.sex=item.sex;
++Item.key;
this.key = Item.key;
}
}
毕竟抛出的不是Item,接下来这段代码呢,主要就是为了初始化一下抛出去的Store,也是使用一个循环把它付给了属性store,这样在后续的var store=new Store之后,就可以使用创建的对象进行绑定,因为store.store就等同于需要使用的数据源喽,然后就可以通过props传递他让他可以在最底层绑定出来了
constructor() {
this.allStore = [];
if(Store.rawData && Store.rawData.length!=0){
Store.rawData.forEach(
item=>{
this.allStore.push(new Item(item));
}
)
}
this.store=this.allStore;
}