美文网首页ReactNative相关资源整理程序员我爱编程
ReactNative快应用时代,是选择还是放弃?

ReactNative快应用时代,是选择还是放弃?

作者: lumic000 | 来源:发表于2018-04-09 16:30 被阅读0次

React Native已经推出好几年,越来越多的app在使用该技术进行项目的开发,而今年3月份安卓阵营的快应用的推出,让大前端的理念可能随之被提出,随着React Native的越来越成熟,以及快应用的出现,我们是选择还是放弃呢?这就要根据公司的选择了,但不管怎么我们还是有必要了解一下。
React Native (简称RN)是Facebook于2015年4月开源的跨平台移动应用开发框架,是Facebook早先开源的UI框架 React 在原生移动应用平台的衍生产物,目前支持iOS和安卓两大平台。RN使用Javascript语言,类似于HTML的JSX,以及CSS来开发移动应用,因此熟悉Web前端开发的技术人员只需很少的学习就可以进入移动应用开发领域。React Native使你能够在Javascript和React的基础上获得完全一致的开发体验,构建世界一流的原生APP。
来来来,开始我们的RN之旅吧!
一、环境安装
这个不多说了,根据RN官方文档来吧,链接地址如下https://reactnative.cn/docs/0.44/getting-started.html
注意:
这里有些需要注意下,按照上面的步骤执行下来,安装的是RN最新的版本,目前是5.1 init命令默认会创建最新的版本,而目前最新的0.45及以上版本需要下载boost等几个第三方库编译。这些库在国内即便翻墙也很难下载成功,导致很多人无法运行iOS项目!!!中文网在论坛中提供了这些库的国内下载链接。如果你嫌麻烦,又没有对新版本的需求,那么可以暂时创建'0.44.3'的版本。

react-native init JJ1 --version 0.44.3
cd JJ1
react-native run-ios

到这里,我相信你RN的环境应该搞定,开始你的第一个项目了!

二、项目开发
1.准备工作:
在开始新项目之前,我们首先要了解 ---- 组件的生命周期(相当于OC中的控制器的声明周期)
先来一张图吧!


20161101195539620.jpg
var List = React.createClass({
//1.创建阶段
getDefaultProps:function(){
//在创建类的时候被调用 默认props设置
console.log('getDefaultProps');
},
//2.实例化阶段
getInitialState:function(){
//获取this.state的默认值
console.log('getInitialState');
return {};
},
componentWillMount:function(){
//在render之前调用该方法
//业务逻辑的处理应该放在这里,如对state的操作等
console.log('componentWillMount');
},
render:function(){
//渲染并返回一个虚拟的DOM
console.log('render');
return ( <View > <Text >厉害了,我的国</Text></View>
);
},
componentDidMount:function(){
//该方法发生在render方法之后,在该方法中,ReactJS会使用render方法返回的虚拟DOM对象来创建真实的DOM结构
console.log('componentDidMount');
},
//更新阶段
componentWillReceiveProps:function(){
//该方法发生在this.props被修改或者父组件调用了setProps()方法之后
console.log('componentWillReceiveProps');
},
shouldComponentUpdate:function(){
//是否需要更新
console.log('shouldComponentUpdate');
return true;
},
componentWillUpdate:function(){
//将要更新
console.log('componentWillUpdate');
},
componentDidUpdate:function(){
//更新完毕
console.log('componentDidUpdate');
},
//4.销毁阶段
componentWillUnmount:function(){
//销毁时被调用,定时器要在这里注销
console.log('componentWillUnmount');
}
});

对组件的生命周期有一定了解,我们就开始我们的项目啦!

2.项目实践
项目一般是是由一个新特性页面或者引导页开始的,那我们第一件事就是开始我们的引导页创建
通过ScrollView组件实现轮播的效果,实现代码如下

import React, { Component } from 'react';
// var Header = require('./Header');
import {
  AppRegistry,
  Dimensions,
  PixelRatio,
  View,
  ScrollView,
  Text,
  NavigatorIOS,
  Image,
  StyleSheet,
  TouchableOpacity

} from 'react-native';
import Util from './Views/Common/util';
import App from './app';

