在 App 中,渲染 HTML 是一個非常常見的功能,有可能是直接渲染 HTML 字串或者是通過 URL 渲染遠端 HTML頁面。
React Native 提供了一個 WebView 元件以供我們實現 HTML 的渲染。
早先 WebView 是在 React Native 核心包中,後來為了減小 React Native 核心包的體積,便將其單獨提出到 react-native-webview元件中。
話不多說,讓我們來試試這個元件吧。
渲染遠端 HTML 內容
在開始之前,你需要使用 yarn/npm 來安裝它:
yarn add react-native-webview
安裝完成後,我們就可以在程式碼中使用它:
import React, { Component } from 'react';
import { View } from 'react-native';
import { WebView } from 'react-native-webview';
export default class App extends Component {
render() {
return (
<View>
<WebView source={{ uri: 'https://www.baidu.com' }} />
</View>
)
}
}
需要注意的是:第一次安裝完成後,需要重新執行一次
react-native run-*
讓 rn 幫我們自動 link 一次,否則會丟擲以下錯誤:
重新執行 react-native run-*
後,報錯沒了,但是頁面上一片空白:
這是什麼原因呢?在檢視了一下文件之後,發現 WebView 預設是不會自動設定其高度,所以這個時候高度是0,我們才無法在頁面中找到它。需要注意的是,如果 WebView 的父級元件是 View, 直接使用 style
給 WebView 元件設定高度是無效的,需要給這個 View 元件設定高度才能正常顯示。然而在 ScrollView 中,則是需要給 WebView 本身設定 height。其它幾個元件,例如 SafeAreaView
我沒有去嘗試,需要你自己親自去檢驗。
知道原因後,我們將 WebView 父元件設定 style 為 flex: 1
,讓其鋪滿整個螢幕,在 reload 一次看看效果:
大功高程,我們已經成功的把百度展現到我們的 App 中了。
渲染 HTML 字串
有時候我們需要將 API 中返回的 HTML 字串解析出來。渲染 HTML 字串的時候,我們需要將 source 中的 uri 替換為 html,它的值就是我們的 HTML 字串。與 uri 不同的是,渲染 HTML 字串的時候,我們需要設定originWhitelist,比如可以設為["*"]來允許執行原生程式碼。
{/* ... */}
<WebView
originWhitelist={['*']}
source={{ html: `<h1>這裡是一個標題</h1>` }}
/>
{/* ... */}
到這裡我們就成功的把標題給渲染出來了。
根據內容自動計算高度
往往我們無法提前預知 HTML 內容的高度,所以我們無法給其設定一個固定的高度,而是需要根據內容來設定其高度。
為了達到這個目的,我們需要用到 injectedJavaScript
和 onMessage
,
injectedJavaScript
這個屬性的作用是設定一個在網頁載入之前執行的 js 程式碼。
onMessage
在 webview 內部的網頁中呼叫 window.postMessage 方法時可以觸發此屬性對應的函式,從而實現網頁和 RN 之間的資料交換。 設定此屬性的同時會在 webview 中注入一個 postMessage 的全域性函式並覆蓋可能已經存在的同名實現。
網頁端的 window.postMessage 只傳送一個引數 data,此引數封裝在 RN 端的 event 物件中,即 event.nativeEvent.data。data 只能是一個字串。
import React, { Component } from 'react';
import { View, ScrollView, SafeAreaView } from 'react-native';
import { WebView } from 'react-native-webview';
export default class App extends Component {
constructor(props) {
super(props);
this.state = { webViewHeight: 0 };
}
{/* 根據內容計算 WebView 高度 */}
onWebViewMessage = (event) => {
this.setState({ webViewHeight: Number(event.nativeEvent.data) });
}
render() {
return (
<View style={{ flex: 1 }}>
<View style={{ height: 100, backgroundColor: 'yellow' }}></View>
<View style={{ height: this.state.webViewHeight }}>
<WebView
originWhitelist={['*']}
source={{ html: `<p>這裡是一個標題</p>` }}
injectedJavaScript='window.ReactNativeWebView.postMessage(document.documentElement.scrollHeight)'
onMessage={this.onWebViewMessage}
/>
</View>
<View style={{ height: 100, backgroundColor: 'green' }}></View>
</View>
)
}
}
從上圖可以看出我們的 WebView 已經根據其中內容動態的計算了其高度。但是還是有一個問題,這裡的文字太小了,要解決這個問題我們需要用到 meta - viewport
。
採用響應式佈局
這個其實很簡單,只需要在 header 中設定 meta 標籤即可。
<WebView
originWhitelist={['*']}
source={{ html: `
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<p>這裡是一個標題</p>
</body>
</html>
` }}
injectedJavaScript='window.ReactNativeWebView.postMessage(document.documentElement.scrollHeight)'
onMessage={this.onWebViewMessage}
/>
總結
到此,關於 React Native 的基礎使用我們已經講完了,更多細節請參考以下連結: