ReactNative WebView元件詳解

Code4Android發表於2017-08-13

原始碼傳送門

react-native-webview-plugin外掛

在開發Android的時候,一般我們會有一些載入網頁的需求,或者執行一些JavaScript,我們都知道在Android中實現這個功能的控制元件是WebView,在ReactNative中也有實現此類需求額的元件,它的名字也是WebView。那麼今天的這篇文章就來詳細說說在ReactNative WebView的使用。本文示例效果圖

webview.gif

屬性

  • automaticallyAdjustContentInsets 控制是否調整放置在導航條、標籤欄或工具欄後面的web檢視的內容。預設值為true

  • contentInset {top: number, left: number, bottom: number, right: number} 設定網頁內嵌邊距

  • injectedJavaScript 設定在網頁載入之前注入一段js程式碼

  • mediaPlaybackRequiresUserAction 設定頁面中的HTML5音視訊是否需要在使用者點選後再開始播放。預設值為true

  • scalesPageToFit 設定是否要把網頁縮放到適應檢視的大小,以及是否允許使用者改變縮放比例。

  • source 在WebView中指定載入內容html或者url,可以指定header,method等

  • startInLoadingState 強制WebView在第一次載入時先顯示loading檢視。預設為true

  • domStorageEnabled(android) 布林值,指定是否開啟DOM本地儲存

  • javaScriptEnabled(android) 布林值,指定WebView中是否啟用JavaScript。只在Android上使用,因為在iOS上預設啟用了JavaScript。

  • mixedContentMode(android) 指定混合內容模式。即WebView是否應該允許安全連結(https)頁面中載入非安全連結(http)的內容,

    • 'never' (預設) - WebView不允許安全連結頁面中載入非安全連結的內容
    • 'always' - WebView允許安全連結頁面中載入非安全連結的內容。
    • 'compatibility' - WebView會盡量和瀏覽器當前對待此情況的行為一致
  • userAgent(android) 為WebView設定user-agent字串標識。這一字串也可以在原生端用WebViewConfig來設定,但js端的設定會覆蓋原生端的設定。

  • allowsInlineMediaPlayback(ios) 指定HTML5視訊是在網頁當前位置播放還是使用原生的全屏播放器播放。 預設值為false,視訊在網頁播放還需要設定webkit-playsinline

  • bounces(ios) 指定滑動到邊緣後是否有回彈效果。

  • decelerationRate(ios) 指定一個浮點數,用於設定在使用者停止觸控之後,此檢視應以多快的速度停止滾動。也可以指定預設的字串值,如"normal"和"fast",

  • scrollEnabled(ios) 是否啟用滾動

函式

  • injectJavaScript 函式接受一個字串,該字串將傳遞給WebView,並立即執行為JavaScript
  • onError 載入失敗時回撥
  • onLoad 完成載入時回撥
  • onLoadEnd 載入成功或者失敗都會回撥
  • onLoadStart 開始載入的時候回撥
  • onMessage 在webView內部網頁中,呼叫window.postMessage可以觸發此屬性對應的函式,通過event.nativeEvent.data獲取接收到的資料,實現網頁和RN之間的資料傳遞
  • renderError 返回一個檢視用來提示使用者錯誤
  • renderLoading 返回一個載入指示器
  • onShouldStartLoadWithRequest(ios) 請求自定義處理,返回true或false表示是否要繼續執行響應的請求 #實戰分析 通過上面的介紹,我們已經對元件的屬性以及函式有了大致的瞭解,當然只有這些是不夠的,接下來就該元件的使用展開分析,效果圖如文章開頭的GIF圖。對於該元件最簡單的使用如下
        <WebView
                source={{uri:'http://www.jianshu.com/u/d5b531888b2b'}}
                style={{width:'100%',height:'100%'}}
            />
複製程式碼

指定source屬性,載入網頁,設定寬和高全屏,需要注意的是必須指定寬和高,否則將不顯示元件,預設寬高都是0。 給WebView增加載入時的回撥

                    onLoad={(e) => console.log('onLoad')}
                    onLoadEnd={(e) => console.log('onLoadEnd')}
                    onLoadStart={(e) => console.log('onLoadStart')}
                    renderError={() => {
                        console.log('renderError')
                        return <View><Text>renderError回撥了,出現錯誤</Text></View>
                    }}
                    renderLoading={() => {
                        return <View><Text>這是自定義Loading...</Text></View>
                    }}
