Skip to content

React-Native #15

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
Wscats opened this issue Oct 31, 2018 · 0 comments
Open

React-Native #15

Wscats opened this issue Oct 31, 2018 · 0 comments

Comments

@Wscats
Copy link
Owner

Wscats commented Oct 31, 2018

安装

我们推荐使用Homebrew来安装NodeWatchman。在命令行中执行下列命令安装:

brew install node
brew install watchman

如果你已经安装了 Node,请检查其版本是否在 v8.3 以上。安装完 Node 后建议设置 npm 镜像以加速后面的过程(或使用科学上网工具)。

注意:不要使用 cnpm!cnpm 安装的模块路径比较奇怪,packager 不能正常识别!

npm config set registry https://registry.npm.taobao.org --global
npm config set disturl https://npm.taobao.org/dist --global

Yarn、React Native 的命令行工具(react-native-cli)
Yarn是 Facebook 提供的替代 npm 的工具,可以加速 node 模块的下载。React Native 的命令行工具用于执行创建、初始化、更新项目、运行打包服务(packager)等任务

npm install -g yarn react-native-cli

安装完 yarn 后同理也要设置镜像源:

yarn config set registry https://registry.npm.taobao.org --global
yarn config set disturl https://npm.taobao.org/dist --global

创建项目

使用 React Native 命令行工具来创建一个名为AwesomeProject的新项目:

react-native init AwesomeProject
cd AwesomeProject && npm install

启动

进入ios文件夹用Xcode打开AwesomeProject.xcodeproj文件,并启动
屏幕快照 2019-06-30 上午7 13 52

props

大多数组件在创建时就可以使用各种参数来进行定制。用于定制的这些参数就称为props属性。

class Greeting extends Component {
  render() {
    return (
      <View style={{alignItems: 'center', marginTop: 50}}>
        <Text>Hello {this.props.name}!</Text>
      </View>
    );
  }
}

type Props = {};
export default class App extends Component<Props> {
  render() {
    return (
      <View style={styles.container}>
        <Text style={styles.welcome}>Welcome1 to React Native!</Text>
        <Text style={styles.instructions}>To get started, edit App.js</Text>
        <Text style={styles.instructions}>{instructions}</Text>
        <Greeting name='Rexxar' />
        <Greeting name='Jaina' />
        <Greeting name='Valeera' />
      </View>
    );
  }
}

布局

在组件样式中使用flex可以使其在可利用的空间中动态地扩张或收缩。一般而言我们会使用flex:1来指定某个组件扩张以撑满所有剩余的空间。如果有多个并列的子组件使用了flex:1,则这些子组件会平分父容器中剩余的空间。如果这些并列的子组件的flex值不一样,则谁的值更大,谁占据剩余空间的比例就更大(即占据剩余空间的比等于并列组件间flex值的比)。

屏幕快照 2019-06-30 下午9 55 37

<View style={{ flex: 1 }}>
    <View style={{ flex: 1, backgroundColor: 'powderblue' }} />
    <View style={{ flex: 2, backgroundColor: 'skyblue' }} />
    <View style={{ flex: 3, backgroundColor: 'steelblue' }} />
</View>

组件

可以新建src/components 文件夹新建Greeting.js,并在App.js中引入import Greeting from './components/Greeting/Greeting.js';,并使用<Greeting name='Eno Yao’ />

import React, { Component } from 'react';
import { Text, View } from 'react-native';
export default class Greeting extends Component {
    render() {
        return (
            <View style={{ alignItems: 'center', marginTop: 50 }}>
                <Text>Hello {this.props.name}!</Text>
            </View>
        );
    }
}

事件

点击这个按钮会调用onPress函数,具体作用就是显示一个 alert 弹出框。

react react-native
onClick onPress
onChange onChangeText
import React, { Component } from 'react';
import { Text, View, Button, Alert } from 'react-native';
export default class Greeting extends Component {
    render() {
        return (
            <View style={{ alignItems: 'center', marginTop: 50 }}>
                <Text>Hello {this.props.name}!</Text>
                <Button
                    onPress={() => {
                        Alert.alert("你点击了按钮!");
                    }}
                    title="点我!"
                />
            </View>
        );
    }
}

处理文本输入

TextInput是一个允许用户输入文本的基础组件。它有一个名为onChangeText的属性,此属性接受一个函数,而此函数会在文本变化时被调用。另外还有一个名为onSubmitEditing的属性,会在文本被提交后(用户按下软键盘上的提交键)调用。

<TextInput
    style={{ height: 40 }}
    placeholder="Type here to translate!"
    onChangeText={(text) => this.setState({ text })}
/>
<TextInput
    // style={{ height: 40 }}
    placeholder="Type here to translate!"
    onChangeText={this.onChangeText.bind(this)}