module.exports=React.createClass({
  render() {
    return (
      <NavigatorIOS style={{flex:1}}
           initialRoute={{
            title:'',
        component:LaunchView,
        navigationBarHidden:true,
      }}
      renderScene ={this._renderScene} ></NavigatorIOS>
    );
  },

  _renderScene(route,navigator){
        return (
            <route.component navigator={navigator} {...route} />
        )
  }
});



var LaunchView = React.createClass({
  getInitialState:function(){
    return {
      data:['iPhone se_b1','iPhone se_b2','iPhone se_b3','iPhone se_b4'],
      currentPage:0
    };
  },
  render:function(){
    return (<View style={{flex:1}}><ScrollView 
       ref='scrollView'
       horizontal={true}
       //当值为true时显示滚动条
       showsHorizontalScrollIndicator={false}
       showsVerticalScrollIndicator={false}
       //当值为true时,滚动条会停在滚动视图的尺寸的整数倍位置。这个可以用在水平分页上
       pagingEnabled={true}
       alwaysBounceHorizontal ={false}
       alwaysBounceVertical={false}
       bounces ={false}
       automaticallyAdjustContentInsets={false}
       // contentContainerStyle={styles.scroll}
       onMomentumScrollEnd = {(e)=>this._onAnimationEnd(e)}
    >
   {this._launchScrollWithData()}

    </ScrollView>
    <View style={styles.pageViewStyle}>
    {this._renderAllIndicator()}
    </View>
    </View>);
  },
  _launchScrollWithData(){
    var imgs =[];
    let data=this.state.data;
    var show =false;
    for (let i = 0; i < data.length; i++) {
      var url = data[i];

      if (i === data.length-1 ) {
        show = true;
      }
      imgs.push(<LaunchItem key={i} num={i} url={url} show={show} {...this.props}/>);
    }
    return imgs;
  },
   /**2.手动滑动分页实现 */
  _onAnimationEnd:function(e) {
    //求出偏移量
    let offsetX = e.nativeEvent.contentOffset.x;
    //求出当前页数
    let pageIndex = Math.floor(offsetX / Util.size.width);
    //更改状态机
    this.setState({ currentPage: pageIndex });
  },
    /**3.页面指针实现 */
    _renderAllIndicator() {
    let indicatorArr = [];
    let style;
    let imgsArr = this.state.data;
    for (let i = 0; i < imgsArr.length; i++) {
      //判断
      style = (i==this.state.currentPage)?{color:'#666'}:{color:'#ddd'};
      indicatorArr.push(
        <Text key={i} style={[{fontSize:30},style]}>
         &bull;
        </Text>
      );
    }
    return indicatorArr;
  }

});



var LaunchItem=React.createClass({

  render:function(){
    var num = this.props.num;
    var url = this.props.url;
    var show = this.props.show;
    return (<View style={[styles.img]}>
      <View style={styles.img}>
      <Image style={styles.img} source={{uri:url}}>
           {show ? <TouchableOpacity style={styles.btn} onPress={this.btnDidClick}><View  ><Image style={styles.btnContent} source ={{uri:'btn_op'}}></Image></View></TouchableOpacity>
:<View/>}
      </Image>
      </View>
      </View>);
  },
  btnDidClick:function(){
    // console.log('我被点击了');
        this.props.navigator.replace({
          component:App
        });

  }

});

var styles = StyleSheet.create({

  img:{
    width:Util.size.width,
    height:Util.size.height
  },
  btn:{
    width:120,
    height:40,
    marginLeft:(Util.size.width -120)/2,
    marginTop: Util.size.height -150,

    // alignSelf: 'center',
    // justifyContent:'center',
    // alignItems:'center'
    },
    btnContent:{
    backgroundColor:'#3FA9C4',
    borderRadius:10,
    width:120,
    height:40,
    },
    title:{
        fontSize:16,
        color:'#fff',
        justifyContent:'center',
        alignItems:'center',
    },
  pageViewStyle:{
    height:25,
    width:Util.size.width,
    backgroundColor:'rgba(0,0,0,0)',
    position:'absolute',
    bottom:20,

    flexDirection:'row',
    alignItems:'center',
    justifyContent:'center'
  }

});

一般引导页的显示只是第一次打开才会显示,程序再次打开的时候我们就直接到首页,或者其他的指定页面,这里我们需要通过AsyncStorage做一些简单的存储。AsyncStorage是一个简单的,具有异步特性的键值对的存储系统,相对这个app而言,它是全局的。
因为AsyncStorage是异步的,所以在使用AsyncStorage的时候,会出现一段时间的白屏现在,我们这里先显示一张图片做类似启动页的效果,在程序读取到数据的时候,替换它的路由特性就好。


屏幕快照 2018-04-09 下午4.26.41.png

实现代码如下:

export default class JJ1 extends Component {
  render() {
    return (
      <NavigatorIOS style={{flex:1}}
           initialRoute={{
            title:'',
        component:LaunchImg,
        navigationBarHidden:true,
      }}
      renderScene ={this._renderScene} ></NavigatorIOS>
    );
  }

  _renderScene(route,navigator){
        return (
            <route.component navigator={navigator} {...route} />
        )
  }

}

var LaunchImg = React.createClass({
  render() {
    return (
      <View style = {{flex:1}} >
      <Image source={{uri:'start_se'}} style={{width:Util.size.width,height:Util.size.height}}></Image>
      </View>
    );
  },
  componentDidMount:function(){
   this.timer = setTimeout(this.openApp(),2000);
  },
  openApp(){
    AsyncStorage.getItem('isFirstLaunch',(error,result)=>{
      if (result === 'false') {
        console.log('不是第一次打开');
       this.props.navigator.replace({
          component:App
        });
      }else{
        console.log('第一次打开');
        AsyncStorage.setItem('isFirstLaunch','false',(error)=>{
          if (error) {
            alert(error);
          }
        });
      this.props.navigator.replace({
          component:Intro
        });
      }
    });
  },
  componentWillUnmount() {
    // 如果存在this.timer,则使用clearTimeout清空。
    // 如果你使用多个timer,那么用多个变量,或者用个数组来保存引用,然后逐个clear
    this.timer && clearTimeout(this.timer);
  }
});
   到这里引导页就已经完成,下面我们就创建TabBar,这里可以自定义TabBar从而实现iOS 和安卓能够同时使用,这里偷懒了,直接使用TabBarIOS去实现了! 
   实现代码如下:
module.exports = React.createClass({
  getInitialState:function(){
    return {
      selectedTab:'图书'
    };
  },
  render:function(){
    return(<TabBarIOS>
      <TabBarIOS.Item 
      title = "图书"
      selected={this.state.selectedTab === '图书'}
      icon = {require('./images/book.png')}
      onPress ={()=>{
        this.setState({
          selectedTab:'图书'
          });
      }}>
      <Book/>
      </TabBarIOS.Item>
      
      <TabBarIOS.Item 
      title="电影"
      selected = {this.state.selectedTab ==='电影'}
      icon = {require('./images/movie.png')}
      onPress = {()=>{
        this.setState({
          selectedTab:'电影'
        });
      }}>
      <Movie />
      </TabBarIOS.Item>
      <TabBarIOS.Item 
      title="音乐"
      selected = {this.state.selectedTab === '音乐'}
      icon = {require('./images/music.png')}
      onPress = {()=>{
        this.setState({
          selectedTab:'音乐'
        });
      }}>
         <Music/>
      </TabBarIOS.Item>

      </TabBarIOS>);
  }
});

写到这里,基本的页面搭建就有了!

剩下就是对一些组件的学习,ListView实现iOS中TableView 的功能
例如我在图书页面通过ListView实现了列表展示,
以及在电影页面通过ListView实现九宫格的功能,这里类似iOS 中CollectionVIew
以及写了个简单的登录界面
这里页面还没有完全写完,还在持续撸代码中...


屏幕快照 2018-04-09 下午4.28.10.png

下面贴出来图书页的代码:

module.exports = React.createClass({
  render:function(){
        return(<NavigatorIOS 
      style={{flex:1}}
      initialRoute={{
        component:BookListView,
        title:'图书',
        passProps:{},    

      }}
      renderScene ={this._renderScene} ></NavigatorIOS>
);

  },
  goToLogin:function(){
            this.props.navigator.push({
            component:Login,
            title:'登录',
            });

  },

    _renderScene(route,navigator){
        return (
            <route.component navigator={navigator} {...route} />
        )
  }
});

