react_native 项目实战 (5) DeviceEventEmitter 使用 ,webview 使用 react navigation进行参数传递

来源:互联网 发布:mac 升级后切换花屏 编辑:程序博客网 时间:2024/06/08 11:57

今天 2017.10.26 我把android studio升级成了3.0 结果RN项目 各种问题

其他问题我用android studio 3.0 把项目打开一遍就好了 但是使用rn run android的时候 有个gradle 3.0一直下载不下来

说缺少3.0

解决:

buildscript {    repositories {        jcenter()        maven { url 'https://maven.google.com' }    }    dependencies {        classpath 'com.android.tools.build:gradle:3.0.0'        // NOTE: Do not place your application dependencies here; they belong        // in the individual module build.gradle files    }}

我是翻墙了的 不翻墙 不清楚能不能下载

分类排序数据存取

分类选择页面和首页的数据获取,存取的数据结构是:

[  {"name":"Android","checked":true},  {"name":"IOS","checked":false},  {"name":"React","checked":true},  {"name":"Java","checked":true},  {"name":"JS","checked":true}]

分类排序的页面存取的数据结构是

这里取出的值 checked 肯定是true

“name”:”Android”
“name”:”IOS”
“name”:”IOS”

举个例子

//原始数组var originalArray = [    {name:'Android',checked:true},    {name:'IOS',checked:false},    {name:'React',checked:true},    {name:'Java',checked:false},    {name:'JS',checked:true},    {name:'Python',checked:false}];//排序后的数组var sortedArray = [    {name:'JS',checked:true},    {name:'React',checked:true},    {name:'Android',checked:true}];

当分类排序过后 需要把分类排序后的数据 再次存入通用的分类数据结构.

图例:

mark

下面是js代码

/** * Created by liuml on 2017/10/22. */import React, {Component} from 'react';import {    AppRegistry,    StyleSheet,    Text,    View,    Image,    TouchableOpacity,    TouchableHighlight,    AsyncStorage,} from 'react-native';import NavigationBar from "../compoent/NavigationBar";import SortableListView from "react-native-sortable-listview";import popular_def_lans from "../../res/data/popular_def_lans.json"import Toast from "react-native-easy-toast"/** * 分类排序页面 */export default class SortKeyPage extends Component {    // 构造    constructor(props) {        super(props);        // 初始状态        this.state = {            originData: popular_def_lans,            data: [],        };        //初始化数据 把所有选中的数据放入进去        this.state.originData.forEach((item => {            if (item.checked) {                this.state.data.push(item)            }        }))    }    doBack = () => {        this.props.navigation.goBack();    }    //保存    doSave = () => {        //原始数组        var originArray = this.state.originData;        //排序后的数组        var sortedArray = this.state.data;        //要保存的数组        var savedArray = [];        //i用来遍历originalArray        //j用来遍历sortedArray        for (var i = 0, j = 0; i < originArray.length; i++) {            var item = originArray[i];            if (item.checked) {                savedArray[i] = sortedArray[j];                j++;            } else {                savedArray[i] = item;            }        }        console.log("保存读取: ");        console.log(savedArray);        AsyncStorage.setItem("custom_key", JSON.stringify(savedArray))            .then(() => {                this.refs.toast.show("保存成功");                this.doBack();            })    }    //保存    handleSave = () => {        this.doSave();    }    getLeftBtn = () => {        return <View style={{flexDirection: 'row', alignItems: 'center'}}>            <TouchableOpacity                activeOpacity={0.7}                onPress={this.doBack}>                <Image source={require('../../res/images/ic_arrow_back_white_36pt.png')}                       style={{width: 24, height: 24}}/>            </TouchableOpacity>        </View>;    }    getRightBtn = () => {        return <View style={{flexDirection: 'row', alignItems: 'center'}}>            <TouchableOpacity                onPress={this.handleSave}                activeOpacity={0.7}>                <View style={{marginRight: 10}}>                    <Text style={{fontSize: 16, color: '#FFF'}}>保存</Text>                </View>            </TouchableOpacity>        </View>;    }    componentDidMount() {        AsyncStorage.getItem("custom_key")            .then(value => {                console.log("进入读取: ");                console.log(value);                if (value != null) {                    //只获取checked为true语言,进行排序  forEach 不会返回一个数组 而map会返回一个数组                    let d = [];                    let origin = JSON.parse(value);                    origin.forEach((item) => {                        if (item.checked) {                            d.push(item);                        }                    })                    // this.setState({data: d});                    // var myorder = Object.keys(this.state.data); //Array of keys                    this.setState({originData: origin, data: d});                }            })    }    render() {        //http://www.w3school.com.cn/jsref/jsref_splice.asp   splice方法的使用        return <View style={styles.container}>            <NavigationBar                title="语言分类排序"                rightButton={this.getRightBtn()}                leftButton={this.getLeftBtn()}/>            <SortableListView                data={this.state.data}                order={Object.keys(this.state.data)}                rowActivationTime="10"                renderRow={row => <RowComponent data={row}/>}                onRowMoved={e => {                    this.state.data.splice(e.to, 0, this.state.data.splice(e.from, 1)[0]);                    this.forceUpdate();                }}            />            <Toast ref="toast"/>        </View>    }}//https://github.com/deanmcpherson/react-native-sortable-listview/blob/master/Sortable/example.js 这里是SortableListView github地址 示例代码class RowComponent extends Component {    static defaultProps = {        data: {name: ""}    };    render() {        return <TouchableHighlight            underlayColor="#EEE"            style={styles.item}            {...this.props.sortHandlers}>            <View style={{flexDirection: 'row', paddingLeft: 10}}>                <Image source={require('../../res/images/ic_sort.png')} style={styles.image}/>                <Text>{this.props.data.name}</Text>            </View>        </TouchableHighlight>    }}const styles = StyleSheet.create({    container: {        flex: 1    },    item: {        backgroundColor: '#F8F8F8',        borderBottomWidth: 1,        borderColor: '#EEE',        height: 50,        justifyContent: 'center'    },    image: {        width: 16,        height: 16,        marginRight: 10,        tintColor: '#63B8FF'    }});

可以看到 我主要的代码 就在返回保存的时候doSave 方法里面 进行排序存储

下面是效果:

mark

首页实时更新 使用 DeviceEventEmitter 发送接收事件

现在首页是我通过手动刷新js 才更新界面 现在需要 自动刷新

DeviceEventEmitter 使用方法

第一步 添加监听

DeviceEventEmitter.addListener(‘名称’,(events) ={使用数据events});

第二部 发送数据

DeviceEventEmitter.emit(‘自定义名称’,发送数据);

这样就可以了

那么现在我写一下 在首页刷新数据的监听

//路由const resetAction = NavigationActions.reset({    index: 0,    actions: [        NavigationActions.navigate({ routeName: 'Home'})    ]}) componentDidMount() {        this.listener = DeviceEventEmitter.addListener('HOMEPAGE_RELOAD', (n) => {            //主页重新加载数据            console.log("主页重新加载数据");            //跳转到新的场景,并且重置整个路由栈            this.props.navigation.dispatch(resetAction);            // this.props.navigation.resetTo({            //     component:Homepage            // })        })    }    componentWillUnmount() {        //移除监听        this.listener.remove();    }

然后在保存的时候发送数据

    //保存    handleSave = () => {        //http://lib.csdn.net/article/reactnative/43540   JSON.stringify 字符串转JSON        //AsyncStorage是一个简单的、异步的、持久化的Key-Value存储系统        AsyncStorage.setItem('custom_key', JSON.stringify(this.state.data))            .then(() => this.refs.toast.show("保存成功"));        // console.log(JSON.stringify(this.state.data));        this.doBack();        DeviceEventEmitter.emit("HOMEPAGE_RELOAD","HomePage重新加载");    }

但是发现有个bug 如果在我的页面 跳转后 返回重新加载会报错 说是和 测量的问题有关..这个就先放放.

webview使用 项目详情页面

新建ProjectDetails.js 作为项目详情页面

在PapularPage页面 点击listview 的item 跳转 把item数据内的 title 和url 传到项目详情页面

    //渲染ListView的每一行    renderRow = (obj) => {        return <ProjectRow item={obj} onSelect={() => this.handleProjectSelect(obj)}>        </ProjectRow>    }    handleProjectSelect = (obj) => {        navigation('ProjectDetails', {            params: {                title: obj.full_name,                url: obj.html_url            },        });    }

注意这里是一个比较经典的 父控件 把方法传入 子控件 子控件 回调父控件.

上面在PapularPage页面 这个onSelect 属性传入子控件ProjectRow

render() {        var item = this.props.item;        return <TouchableOpacity            activeOpacity={0.5}            onPress={this.props.onSelect}>            <View style={styles.container}>                <Text style={styles.title}>{item.full_name}</Text>                <Text style={styles.description}>{item.description}</Text>                <View style={styles.bottom}>                    <View style={styles.bottomTextWrapper}>                        <Text>作者:</Text>                        {/* {console.log(item.owner.avatar_url)}*/}                        <Image style={{width: 22, height: 22}} source={{uri: item.owner.avatar_url}}/>                    </View>                    <View style={styles.bottomTextWrapper}>                        <Text>star:</Text>                        <Text>{item.stargazers_count}</Text>                    </View>                    <Image source={require("../../res/images/ic_unstar_transparent.png")}                           style={{width: 22, height: 22}}/>                </View>            </View>        </TouchableOpacity>    }

在子控件中 onPress={this.props.onSelect} 进行回调这样就有了点击事件

而且还防止了一个问题 . 我测试过 直接在外面父控件中 使用onpress调用

this.handleProjectSelect(obj)

这个方法 会直接调用 没有点击就会调用 因为 带上了括号 所有导致这个问题 .如果我使用子控件回调的方式 也就防止了这个问题…

下面写ProjectDetails.js 这个是详情页面 用了webveiw

/** * Created by liuml on 2017/10/26. */import React, {Component} from 'react';import {    AppRegistry,    StyleSheet,    Text,    View,    Image,    TouchableOpacity,    WebView} from 'react-native';import NavigationBar from "../compoent/NavigationBar";export default class ProjectDetails extends Component {    // 构造    constructor(props) {        super(props);        // 初始状态        this.state = {            canGoBack: false        };    }    handleBack = () => {        //如果网页能够返回 先返回网页        if (this.state.canGoBack) {            this.refs.webview.goBack();        } else {            this.doBack();        }    }    doBack = () => {        this.props.navigation.goBack();    }    getLeftBtn = () => {        return <View style={{flexDirection: 'row', alignItems: 'center'}}>            <TouchableOpacity                activeOpacity={0.7}                onPress={this.handleBack}>                <Image source={require('../../res/images/ic_arrow_back_white_36pt.png')}                       style={{width: 24, height: 24}}/>            </TouchableOpacity>        </View>;    }    //监听状态改变 是否能够返回    handleNavStateChange = (s) => {        this.setState({canGoBack: s.canGoBack});    }    render() {        const {state} = this.props.navigation;        let title = state.params.params.title;        let url = state.params.params.url;        console.log("打印" + url);        return (            <View style={styles.container}>                <NavigationBar                    title={title}                    leftButton={this.getLeftBtn()}/>                <WebView                    ref="webview"                    startInLoadingState={true}                    source={{uri: url}}                    onNavigationStateChange={this.handleNavStateChange}                />            </View>        );    }}const styles = StyleSheet.create({    container: {        flex: 1    },})

有几个点
- 一个是使用react navigation 传递参数
- 一个是从react navigation 接受参数
- 一个是监听webveiw 是否可以返回

第一个点: 传递参数在上面 单独的点已经有了

第二个点: 接受参数

 const {state} = this.props.navigation;        let title = state.params.params.title;        let url = state.params.params.url;

从props里面取出navigation 然后取出他的state 两层params 最后才是数据

第三个点: 监听webview是否返回 这里webview有个自己的属性onNavigationStateChange 我在属性上面添加了一个方法

 //监听状态改变 是否能够返回    handleNavStateChange = (s) => {        this.setState({canGoBack: s.canGoBack});    }

把是否可以返回加入state中 这样当点击返回箭头的时候可以进行判断

看下最终效果图

mark

原创粉丝点击