/>
// js
onChangeText(text) {
    console.log(text)
    this.setState({ text })
}

导航

在你的React Native项目中安装react-navigation这个包

yarn add react-navigation
# or with npm
# npm install --save react-navigation

然后,安装react-native-gesture-handler

yarn add react-native-gesture-handler
# or with npm
# npm install --save react-native-gesture-handler

Link所有的原生依赖,这一步是必须的,之前漏了这一步在这里花费了很多时间

屏幕快照 2019-06-30 上午9 42 41

react-native link react-native-gesture-handler
# or
react-native link

App.js中把代码替换为下面这些

import React, { Component } from 'react';
import { Text, View, Button } from 'react-native';
import { createAppContainer, createStackNavigator, StackActions, NavigationActions } from 'react-navigation'; // Version can be specified in package.json

class HomeScreen extends Component {
  render() {
    return (
      <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
        <Text>Home Screen</Text>
        <Button
          title="Go to Details"
          onPress={() => {
            this.props.navigation.dispatch(StackActions.reset({
              index: 0,
              actions: [
                NavigationActions.navigate({ routeName: 'Details' })
              ],
            }))
          }}
        />
      </View>
    );
  }
}

class DetailsScreen extends Component {
  render() {
    return (
      <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
        <Text>Details Screen</Text>
      </View>
    );
  }
}

const AppNavigator = createStackNavigator({
  Home: {
    screen: HomeScreen,
  },
  Details: {
    screen: DetailsScreen,
  },
}, {
    initialRouteName: 'Home',
  });

export default createAppContainer(AppNavigator);

导航跳转

<Button
  title="Go to Home"
  onPress={() => this.props.navigation.navigate('Home')}
/>

将路由页面封装模块化封装进组件里面

import { createAppContainer, createStackNavigator } from 'react-navigation'; // Version can be specified in package.json

import DetailsScreen from './src/components/DetailsScreen/DetailsScreen'
import HomeScreen from './src/components/HomeScreen/HomeScreen'

const AppNavigator = createStackNavigator({
  Home: {
    screen: HomeScreen,
  },
  Details: {
    screen: DetailsScreen,
  },
}, {
    initialRouteName: 'Home',
});

export default createAppContainer(AppNavigator);

导航栏标题

屏幕快照 2019-06-30 下午8 52 54

class HomeScreen extends React.Component {
  static navigationOptions = {
    title: 'Home',
  };
}

导航栏按钮

屏幕快照 2019-06-30 下午9 08 51

class LogoTitle extends React.Component {
    render() {
        return (
            <Image
                source={require('../../assets/spiro.png')}
                style={{ width: 30, height: 30 }}
            />
        );
    }
}
export default class DetailsScreen extends Component {
    static navigationOptions = {
        title: 'Detail',
        headerTitle: <LogoTitle />,
        headerRight: (
            <Button
                title="菜单"
                onPress={() => alert('This is a button!')}
                title="Info"
                color="#58bc58"
            />
        ),
    };
    // other code
}

底部导航条

Kapture 2019-07-02 at 13 19 46

import { createAppContainer, createStackNavigator, createBottomTabNavigator } from 'react-navigation'; // Version can be specified in package.json

import DetailsScreen from './src/components/DetailsScreen/DetailsScreen'
import HomeScreen from './src/components/HomeScreen/HomeScreen'
import MineScreen from './src/components/MineScreen/MineScreen'


const MineNavigator = createStackNavigator({
  Mine: {
    screen: MineScreen,
  },
  Details: {
    screen: DetailsScreen,
  },
}, {
    initialRouteName: 'Mine',
  });

const HomeNavigator = createStackNavigator({
  Home: {
    screen: HomeScreen,
  },
  Details: {
    screen: DetailsScreen,
  },
}, {
    initialRouteName: 'Home',
  });

const TabNavigator = createBottomTabNavigator({
  Home: HomeNavigator,
  Mine: MineNavigator,
}, {
    tabBarOptions: {
      activeTintColor: 'tomato',
      inactiveTintColor: 'gray',
    },
  });
export default createAppContainer(TabNavigator);

网络

React Native 提供了和 web 标准一致的Fetch API,用于满足开发者访问网络的需求。如果你之前使用过XMLHttpRequest(即俗称的 ajax)或是其他的网络 API,那么 Fetch 用起来将会相当容易上手。

async componentDidMount() {
    try {
      let response = await fetch('https://cnodejs.org/api/v1/topics');
      console.log(response.json());
    } catch (error) {
      console.error(error);
    }
}
// or
async componentDidMount() {
    var request = new XMLHttpRequest();
    request.onreadystatechange = (e) => {
      if (request.readyState !== 4) {
        return;
      }
      if (request.status === 200) {
        console.log('success', request.responseText);
      } else {
        console.warn('error');
      }
    };
    request.open('GET', 'https://cnodejs.org/api/v1/topics');
    request.send();
}

