这个实例是参照这篇文章写的:https://www.cnblogs.com/powertoolsteam/p/react-native-tutorials3.html
有需要的可以点进去看看,但是由于我是新手,基础很差所以看这个文章总是一脸懵逼,所以我决定自己重新写一下。
- 完整代码可以在网盘里下载:https://pan.baidu.com/s/1nCuGwguOcCnIvzcED2mIOg 提取码: punn
- 下面的内容是这个实例的每一步的分解
- 代码的import部分和样式部分可以从上面的文件里复制
打开cmd,进入到保存项目的文件夹,执行以下语句:
react-native init 项目名称
1.电脑通过数据线连接手机,手机进入开发者选项开启USB调试,打开cmd执行以下语句
adb devices
//若出现以下内容即连接成功
//List of devices attached
//a79dc6b4 device
2.让手机和电脑连接同一个WIFI,同时在手机的WIFI里手动设置代理,代理的IP地址写电脑的IP地址,端口是8081。
打开cmd进入项目的根目录,先后执行以下语句:
react-native start
react-native run-android
当项目能够正常运行起来时,就可以开始动手写一个简单的demo了。
要实现这个demo,要解决以下几个问题:
1.如何完成页面的跳转
2.如何控制组件/多选按钮的显示和隐藏
3.如何实现多选按钮两种状态的切换
整个demo的逻辑:
我们这个实例涉及四个组件,分别是App,Add,Main和ToDoListItem
其中App是一个大的父组件,我们通过这个App组件访问整个应用,而且这个组件里面有一个todoList数组对象,用于存放待办事项列表;Main组件是显示的主界面;ToDoListItem组件是获取todoList中的每一项并显示出来;Add组件是添加事项的界面。
详细内容会在代码里作解释。
第一步:完成ToDoListAdd页面的编写,并把该页面挂载到App.js
(1)在项目根目录下创建一个ToDoListAdd.js文件
(2)在页面中添加以下代码 (省略了样式和import部分) :
export default class Add extends Component{
//调用父类的构造函数,让子类继承父类的this对象,获取父类的属性
constructor(props){
super(props);
}
//点击保存按钮时触发的方法,暂时不作处理
onPress(){ }
render() {
return (
//用flexbox对页面进行布局
返回
点击保存
)
}
}
(3)修改App.js文件,使Add组件可以显示
//引入组件
import Add from './ToDoListAdd'
export default class App extends Component{
constructor(props){
super(props);
}
render() {
return(
//显示该组件
)
}
}
第二步:编写ToDoListMain页面
(1)在项目根目录下创建一个ToDoListMain.js文件
(2)在页面中添加以下代码 (省略了样式和import部分) :
export default class Main extends Component{
constructor(props){
super(props);
this.state={
//设置一个状态
isEditing:false
};
//bind的作用是将处理函数和指定的操作绑定在一起,操作触发时函数执行,有多种写法
this.onEdit = this.onEdit.bind(this);
}
//通过setState
//如果直接用setState修改状态可能会由于异步更新问题导致修改失败
//所以要传入上一次状态prevState
onEdit(){
this.setState((prevState) => {
return {
isEditing: !prevState.isEditing
}
});
}
render() {
return (
//用flexBox布局
添加
待办事项
//点击该文字会触发onEdit函数修改isEditing的值
{this.state.isEditing ? '取消' : '多选'}
)
}
}
(3)修改App.js文件,使Main组件可以显示
import Add from './ToDoListAdd'
//引入Main组件
import Main from './ToDoListMain'
……
此处内容不变
……
render() {
return(
//把之前显示的Add组件换成Main组件
)
}
}
第三步:实现Add页面和Main页面的跳转
(1)在App.js中添加一个状态current控制当前显示的页面,添加两个函数用于修改current值。同时要把这两个函数传给Main和Add两个子组件。
修改App.js如下:
export default class App extends Component{
constructor(props){
super(props);
this.state = {
current:'main', //current表示当前显示的页面
}
this.onAddItem = this.onAddItem.bind(this);
this.onBack = this.onBack.bind(this);
}
//当点击‘添加’时跳转到添加页面
onAddItem(){
this.setState((prevState)=>{
return{
current:'add'
}
});
}
//在添加页面点击‘返回’回到主页面
onBack(){
this.setState({
current:'main'
});
}
render() {
if (this.state.current === 'main') {
return ();
} else {
return ( );
}
}
}
(2)在ToDoListMain页面中的“添加”加入一个onPress事件,其他代码保持不变
添加
(3)在ToDoListAdd页面中的“返回”加入一个onPress事件,其他代码保持不变
返回
说明:父组件在子组件上分别定义了onAddItem和onBack属性,子组件通过this.props获取这个属性。
第四步:让待办事项列表在Main组件中显示
(1)在App.js的state中添加名为todoList的数组对象
this.state = {
current:'main', //current表示当前显示的页面
todoList:[ //待办事项的数组,组内每一项都是一个对象
{
level:'info', //通过level控制显示的样式,共有四种:info,warning,error,other
detail:'一般的任务', //待办事项的内容
isChecked:false, //标记是否选中
key:'0' //通过key值来唯一标识
}]
}
(2)把上面的todoList以属性todoList传给子组件Main
在App.js的render()中对作如下修改:
(3)在ToDoListMain.js的Main组件中添加一个
有注释的地方就是修改过的地方
render() {
//这是获取父组件属性的另外一种写法,一种是直接'this.props.属性名',一种是用变量获取
const {onAddItem,todoList} = this.props;
return (
//onPress中可以用变量onAddItem取代以前的this.props.onAddItem
添加
待办事项
{this.state.isEditing ? '取消' : '多选'}
//data和renderItem是FlatList的必填属性,后者的作用是从data中挨个取出数据并渲染到列表中。
//renderItem函数在后面会写
)
}
(4)编写Main组件的renderItem函数,并在constructor中做绑定
…… ……
…… ……
//显示父组件中todolist的每一项
renderItem(item) {
//"..."称为延展操作符,用{...item}的方式为组件传递item对象中的所有属性
//ToDoListItem是一个组件,后面会写
return( )
}
onEdit(){
this.setState((prevState) => {
return {
isEditing: !prevState.isEditing
}
});
}
…… ……
…… ……
this.renderItem = this.renderItem.bind(this);
(5)在ToDoListMain中添加一个组件ToDoListItem
class ToDoListItem extends Component{
constructor(props){
super(props);
}
render(){
//获取从Main组件传来的item,以及item的属性
const {item} = this.props;
const {isChecked,detail,level} = item;
//基础样式---圆
const basicLevelStyle = styles.level;
//特定样式---圆的颜色
let specificLevelStyle;
if(level === 'info'){
specificLevelStyle = styles.info;
}else if(level === 'warning'){
specificLevelStyle = styles.warning;
}else if(level === 'error') {
specificLevelStyle = styles.error;
}
return (
{detail}
);
}
}
第五步:点击“多选”显示复选框,点击“取消”则隐藏
(1)因为显示和隐藏都由isEditing控制,所以要在FlatList中和renderItem函数中传入该状态。
renderItem(item) {
return( )
}
(2)在ToDoListItem组件的render中添加以下代码实现多选框的显示隐藏:
let url = "./img/uncheck.png";
//定义一个小的组件checkBox,如果值为true就显示复选框,否则什么都不显示
let checkBox = this.props.isEditing ? : null ;
return (
//把这个组件加在文字的前面
{checkBox}
{detail}
);
第六步:点击复选框切换选中和不选中状态
由于“选中”和“不选中”状态都是由Item的isChecked属性值控制的,而这个值是存放在App组件中,所以我们想要成功修改这个isChecked的值,就要回到App.js中修改才行。
(1)在App.js中定义toggleItemCheck函数并做绑定,然后在
//判断该项是否被选中,并修改其isChecked值
toggleItemCheck(item){
//匹配item,如果不匹配则把该todo直接放入newTodos列表
const newTodos = this.state.todoList.map(todo =>{
if(todo !== item){
return todo;
}
//如果匹配则获取该todo的所有属性,并修改其isChecked属性
return {
...todo,
isChecked:!item.isChecked
}
});
this.setState({
todoList: newTodos
});
}
this.toggleItemCheck = this.toggleItemCheck.bind(this);
);
(2)在ToDoListMain --》Main --》renderItem函数中再次定义该属性
renderItem(item) {
return( )
}
(3)在ToDoListItem中调用该函数
const {toggleItemCheck,item} = this.props;
//修改checkBox,添加onPress方法并传入当前Item值,根据isChecked的值切换两张图片
let checkBox = this.props.isEditing ?
toggleItemCheck(item)} >
: null ;
第七步:实现Footer的显示隐藏和全选功能
到了这里其实做法跟前面都是类似的:定义函数 --》绑定函数 --》 父组件通过属性给子组件传值 --》子组件通过const或者this.props获取父组件传来的属性 --》调用函数
这部分代码不详细说明,可以直接看文件里的代码,里面会有注释。