複製程式碼

renderError可以自定義載入錯誤的提示資訊View.當載入錯誤時會回撥該函式,並且顯示該函式返回的View。使用此方法我們可以自定義載入錯誤時的提示資訊。 而renderLoading函式可以自定義載入提示.當我們通過WebView載入一個網頁時,往往我們有需求展示出請求的url,網頁的標題,以及是否可前進或者後退。在WebView元件中有一個函式onNavigationStateChange可以實現此功能,他是在載入開始和結束的時候回撥的,

   //新增屬性
   onNavigationStateChange={this._onNavigationStateChange}

    _onNavigationStateChange = (navState) => {
        console.log(navState)
        this.setState({
            backButtonEnabled: navState.canGoBack,
            forwardButtonEnabled: navState.canGoForward,
            url: navState.url,
            status: navState.title,
            loading: navState.loading,
        });
    }
複製程式碼

當canGoBack返回值為true時,我們就可以使用this.webview.goBack();(this.webview是WebView的引用)對網頁進行回退操作,同理當canGoForward為true時我們就可以使用 this.webview.goForward();對我們的網頁進行跳轉操作。當我們的網頁url發生改變時我們可以使用 this.webview.reload();載入新的網頁。

載入HTML

     <WebView>
            style={{width:'100%',height:'100%'}}
            source={require('./helloworld.html');}
     </WebView>
複製程式碼

RN和Html通訊

當WebView載入html時我們可以實現html和rn之間的通訊。rn向html發生資料可以通過postMessage函式實現。如下

this.webview.postMessage('"Hello" 我是RN傳送過來的資料');
//在html中註冊事件接收rn發過來的資料並顯示在html中
    document.addEventListener('message', function(e) {
      messagesReceivedFromReactNative += 1;
      document.getElementsByTagName('p')[0].innerHTML =
        '從React Native接收的訊息: ' + messagesReceivedFromReactNative;
      document.getElementsByTagName('p')[1].innerHTML = e.data;
    });

複製程式碼

在html中我們定義了一個按鈕,並新增事件向rn傳送資料

   //window.postMessage向rn傳送資料
    document.getElementsByTagName('button')[0].addEventListener('click', function() {
      window.postMessage('這是html傳送到RN的訊息');
    });
複製程式碼

當html中呼叫了window.postMessage函式後,WebView的onMessage函式將會被回撥,用來處理html向rn傳送的資料,可以通過e.nativeEvent.data獲取傳送過來的資料。

    //接收HTML發出的資料
    _onMessage = (e) => {
        this.setState({
            messagesReceivedFromWebView: this.state.messagesReceivedFromWebView + 1,
            message: e.nativeEvent.data,
        })
        Alert.alert(e.nativeEvent.data)
    }
複製程式碼

JavaScript

在android這個需要使用 javaScriptEnabled屬性來支援JavaScript,ios預設是支援的,沒有此屬性。在WebView中提供了函式injectJavaScript(String),它有一個字串引數,可以向webview中注入指令碼,如下

    //指令碼注入
    injectJS = () => {
        const script = 'document.write("Injected JS ")';  // eslint-disable-line quotes
        if (this.webview) {
            this.webview.injectJavaScript(script);
        }
    }
複製程式碼

最後需要注意的一點,ScrollView中巢狀WebView時滑倒會有衝突,需要特殊處理(目前還沒研究處理方法。)今天的這篇文章就介紹這麼多,所介紹的例項中,只提供了核心程式碼,如果想檢視全部程式碼可以訪問GitHub,由於認知有限,若有錯誤的地方歡迎指出,共同進步,謝謝。

最後補充:

ReactNative WebView實現Android端圖片和視訊的拍攝和選擇,以及ios,android根據webView內容自動設定高度(WebView巢狀在ScrollView中問題),修復現在Android端WebView偶先的閃退bug,外掛地址github.com/xiehui999/r…

相關文章