var BookListView = React.createClass({
    getInitialState:function(){
        var ds = new ListView.DataSource({rowHasChanged:(r1,r2)=>r1!==r2});
        return{
            dataSource:ds.cloneWithRows([]),
            keywords:'c语言',
            show:false
        };
    },
    render:function(){
        return(
            <ScrollView style={[styles.flex,styles.containerTop]}>
            <View><Search></Search></View>
      {this.state.show?
            <ListView dataSource={this.state.dataSource}
                renderRow={this._renderRow}
                renderHeader={this._headerView}
                />:Util.loading}
                
            </ScrollView>);
    },
    componentDidMount:function(){
        this.getData();
    },
    //渲染图书列表
    _renderRow:function(row,sectionID,rowId){
        return(<BookItem row={row} onPress={this.goToNext.bind(this,row.id,rowId)}></BookItem>);
    },
    _changeText:function(val){
        this.setState({
            keywords:val
        });
    },
    _search:function(){
        this.getData();
    },
    //根据关键字查询
    getData:function(){
        var ds = new ListView.DataSource({rowHasChanged:(r1,r2)=>r1!==r2});
        var that = this;
        var baseUrl = ServiceURL.book_search+'?count=10&q='+this.state.keywords;
        //开启loading
        this.setState({
            show:false
        });
        //get获取数据
        Util.get(baseUrl,function(data){
            if (!data.books || !data.books.length) {
                return alert('图书服务出错');
            }
            var books = data.books;
            that.setState({
                dataSource:ds.cloneWithRows(books),
                show:true
            });
        },function(err){
            alert(err);
        });
    },
    goToNext:function(id,rowId){
        console.log(rowId);
            if (rowId === '0') {
                this.props.navigator.push({
            component:Login,
            title:'登录',
            });
        }else{
    this.props.navigator.push({
      component:BookDetail,
      title:id,
      passProps:{id:id},
    });
     }
    },
    _headerView:function(){
    return (<View style={{height:40},{alignItems:'center'},
      {flexDirection:'row'}}>
      <Text style={{marginLeft:15}}>图书表头</Text></View>);
  }

});

屏幕快照 2018-04-09 下午4.28.28.png

下面就不在贴电影和登录页的代码了,直接给码云的git的地址:https://gitee.com/lumic/SouApp.git
代码比较乱,里面很多是一些实践的东西,只是作为自己学习的记录。

相关文章

  • ReactNative快应用时代,是选择还是放弃?

    React Native已经推出好几年,越来越多的app在使用该技术进行项目的开发,而今年3月份安卓阵营的快应用的...

  • 是选择还是放弃?

    昨晚做了一个梦,时不时浮现脑海。 梦里我在跟一个老师学画画,跟她的女儿一起画画。而这个老师是我所敬仰的。都说,日有...

  • ReactNative和原生的相互调用

    ReactNative? 是Facebook开源的跨平台移动应用开发框架 ReactNative的导入 iOS使用...

  • (2)Angular的开发

    什么是 ReactNative应用, 小程序与RN的关系 native端优化 Js端优化 ReactNative是...

  • 选择放弃,还是放弃选择

    人的一生中,会有很多抉择,需要去选择。小时候,我们可以无忧无虑,吃饭睡觉上学,都是父母帮我们选择,然后再告诉我们最...

  • ReactNative简介

    ReactNative简介 ReactNative是Facebook于2015年4月开源的跨平台移动应用开发框架,...

  • 为什么我们擅长模仿而不善于创造

    ps: 最近在写Web框架,同时也在用ReactNative写一个OS X桌面应用。突然发现不管是框架,还是应用,...

  • 是坚守还是选择放弃

    周四,跨贸办的同事让我约两家税源企业,说是想去走访。我和这两家分别做了沟通,一家很爽气,欢迎我们随时过去...

  • 成就自己是一个什么样的过程?

    这个时代的挑战很多, 机会也很多, 但你选择放弃? 还是选择继续努力? 不是时代抛弃你,时代一直在进步,而且从来没...

  • 放弃还是选择

    睡前老公突然一本正经的盯着我,严肃的说:老婆,易灸灸咱能不能不做了? 我瞬间懵逼,我知道他一直不喜欢我做微商,想让...

网友评论

    本文标题:ReactNative快应用时代,是选择还是放弃?

    本文链接:https://www.haomeiwen.com/subject/zoabhftx.html