React Native 内嵌h5页面(基于vue)的实现方案调研
React Native 是目前流行的跨平台移动应用开发框架之一。通过采用不同的方法进行混合移动应用开发,它不会生成原生 UI 组件,而是基于 React,React Native 是一个用于构建基于 Web 的交互界面的 JavaScript 库,因此会有更丰富的 UI 体验效果,同时也能够很好地调用底层框架的UI使用。 React Native 已经成为一种流行的移动开发技术,它提供了一个使用
React Native 是目前流行的跨平台移动应用开发框架之一。通过采用不同的方法进行混合移动应用开发,它不会生成原生 UI 组件,而是基于 React,React Native 是一个用于构建基于 Web 的交互界面的 JavaScript 库,因此会有更丰富的 UI 体验效果,同时也能够很好地调用底层框架的UI使用。 React Native 已经成为一种流行的移动开发技术,它提供了一个使用 JavaScript 构建原生跨平台移动应用的强大框架。
在做原生开发时,一般我们会有一些加载H5网页的需求,或者需要内嵌类似vue等前端框架开发的web 页面。我们知道在Android 或者 ios中实现这个功能的控件是WebView,在ReactNative中也有实现此类需求的组件,它的名字也是WebView,后来单独集成为第三方组件 react-native-webview。
1. ReactNative 页面引用 WebView
react-native-webview 组件的安装:
npm i react-native-webview
react-native-webview 组件引用:
import { WebView } from 'react-native-webview';
WebView 标签内渲染 vue 页面,该标签下的配置信息如下:
<WebView ref={ (webView) => this.webView = webView }
originWhitelist={ ['*'] }
// 布尔值,指定WebView中是否启用JavaScript。只在Android上使用,因为在iOS上默认启用了JavaScript。
javaScriptEnabled={ true }
// 布尔值,指定是否开启DOM本地存储
domStorageEnabled={ true }
// 允许文件上传
allowFileAccess={ true }
// 在webView内部网页中,调用window.postMessage可以触发此属性对应的函数,通过event.nativeEvent.data获取接收到的数据,实现网页和RN之间的数据传递
onMessage={ this._onMessage }
//初始化调用方法
onLoad={() => { this.handleInjectJavascript();}}
// 加载时强制使用loading转圈视图,如果为true,webview可能会加载失败,显示为空白
startInLoadingState={false}
// webview加载错误页面
renderError={this.renderErrorView}
// 网络路径
// 也可以为本地路径 source={ {uri: 'http://192.168.1.1111:8080/'} }
source={ {uri: 'http://www.baidu.com/'} }
/>
2. ReactNative 与 vue交互
2.1 RN —> Vue
RN 页面在webview初始化source前,通常是调用一个方法,执行的函数是 onLoad 函数
onLoad={() => { this.handleInjectJavascript('hello world'); }}
调用的 onLoad 函数 中的 handleInjectJavascript() 方法才是真正用于给 Vue 或者 Html 页面发送数据的函数方法:
//RN webview 向 vue发送数据
handleInjectJavascript = (data) => {
// 拼接数据为方法
const injectJavascriptStr = `(function() {
window.WebViewBridge.onMessage(${JSON.stringify(data)});
})()`;
// 通过 injectJavaScript 将数据传递给WebView页面,并立即执行为js
if(this.webView) {
this.webView.injectJavaScript(injectJavascriptStr)
}
}
vue 页面接受数据:
mounted() {
window.WebViewBridge = {
onMessage: this._onMessage //在window上挂载一个onMessage方法,RN会调用
}
// 自定义事件后直接触发:
const event = new Event('WebViewBridge')
window.dispatchEvent(event);
},
methods: {
// 接收 RN 发送的消息
_onMessage(data) {
let that = this;
console.log('data ------- ',JSON.stringify(data)); // 'hello world'
}
}
以上是RN向vue 传值的过程,其具体过程:RN中给 window.WebViewBridge 增加一个名为 onMessage 的方法,vue初始化页面会对应给出onMessage 指向的方法,在此代码块 指向 _onMessage 方法并执行。
2.2 Vue —> RN
vue 页面发送数据:
mounted() {
// 自定义事件后直接触发:
const event = new Event('WebViewBridge');
window.dispatchEvent(event);
},
methods: {
// 向rn发送消息, 将值 'hello world' 挂载到 postMessage
_postMessage('hello world') {
window.ReactNativeWebView.postMessage(data);
}
}
RN 页面在接收到 vue 传输的数据之后执行 onMessage 函数方法
onMessage={ this._onMessage }
触发 _onMessage 方法获取 Vue 或者 Html 页面返回的数据
// 接受vue发送来的消息。 -- '接收vue发来的消息onMessage hello world'
_onMessage = (event) => {
console.log('接收vue发来的消息onMessage', event.nativeEvent.data);
}
2.3 Vue <—> RN (多次双向传值)
vue 页面:
mounted() {
window.WebViewBridge = {
onMessage: this._onMessage,
receiveMessage: this._receiveMessage //在window上挂载一个receiveMessage方法,RN自行调用
}
const event = new Event('WebViewBridge')
window.dispatchEvent(event);
},
methods: {
// 向rn发送消息
_postMessage('wow,RN!!') {
window.ReactNativeWebView.postMessage(data); // 将值 'wow,RN!!' 挂载到 postMessage
},
// 二次或多次接收RN发送消息
_receiveMessage(data){
let that = this;
console.log('data receiveMessage------- ',JSON.stringify(data));
}
}
RN 页面在接收到 vue 传输的数据之后执行 onMessage 函数
onMessage={ this._onMessage }
// 接受vue发送来的消息
_onMessage = (event) => {
console.log('接收vue发来的消息onMessage', event.nativeEvent.data);
// '接收vue发来的消息onMessage wow,RN!!'
const injectJavascriptStr = `(function() {
window.WebViewBridge.receiveMessage(${JSON.stringify('hello,vue2!!! ')});
})()`;
this.webView.injectJavaScript(injectJavascriptStr);
}
3. react-native-webview 组件使用总结
使用 WebView 组件我们可以通过 url 来加载显示一个网页,也可以传入一段 html 代码来显示。该组件的引入是解决 React Native 内嵌 Vue 的比较好的解决方案,该组件自带的常用属性和方法我们可以归纳如下:
3.1 主要属性:
- source:在 WebView 中载入一段静态的 html 代码或是一个 url(还可以附带一些 header 选项)
- automaticallyAdjustContentInsets:设置是否自动调整内容。格式:boolean
- contentInset:设置内容所占的尺寸大小。格式:{top:number,left:number,bottom:number,right:number}
- injectJavaScript:当网页加载之前注入一段 js 代码。其值是字符串形式。
- startInLoadingState:是否开启页面加载的状态,其值为 true 或者 false。
- bounces(仅iOS):回弹特性。默认为 true。如果设置为 false,则内容拉到底部或者头部都不回弹。
- scalesPageToFit(仅iOS):用于设置网页是否缩放自适应到整个屏幕视图,以及用户是否可以改变缩放页面。
- scrollEnabled(仅iOS):用于设置是否开启页面滚动。
- domStorageEnabled(仅Android):用于控制是否开启 DOM Storage(存储)。
- javaScriptEnabled(仅Android):是否开启 JavaScript,在 iOS 中的 WebView 是默认开启的。
3.2 主要方法:
- onNavigationStateChange:当导航状态发生变化的时候调用。
- onLoadStart:当网页开始加载的时候调用。
- onError:当网页加载失败的时候调用。
- onLoad:当网页加载结束的时候调用。
- onLoadEnd:当网页加载结束调用,不管是成功还是失败。
- renderLoading:WebView组件正在渲染页面时触发的函数,只有 startInLoadingState 为 true 时该函数才起作用。
- renderError:监听渲染页面出错的函数。
- onShouldStartLoadWithRequest(仅iOS):该方法允许拦截 WebView 加载的 URL 地址,进行自定义处理。该方法通过返回 true 或者 false 来决定是否继续加载该拦截到请求。
4. react-native-webview 组件基于RN 使用样例
4.1 场景一:直接展示外源网页信息
import React,{Component} from 'react'
import {
StyleSheet,
View,
Text,
WebView,
} from 'react-native'
export default class Root extends Component{
constructor(props){
super(props)
}
render(){
return (
<View style={styles.container}>
<WebView
source={{uri: 'https://www.baidu.com'}}
domStorageEnabled={true}
javaScriptEnabled={true}
startInLoadingState={true}
automaticallyAdjustContentInsets={true}>
</WebView>
</View>
)
}
}
const styles = StyleSheet.create({
container:{
flex:1,
},
})
程序启动后,我们使用 WebView 加载 baidu.com 并全屏显示,局部效果如下:
4.2 场景二:组件在实际登陆场景中的使用
我们有如下场景:一款 toB 的 app,面对很多家客户,每家客户都有自己的登录系统界面,并且客户要求接入自己的登录系统。这个时候就需要 webview 接入登录界面之后,进行一些 “值拦截”,进行登录状态判断。这里主要用到 webview 的 onNavigationStateChange 参数。此方法会在当导航状态发生变化的时候调用,例如取到下面的参数:
{
"canGoBack": false,
"canGoForward": false,
"loading": true,
"navigationType": "other",
"target": 229,
"title": "",
"url": "https://www.baidu.com/"
}
这里主要注意 url 字段,网页内部登录完成之后,可以发起一个重定向,前端关注 url 变化,进行登录状态的判断,同时重定向的 url 中可以拼接一些登录信息字段,用于前端登录状态校验等,例如:
{ "url": "https://www.baidu.com ? sessionId=xxx & username= xxx" }
4.3 场景三:功能模块嵌入到 RN 中
将 webview 作为功能模块载体,这个时候就会涉及到用户交互,需要 rn 与 h5 进行值的互相传递。此时就要react native 向 web 中注入 js,web 也可以主动回传数据到 react native中。webview 组件提供了 injectedJavaScript 用于向 h5 注入js,在 h5 中使用 window.ReactNativeWebView.postMessage 进行主动的回调,并且在 webview 的 onMessage 中进行字段的监听,以此就可以完成 react 和 h5 之间的数据交互。
const injectJSStr = `
window.injectStr='我是注入的字段';
var div = document.getElementById('testID');
div.style.color='red';
div.style.fontSize='100px';
`;
const html = `
<html>
<head></head>
<body>
<script>
setTimeout(function () {
window.ReactNativeWebView.postMessage(window.injectStr)
}, 2000)
</script>
<div id='testID'>Hello Word</div>
</body>
</html>
`;
......
<View style={{flex: 1}}>
<WebView
source={{html}}
injectedJavaScript={injectJSStr}
onMessage={event => {
alert(event.nativeEvent.data);
}}
/>
</View>
更多推荐
所有评论(0)