React Native 中使用 WebView 載入本地 html
1. 主要屬性
- source:在 WebView 中載入一段靜態的 html 程式碼或是一個 url(還可以附帶一些 header 選項)
- automaticallyAdjustContentInsets:設定是否自動調整內容。格式:bool
- contentInset:設定內容所佔的尺寸大小。格式:{top:number,left:number,bottom:number,right:number}
- injectJavaScript:當網頁載入之前注入一段 js 程式碼。其值是字串形式。
- startInLoadingState:是否開啟頁面載入的狀態,其值為 true 或者 false。
- bounces(僅iOS):回彈特性。預設為 true
- scalesPageToFit(僅iOS):用於設定網頁是否縮放自適應到整個螢幕檢視,以及使用者是否可以改變縮放頁面。
- scrollEnabled(僅iOS):用於設定是否開啟頁面滾動。
- domStorageEnabled(僅Android):用於控制是否開啟 DOM Storage(儲存)。
- javaScriptEnabled(僅Android):是否開啟 JavaScript,在 iOS 中的 WebView 是預設開啟的。
2.主要方法
- onNavigationStateChange:當導航狀態發生變化的時候呼叫。
- onLoadStart:當網頁開始載入的時候呼叫。
- onError:當網頁載入失敗的時候呼叫。
- onLoad:當網頁載入結束的時候呼叫。
- onLoadEnd:當網頁載入結束呼叫,不管是成功還是失敗。
- renderLoading:WebView元件正在渲染頁面時觸發的函式,只有 startInLoadingState 為 true 時該函式才起作用。
- renderError:監聽渲染頁面出錯的函式。
- onShouldStartLoadWithRequest(僅iOS):該方法允許攔截 WebView 載入的 URL 地址,進行自定義處理。該方法通過返回 true 或者 falase 來決定是否繼續載入該攔截到請求。
3.用法詳解
ReactNative 中的
import React, { Component } from 'react';
import { WebView } from 'react-native';
class MyWeb extends Component {
render() {
return (
<WebView
source=
style=
/>
);
}
}
有時候可以使用 WebView 彌補一些 ReactNative 內建的元件實現不了的東西,我們可以藉助 HTML 來完成,畢竟 HTML 有豐富的工具可以用。例如要想在 ReactNative 裡展示圖表,原生自帶的元件則沒辦法實現,其他的圖表元件都是基於 react-native-svg 實現的,展示效果目前還不足人意。這個時候 HTML 則有一大堆圖表工具可以使用,echarts, highcharts 等等等。
接下來我們可以寫一個網頁,然後使用 uri 外部引用進來。但是把網頁放在伺服器上,然後 App 引用還是挺囉嗦的。能不能把網頁放在應用內部,本地引用呢?當然可以,這個才是這篇部落格的主題。
WebView 載入本地 html
假設我們有一個 demo 專案
Demo/
android/
ios/
index.android.js
index.ios.js
packege.json
WebViewScreen.js
pages/
demo.html
...
新建一個檔案 WebViewScreen.js
import React from 'react';
import { WebView } from 'react-native';
export default class WebViewScreen extends React.Component {
render() {
return (
<WebView source={require('./pages/demo.html')} />
)
}
}
然後在 index.android.js 和 index.ios.js 修改程式碼使用 WebViewScreen 展示
...
import WebViewScreen from './WebViewScreen';
class Demo extends React.Component {
render() {
return (
<View>
<WebViewScreen />
</View>
)
}
}
AppRegistry.registerComponent('Demo', () => Demo);
添加個 pages/demo.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
hello world
</body>
</html>
然後就可以跑起來測試了,iOS 沒問題,Android 則不會顯示。這是一個已知的問題,目前 0.46 版本還沒有解決。但是我們可以想辦法繞過去,Android 需要先把靜態資源放到 android/app/src/main/assets
目錄下面,然後把 require('./pages/demo.html')
換成 {uri: 'file:///android_asset/pages/demo.html'}
。WebViewScreen.js 會是下面這個樣子
export default class WebViewScreen extends React.Component {
const source = (Platform.OS == 'ios') ? require('./pages/demo.html') : { uri: 'file:///android_asset/pages/demo.html' }
render() {
return (
<WebView source={source} />
)
}
}
這樣 Android 就沒問題了,但是要記得同步 pages 目錄到 android asset 目錄下。
注意 HTML 中可以引用 javascript 但是不能引用 stylesheet, css 可以使用
<style>
內聯寫在 HTML 裡。
傳資料給 HTML
有時候不只是純靜態的頁面,繼續我們之前圖表的的例子, 圖表的資料是變化的,需要將資料傳給 HTML。 藉助 WebView injectedJavaScript
屬性可以實現從應用傳入資料給 HTML。
改造 pages/demo.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<div id="output"></div>
<script>
function init(data) {
document.getElementById('output').innerHTML = JSON.stringify(data)
}
</script>
</body>
</html>
改造 WebViewScreen.js
export default class WebViewScreen extends React.Component {
const source = (Platform.OS == 'ios') ? require('./pages/demo.html') : { uri: 'file:///android_asset/pages/demo.html' }
render() {
return (
<WebView source={source} injectedJavaScript={this.bootstrapJS()} />
)
}
bootstrapJS() {
const data = { hello: 'world' }
return `init(${JSON.stringify(data)})`
}
}
injectedJavaScript
可以是一段 JavaScript 程式碼,當頁面載入後注入並執行。