基础组件

Picker

Kapture 2019-06-30 at 17 50 24

本组件可以在iOS和Android上渲染原生的选择器Picker

import React, { Component } from 'react';
import { Text, View, Picker } from 'react-native';
export default class HomeScreen extends Component {
  constructor(props) {
    super(props);
    this.state = {
      language: 'java',
      itemIndex: 0,
      pickers: [{
        label: 'Java',
        value: 'java'
      }, {
        label: 'JavaScript',
        value: 'js'
      }, {
        label: 'Python',
        value: 'py'
      }]
    };

    this.setDate = this.setDate.bind(this);
  }
  render() {
    return (
      <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
        <Picker
          selectedValue={this.state.language}
          style={{ height: 50, width: 100 }}
          onValueChange={(itemValue, itemIndex) => this.setState({ language: itemValue, itemIndex })}>
          {
            this.state.pickers.map((item, index) => {
              return (<Picker.Item key={index} label={item.label} value={item.value} />)
            })
          }
        </Picker>
        <Text>{this.state.language}{this.state.itemIndex}</Text>
      </View>
    );
  }
  setDate(newDate) {
    this.setState({ chosenDate: newDate })
  }
}

ScrollView && FlatList

Kapture 2019-06-30 at 18 30 12

能实现下拉刷新

import React, { Component } from 'react';
import { Text, ScrollView, FlatList, StyleSheet, RefreshControl } from 'react-native';
export default class HomeScreen extends Component {
  constructor(props) {
    super(props);
    this.state = {
      refreshing: false,
    };
  }
  _onRefresh = () => {
    this.setState({ refreshing: true });
    setTimeout(() => {
      this.setState({ refreshing: false });
    }, 2000)
  }
  render() {
    return (
      <ScrollView refreshControl={
        <RefreshControl
          title='下拉刷新'
          titleColor='#58bc58'
          refreshing={this.state.refreshing}
          onRefresh={this._onRefresh}
        />} contentContainerStyle={styles.contentContainer}>
        <Text style={styles.TextStyle}>1</Text>
      </ScrollView>
    );
  }
}
const styles = StyleSheet.create({
  contentContainer: {
    paddingVertical: 20,
    padding: 20
  },
  TextStyle: {
    color: 'red',
    borderStyle: 'solid'
  }
});

Kapture 2019-06-30 at 20 18 21

FlatList更适于长列表数据,且元素个数可以增删。和ScrollView不同的是,FlatList并不立即渲染所有元素,而是优先渲染屏幕上可见的元素。

FlatList组件必须的两个属性是data和renderItem。data是列表的数据源,而renderItem则从数据源中逐个解析数据,然后返回一个设定好格式的组件来渲染。

import React, { Component } from 'react';
import { Text, ScrollView, FlatList, StyleSheet, RefreshControl } from 'react-native';
export default class HomeScreen extends Component {
  constructor(props) {
    super(props);
    this.state = {
      refreshing: false,
      data: []
    };
  }
  async _onRefresh() {
    this.setState({ refreshing: true });
    var self = this;
    var request = new XMLHttpRequest();
    request.onreadystatechange = (e) => {
      if (request.readyState !== 4) {
        return;
      }
      if (request.status === 200) {
        console.log('success', JSON.parse(request.responseText).data);
        self.setState({
          data: this.state.data.concat(JSON.parse(request.responseText).data)
        })
        self.setState({ refreshing: false });
      } else {
        console.warn('error');
      }
    };
    request.open('GET', 'https://cnodejs.org/api/v1/topics');
    request.send();
  }
  async componentDidMount() {
    this._onRefresh();
  }
  render() {
    return (
      <FlatList refreshControl={
        <RefreshControl
          title='下拉刷新'
          titleColor='#58bc58'
          refreshing={this.state.refreshing}
          onRefresh={this._onRefresh.bind(this)}
        />} contentContainerStyle={styles.contentContainer}
        data={this.state.data}
        renderItem={({ item }) => <Text style={styles.item}>{item.title}</Text>}
        keyExtractor={(item) => item.id}
      />
    );
  }
}
const styles = StyleSheet.create({
  contentContainer: {
    paddingVertical: 20,
    padding: 20
  },
  TextStyle: {
    color: 'red',
    borderStyle: 'solid'
  }
});

实现上拉刷新

<FlatList
        onEndReached={this.onEndReached.bind(this)}
        onEndReachedThreshold="0.05"
/>

参考文档

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant