从 react 到 react native
之前团队分享的时候讲了这个主题,点这里查看slide(含图片)。
react只是提供了一个VM的框架,react native则在react的基础上,封装了原生的组件,以及热更新的方法。因此,对一个写惯了css样式的前端工程师来说,rn充满了限制,但是跟如同一张白纸可以随意涂鸦的react相比,react native 自带各种官方轮子,在一定程度上十分便利。
本文讨论react和react native的区别,不仅仅是语法上的,其实也是纯web、以webview为基础的混合应用以及rn为基础的混合应用的一些区别。
如何安装
react
:create-react-app
1 | npm install -g create-react-app |
react native
:react-native-cli
1 | npm install -g yarn react-native-cli |
如何调试
react
:热替换,react 的浏览器插件,redux浏览器插件
react native
:
- 摇一摇
- 在调试页面chrome F12(支持打断点、查看log,但是不能查看app结构)
- 0.43以上版本能下载
react-devtools
,可以查看app结果和props、styles,基本交互同react浏览器插件。 调试 - React Native 中文网
样式写法
react
,一般通过className引用普通css样式,行内则使用驼峰命名法
classnames1
2
3render() {
return <span className="menu navigation-menu">Menu</span>
}
Inline Styles | React1
2
3
4
5
6
7
8var 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
:无论是行内还是引用都是驼峰命名,虽然写法跟css大多一样,但不是真的css样式。官方说明。
样式布局
react
:传统的css布局
1 | position |
相比之下更为灵活
react native
:
- 每个组件自带
relative
特性,可以声明为absolute
- 主要使用
flex
进行布局
图片引用
react
1 | <img className="preview-image" src={source} onClick={this.loadImage.bind(this)}/> |
react native
引用网络资源1
<Image source={{uri: `http://${GEMINI_STORE.config.cdnHostname}/international/shop/v5870/default/resource/images/icons/customize_icon_new.png`}}/>
引用本地资源
如果你在编写一个混合App(一部分UI使用React Native,而另一部分使用平台原生代码),也可以使用已经打包到App中的图片资源(以拖拽的方式放置在Xcode的asset类目中,或是放置在Android的drawable目录里)。注意此时只使用文件名,不带路径也不带后缀
1 | <Image resizeMode='stretch' |
将本地资源一起打包1
<Image source={require('./img/icon.png')} />
注意:在web中,如果我们不规定图片的尺寸,图片在加载前不占空间,之后按自身大小显示;但是在rn中,为了防止这种情况造成的视图抖动,官方规定需要提前赋予图片尺寸(除非是require方式加载图片),否则图片无法显示。
背景图片
react
:css中的背景图片
1 | .container { //以图片中心为基准进行原比例缩放,以覆盖整个背景 |
可以调整background-position
、background-size
、background-repeat
等值来达到背景图片的不同自适应效果和位置,非常灵活。
react native
:直接用Image组件实现。1
2
3
4
5<Image style={styles.bg}
source={{uri: this.bgImg}}
resizeMode={'stretch'}>
<Text style={styles.text}>{'more'}</Text>
</Image>
但是由于Image组件做背景时有各种兼容问题,比如border-radius失效等等。所以我们也可以采用假背景——将图片作为子组件,但是使用absolute定位,高宽与容器相同,从而达到背景图的效果。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24<View style={styles.scrollContainer}>
<Image source={{uri: this.bgImg}}
resizeMode={'stretch'}
style={styles.bg} />
<View style={styles.contentWrap}>
{this.renderTitle()}
{dataList.map(this.renderItem.bind(this))}
</View>
</View>
const styles = StyleSheet.create({
scrollContainer: {
width: w,
height: h,
},bg: {
width: w,
height: h,
position: 'absolute',
left: 0,
borderRadius: 2,
},
//...
})
官方也有类似的暂代方案:ImageBackground,在Image组件的兼容问题未解决之前,可以使用这个代替。
动画
react
:
- css动画,处理简单动画和交互
- js动画,流程上较复杂的动画
- cavas或svg,涉及各种几何变换的超复杂动画
react native
:
- Animated,适用于各种复杂动画,性能很好
- LayoutAnimation,用于更新flexbox布局和元素本身高宽变化,使用范围有限但是性能更高-
点击事件
react
:任何组件都可以绑定onClick事件
react native
:需要用TouchableXX组件接收点击事件,Touchable家族有如下组件——
TouchableOpacity:透明度改变
TouchableHighlight:背景颜色和透明度改变
TouchableNativeFeedback:在安卓上,有涟漪效果
TouchableWithoutFeedback:不显示任何视觉反馈
由于处理点击事件和点击时的交互都会占用js资源,会导致交互样式掉帧。需要在处理事件时添加300ms时延,并在unmount时清除——
1 | handleClick() { |
跟原生的交互
就不从原理层面上说明了,实际上应该是react native实现了跟webview差不多的解释器
react
:基于webview
参考:Android:你要的WebView与 JS 交互方式 都在这里了 - CSDN博客
对于Android调用JS代码的方法有2种:
- 通过WebView的loadUrl()
- 通过WebView的evaluateJavascript()
对于JS调用Android代码的方法有3种:
- 通过WebView的addJavascriptInterface()进行对象映射
- 通过 WebViewClient 的shouldOverrideUrlLoading ()方法回调拦截 url
- 通过 WebChromeClient 的onJsAlert()、onJsConfirm()、onJsPrompt()方法回调拦截JS对话框alert()、confirm()、prompt() 消息
1 | window.webviewSelected = () => { // 客户端调用js代码,在离开该webview时执行 |
react native
:
参考:React Native与Android原生通信交互详情 | 江清清的技术专栏
1.RCTDeviceEventEmitter 事件
1 | const { DeviceEventEmitter} = ReactNative; |
2和3在安卓上的实现相似。客户端继承ReactContextBaseJavaModule定义方法,前端引用react-native的NativeModules模块,继而调用客户端定义的module
2.Callback 回调
1 | import { NativeModules } from 'react-native'; |
3.Promise 回调
1 | import { NativeModules } from 'react-native'; |