从 react 到
react native

如何安装
create-react-app
npm install -g create-react-app
create-react-app my-app
cd my-app
npm start
react
npm install -g yarn react-native-cli
react-native init AwesomeProject
cd AwesomeProject
react-native run-android
react-native-cli
* 集成到原生应用略有不同
react native
如何调试
react
-
react 浏览器插件
-
redux 浏览器插件
-
摇一摇,在调试页面F12
-
0.43以上版本能下载react-devtools,可以查看app结果和props、styles,基本交互同react浏览器插件
react native

样式
- 写法
react
className
render() {
return <span className="menu navigation-menu">Menu</span>
}
inline style
var divStyle = {
color: 'white',
backgroundImage: 'url(' + imgUrl + ')',
WebkitTransition: 'all', // note the capital 'W' here
msTransition: 'all' // 'ms' is the only lowercase vendor prefix
};
ReactDOM.render(<div style={divStyle}>Hello World!</div>, mountNode);
或
react native
创建一个样式表:
var styles = StyleSheet.create({
container: {
borderRadius: 4,
borderWidth: 0.5,
borderColor: '#d6d7da',
},
title: {
fontSize: 19,
fontWeight: 'bold',
},
activeTitle: {
color: 'red',
},
});
使用一个样式表:
<View style={styles.container}>
<Text style={[styles.title, this.props.isActive && styles.activeTitle]} />
</View>
并不是真正的css样式
样式
- 布局
react
传统的css布局
position
static, relative, absolute, fixed...
display
inline, block, inline-block, table, flex, grid ...
灵活
react native
够用
- 每个组件自带relative特性,可以声明为absolute
- 主要使用flex进行布局
associatedKeysScrollWrap: {
position: 'absolute',
width: WindowSize.WIDTH,
height: WindowSize.HEIGHT - HEADER_HEIGHT,
top: HEADER_HEIGHT,
left: 0,
},
associatedKeysContainer: {
flex:1,
paddingBottom: WindowSize.HEIGHT / 2
},
associatedKeysItem: {
width: WindowSize.WIDTH,
height: 56,
flexDirection: 'row',
justifyContent: 'flex-start',
alignItems: 'center',
},
searchIcon: {
marginLeft: 20,
},
associatedKeysText: {
marginLeft: 20,
fontSize: 16,
color: 'rgba(33,33,33,0.9)'
},

图片
react
<img className="preview-image"
src={source}
onClick={this.loadImage.bind(this)}/>
react
react native
引用网络资源
<Image style={styles.image}
source={{uri: this.imageUrl}}/>
引用本地资源
<Image resizeMode='stretch'
source={{uri: 'icon'}}
style={styles.icon} />
混合App(一部分UI使用React Native,而另一部分使用原生),可以使用已经打包到App中的图片资源(以拖拽的方式放置在Xcode的asset类目中,或是放置在Android的drawable目录里)。注意此时只使用文件名,不带路径也不带后缀
引用本地资源 - 2
<Image source={require('./img/icon.png')} />
会将资源打包进整个bundle
在web中,如果我们不规定图片的尺寸,图片在加载前不占空间,之后按自身大小显示
但是在rn中,为了防止这种情况造成的视图抖动,官方规定需要提前赋予图片尺寸(除非是require方式加载图片),否则图片无法显示。
在rn中,特殊图片格式,如gif, webp, 动态webp等需要额外添加支持。
注意
图片
背景图片
react
使用css
.container { //以图片中心为基准进行原比例缩放,以覆盖整个背景
background-image: url("../images/bg.webp");
background-position: 50% 50%;
background-size: cover; // contain | 100% | 100% 100% | ...
background-repeat: no-repeat;
}
灵活
react native
Image做为父组件
<Image style={styles.bg}
source={{uri: this.bgImg}}
resizeMode={'stretch'}> // 'contain' | 'cover'
<Text style={styles.text}>
{text}
</Text>
</Image>
不太兼容
Image做为子组件,撑满容器
container: {
width: w,
height: h,
},
bg: {
width: w,
height: h,
position: 'absolute',
borderRadius: 1,
left: 0,
},
<ImageBackground>
勉强够用
事件
点击事件
react
任何组件都可以绑定onClick事件
* 移动端有必要的话需要处理300ms延时
react
需要用TouchableXX组件接收点击事件
react native
- TouchableOpacity:透明度改变
- TouchableHighlight:背景颜色和透明度改变
- TouchableNativeFeedback:在安卓上,有涟漪效果
- TouchableWithoutFeedback:不显示任何视觉反馈
<TouchableOpacity
style={styles.button}
onPress={this.handlePress.bind(this)}>
{children}
</TouchableOpacity>
* 也可以用PanResponder类指定触摸事件接收的对象
由于处理点击事件和点击时的交互都会占用js资源,会导致交互样式掉帧。
需要在处理事件时添加时延(一般为300ms),并在componenWillUnmount时清除
handleClick() {
this.clickTimeout = setTimeout(() => {
// do something
}, 300)
注意
事件
back键
react
1. 跟客户端配合;
2. 使用History API
react
提供原生支持
BackAndroid.exitApp();
react native
// mount时添加监听
BackAndroid.addEventListener('hardwareBackPress', this.handleBackButton);
// unmount时移除监听
BackAndroid.removeEventListener('hardwareBackPress', this.handleBackButton);
handleBackButton() {
// ...
if(flag){
return true; // 暂时不退出
}
return false; // 立刻退出
}
跟原生的交互
react
基于webview
对于Android调用JS代码的方法有2种:
1. 通过WebView的loadUrl()
2. 通过WebView的evaluateJavascript()
对于JS调用Android代码的方法有3种:
1. 通过WebView的addJavascriptInterface()进行对象映射
2. 通过 WebViewClient 的shouldOverrideUrlLoading ()方法回调拦截 url
3. 通过 WebChromeClient 的onJsAlert()、onJsConfirm()、onJsPrompt()方法回调拦截JS对话框alert()、confirm()、prompt() 消息
window.webviewSelected = () => { // 客户端调用js代码,在离开该webview时执行
AHandler.foo();// 通过js调用客户端代码
};
react native
1. RCTDeviceEventEmitter 事件
import { NativeModules } from 'react-native';
const NativeModule = NativeModules.NativeModule;
NativeModule.foo(
JSON.stringify(data),
() => {// do something},
(err) => { // do something}
);
const { DeviceEventEmitter} = ReactNative;
DeviceEventEmitter.addListener('event_name', this.handleEvent);
2和3相似。
客户端继承ReactContextBaseJavaModule创建模块,按照rn指定的步骤注册并添加模块;
前端引用react-native的NativeModules模块,继而调用客户端定义的模块。
import { NativeModules } from 'react-native';
const NativeClientInfo = NativeModules.NativeModule;
NativeModule.foo('xx').then(v => {
bar(v);
});
2. Callback 回调
3. Promise 回调
其他
动画
Animated
LayoutAnimation
只能控制width, height,在flex布局中自动呈现动态效果
用起来很爽的组件
ListView => FlatView
From React to React Native
By Esther Y
From React to React Native
- 842