React Native 加载H5页面的实现方法
作者:xiangzhihong8
一、基本使用
作为目前流行的移动跨平台开发技术,React Native 提供了一个使用 JavaScript 构建原生跨平台移动应用的强大框架。使用React Native开发时,经常会遇到加载H5网页的需求,此时需要用到react-native-webview
插件来执行H5网页的加载。
使用插件之前,需要先安装npm i react-native-webview
插件,命令如下:
npm i react-native-webview
然后,就可以在业务代码中引入react-native-webview
插件的WebView组件,比如:
<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/'} } />
使用WebView组件加载H5页面时,必然会涉及到交互。
1.1 RN向H5发送数据
如果是RN向H5发送数据,那么可以调用onLoad函数的handleInjectJavascript() 方法。
//RN webview 向 vue发送数据 handleInjectJavascript = (data) => { // 拼接数据为方法 const injectJavascriptStr = `(function() { window.WebViewBridge.onMessage(${JSON.stringify(data)}); })()`; // 通过 injectJavaScript 将数据传递给WebView页面,并立即执行为js if(this.webView) { this.webView.injectJavaScript(injectJavascriptStr) } }
如果有回调的结果,需要在mounted生命周期函数中,
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向H5 传值的过程,其具体过程:RN中给 window.WebViewBridge
增加一个名为 onMessage 的方法,H5初始化页面会对应给出onMessage 指向的方法,在此代码块 指向 _onMessage 方法并执行。
1.2 H5向RN传递数据
如果是H5页面主动向RN发送数据,需要用到postMessage方法。
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 = (event) => { console.log('接收vue发来的消息onMessage', event.nativeEvent.data); }
1.3 双向传值
当然,有时候,也会涉及到多次双向传递的情况。
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 页面在接收到 H5 传输的数据之后执行 onMessage 函数。
onMessage={ this._onMessage } // 接受H5发送来的消息 _onMessage = (event) => { console.log('接收H5发来的消息onMessage', event.nativeEvent.data); const injectJavascriptStr = `(function() { window.WebViewBridge.receiveMessage(${JSON.stringify('hello,vue2!!! ')}); })()`; this.webView.injectJavaScript(injectJavascriptStr); }
二、属性和方法
使用 WebView 组件我们可以通过 url 来加载显示一个网页,也可以传入一段 html 代码来显示。该组件的引入是解决 React Native 内嵌 H5 的比较好的解决方案,该组件自带的常用属性和方法我们可以归纳如下:
2.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 是默认开启的。
2.2 方法
- onNavigationStateChange:当导航状态发生变化的时候调用。
- onLoadStart:当网页开始加载的时候调用。
- onError:当网页加载失败的时候调用。
- onLoad:当网页加载结束的时候调用。
- onLoadEnd:当网页加载结束调用,不管是成功还是失败。
- renderLoading:WebView组件正在渲染页面时触发的函数,只有 startInLoadingState 为 true 时该函数才起作用。
- renderError:监听渲染页面出错的函数。
- onShouldStartLoadWithRequest(仅iOS):该方法允许拦截 WebView 加载的 URL 地址,进行自定义处理。该方法通过返回 true 或者 false 来决定是否继续加载该拦截到请求。
三、使用示例
3.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, }, })
上面是一个加载百度首页的示例。
3.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" }
3.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>
3.4 完整示例
例如,有下面一个需求:RN里面通过触发刷新使H5界面的背景色可以随机改变;H5 界面我们写一个简单的 input 输入使输入的文字可以在RN 显示出来。
import React, {Component} from 'react'; import {Text, StyleSheet, View, Button} from 'react-native'; import WebView from 'react-native-webview'; export default class App extends Component { state = {colorIndex: 0, tip: '原生的Text组件,等webview中的发送。。'}; changeColor = () => { this.webview.reload(); let colorIndex = this.state.colorIndex; colorIndex = ++colorIndex % 5; this.setState({colorIndex}); }; recieve = msg => { let data = msg.nativeEvent.data; let uname = JSON.parse(data).uname; this.setState({tip: uname}); }; render() { let colors = ['gray', 'yellow', 'red', 'antiquewhite', 'white']; let scriptStr = `document.body.style.backgroundColor='${ colors[this.state.colorIndex] }'`; return ( <View style={{flex: 1}}> <Button title="刷新WebView的背景色" onPress={this.changeColor} /> <Text style={{fontSize: 30}}>{this.state.tip}</Text> <WebView onMessage={this.recieve} ref={ref => (this.webview = ref)} injectedJavaScript={scriptStr} source={{uri: 'http://192.168.180.241:8080/test.html'}} /> </View> ); } }
H5的代码如下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <input class="info" name="uname" value="John" /> <br> <button class="info">发送给原生组件</button> <script> document.querySelector('button').addEventListener('click', () => { let uname = document.querySelector('input[name="uname"]').value let msg = JSON.stringify({ uname }) window.ReactNativeWebView.postMessage(msg) }) </script> </body> </html>
到此这篇关于React Native 加载H5页面的文章就介绍到这了,更多相关React Native H5页面内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!