最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解react-native WebView 返回處理(非回調(diào)方法可解決)

 更新時間:2018年02月27日 09:54:35   作者:Chloe_zhang  
這篇文章主要介紹了詳解react-native WebView 返回處理(非回調(diào)方法可解決),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

1.前言

項目中有些頁面內(nèi)容是變更比較頻繁的,這些頁面我們會考慮用 網(wǎng)頁 來解決。

在RN項目中提供一個公用的Web頁,如果是網(wǎng)頁內(nèi)容,就跳轉(zhuǎn)到這個界面展示。

此時會有一個問題是,網(wǎng)頁會有一級頁面,二級頁面,這就會設(shè)計到導(dǎo)航欄返回鍵的處理(以及在Android上返回鍵的處理)。

這個問題,在RN官網(wǎng)就可找到解決方式。就是用 onNavigationStateChange 這個回調(diào)方法記錄當(dāng)前的導(dǎo)航狀態(tài),從而判斷是返回上一級頁面還是退出這個網(wǎng)頁,回到App的其他界面。

但是,當(dāng)網(wǎng)頁的實現(xiàn)是React時,就會有問題了,你會發(fā)現(xiàn),當(dāng)頁面跳轉(zhuǎn)的時候,onNavigationStateChange這個回調(diào)方法沒有回調(diào)!??!怎么肥四??!

一開始嘗試了把網(wǎng)頁地址換成百度的,可以接收回調(diào),一切都運(yùn)行的很好,可是換成我們的鏈接就不行,所以就把鍋甩給了后臺,以為是React哪邊寫的不對。

因為上一個項目時間緊,沒有時間好好去看一下源碼,就想了一個不是很完善的解決方案,就是網(wǎng)頁用js來回調(diào)App來告知現(xiàn)在的導(dǎo)航狀態(tài),這樣的解決方式顯示是不友好的。

現(xiàn)在稍微有點(diǎn)時間看了源碼才知道真正原因。

2.原因

下面就分析一下這個問題的原因和我的解決方式。

1.首先,先找到源碼的位置。

node_modules\react-native\ReactAndroid\src\main\java\com\facebook\react\views\webview

node_modules\react-native\Libraries\Components\WebView

目錄結(jié)構(gòu)是這樣的:

 

2.實現(xiàn)的代碼段 (JAVA端)

RN的實際運(yùn)行代碼都是原生代碼,所以,像WebView組件的一些事件回調(diào),其實都是原生代碼中的回調(diào)觸發(fā)的。如下

(ReactWebViewManager.java) rn版本0.47.1

protected static class ReactWebViewClient extends WebViewClient { //WebViewClient就是我們在寫Android原生代碼時,監(jiān)聽網(wǎng)頁加載情況使用的工具。
   protected static final String REACT_CLASS = "RCTWebView"; //定義的原生組件名,在后面JS中會對應(yīng)到。

  //...

  @Override
  public void onPageStarted(WebView webView, String url, Bitmap favicon) { //有很多回調(diào)方法,此處只舉一例
   super.onPageStarted(webView, url, favicon);
   mLastLoadFailed = false;

   dispatchEvent(
     webView,
     new TopLoadingStartEvent(   //自己定義的時間,dispatch后,事件會傳給js
       webView.getId(),
       createWebViewEvent(webView, url)));
  }

  //...
 }

(ReactWebViewManager.java) rn版本0.43.3  ,RN不同版本會有代碼調(diào)整,所以RN升級的時候,需要仔細(xì)的回歸測試。

protected static class ReactWebViewClient extends WebViewClient { //WebViewClient就是我們在寫Android原生代碼時,監(jiān)聽網(wǎng)頁加載情況使用的工具。
   protected static final String REACT_CLASS = "RCTWebView"; //定義的原生組件名,在后面JS中會對應(yīng)到。

  //...

  @Override
  public void onPageStarted(WebView webView, String url, Bitmap favicon) { //有很多回調(diào)方法,此處只舉一例
   super.onPageStarted(webView, url, favicon);
   mLastLoadFailed = false;

   dispatchEvent(
     webView,
     new TopLoadingStartEvent(   //自己定義的時間,dispatch后,事件會傳給js
       webView.getId(),
       createWebViewEvent(webView, url)));
  }

  @Override
  public void doUpdateVisitedHistory(WebView webView, String url, boolean isReload) { //坑在這,這里就是導(dǎo)航有變化的時候會回調(diào)在這個版本是有這個處理的,但是不知道在哪個版本刪掉了 -.-
   super.doUpdateVisitedHistory(webView, url, isReload);

   dispatchEvent(
     webView,
     new TopLoadingStartEvent(
       webView.getId(),
       createWebViewEvent(webView, url)));
  }

  //...
 }

(TopLoadingStartEvent.java) 回調(diào)JS的Event

public class TopLoadingStartEvent extends Event<TopLoadingStartEvent> {
 public static final String EVENT_NAME = "topLoadingStart";  //對應(yīng)方法是onLoadingStart, 因為對RN的結(jié)構(gòu)不熟悉,在此處花了很長時間研究是怎么對應(yīng)的,最后找到了定義對應(yīng)的文件
 private WritableMap mEventData;

 public TopLoadingStartEvent(int viewId, WritableMap eventData) {
  super(viewId);
  mEventData = eventData;
 }

 @Override
 public String getEventName() {
  return EVENT_NAME;
 }

 @Override
 public boolean canCoalesce() {
  return false;
 }

 @Override
 public short getCoalescingKey() {
  // All events for a given view can be coalesced.
  return 0;
 }

 @Override
 public void dispatch(RCTEventEmitter rctEventEmitter) {
  rctEventEmitter.receiveEvent(getViewTag(), getEventName(), mEventData);
 }
}

(node_modules\react-native\ReactAndroid\src\main\java\com\facebook\react\uimanager\UIManagerModuleConstants.java)

這個文件里,定義了對應(yīng)關(guān)系

/**
 * Constants exposed to JS from {@link UIManagerModule}.
 */
/* package */ class UIManagerModuleConstants {

 /* package */ static Map getDirectEventTypeConstants() {
  return MapBuilder.builder()
    .put("topContentSizeChange", MapBuilder.of("registrationName", "onContentSizeChange"))
    .put("topLayout", MapBuilder.of("registrationName", "onLayout"))
    .put("topLoadingError", MapBuilder.of("registrationName", "onLoadingError"))
    .put("topLoadingFinish", MapBuilder.of("registrationName", "onLoadingFinish"))
    .put("topLoadingStart", MapBuilder.of("registrationName", "onLoadingStart"))
    .put("topSelectionChange", MapBuilder.of("registrationName", "onSelectionChange"))
    .put("topMessage", MapBuilder.of("registrationName", "onMessage"))
    .build();
 }
}

3.實現(xiàn)的代碼段 (JS端)

(node_modules\react-native\Libraries\Components\WebView\WebView.android.js)

在下面的代碼中可以看到只有 onLoadingStart    和 onLoadingFinish 才會調(diào)用  updateNavigationState ,問題就出現(xiàn)在這了,由于我們的網(wǎng)頁實現(xiàn)是React,只有一個頁面??!所以只會調(diào)用一次 onLoadingStart  和 onLoadingFinish 。再點(diǎn)擊詳情頁并不會跳轉(zhuǎn)到新頁面,而是刷新原來的頁面。所以也就沒有 updateNavigationState 回調(diào)了。

class WebView extends React.Component {
 static propTypes = {  //給外部定義的可設(shè)置的屬性
  ...ViewPropTypes,
  renderError: PropTypes.func,
  renderLoading: PropTypes.func,
  onLoad: PropTypes.func,
  //...
  }

 render() { //繪制頁面內(nèi)容
  //...
  var webView =
   <RCTWebView
    ref={RCT_WEBVIEW_REF}
    key="webViewKey"
    style={webViewStyles}
    source={resolveAssetSource(source)}
    onLoadingStart={this.onLoadingStart}
    onLoadingFinish={this.onLoadingFinish}
    onLoadingError={this.onLoadingError}/>;

  return (
   <View style={styles.container}>
    {webView}
    {otherView}
   </View>
  );
 }

 onLoadingStart = (event) => {
  var onLoadStart = this.props.onLoadStart;
  onLoadStart && onLoadStart(event);
  this.updateNavigationState(event);
 };

 onLoadingFinish = (event) => {
  var {onLoad, onLoadEnd} = this.props;
  onLoad && onLoad(event);
  onLoadEnd && onLoadEnd(event);
  this.setState({
   viewState: WebViewState.IDLE,
  });
  this.updateNavigationState(event);
 };

 updateNavigationState = (event) => {
  if (this.props.onNavigationStateChange) {
   this.props.onNavigationStateChange(event.nativeEvent);
  }
 };
}

var RCTWebView = requireNativeComponent('RCTWebView', WebView, {  //對應(yīng)上面JAVA中的 ‘RCTWebView'
 nativeOnly: { messagingEnabled: PropTypes.bool, }, });


 module.exports = WebView; 

2.解決方法

既然原因找到了,就容易解決了

解決方式:自定義WebView,添加 doUpdateVisitedHistory 處理,在每次導(dǎo)航變化的時候,通知JS。

1. 拷貝下圖中的文件到我們自己項目中的Android代碼目錄下

拷貝完后的Android目錄:

ReactWebViewManager.java中需要修改幾個地方

public class ReactWebViewManager extends SimpleViewManager<WebView> {
 protected static final String REACT_CLASS = "RCTWebView1"; //此處修改一下名字

 protected static class ReactWebViewClient extends WebViewClient {
    @Override
    public void doUpdateVisitedHistory(WebView webView, String url, boolean isReload) {
      super.doUpdateVisitedHistory(webView, url, isReload);

      dispatchEvent(    //在導(dǎo)航變化的時候,dispatchEvent
          webView,
          new TopCanGoBackEvent(
              webView.getId(),
              createCanGoBackWebViewEvent(webView, url)));
    }
 }
}

TopCanGoBackEvent是我自己添加的一個Event,專門用來通知導(dǎo)航變化

TopCanGoBackEvent.java

public class TopCanGoBackEvent extends Event<TopCanGoBackEvent> {

 public static final String EVENT_NAME = "topChange"; 
 private WritableMap mEventData;

 public TopCanGoBackEvent(int viewId, WritableMap eventData) {
  super(viewId);
  mEventData = eventData;
 }

 @Override
 public String getEventName() {
  return EVENT_NAME;
 }

 @Override
 public boolean canCoalesce() {
  return false;
 }

 @Override
 public short getCoalescingKey() {
  // All events for a given view can be coalesced.
  return 0;
 }

 @Override
 public void dispatch(RCTEventEmitter rctEventEmitter) {
  rctEventEmitter.receiveEvent(getViewTag(), getEventName(), mEventData);
 }
}

新建 ReactWebViewPage.java

public class ReactWebViewPackage implements ReactPackage {

  @Override
  public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {

    return Collections.emptyList();
  }

  @Override
  public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
    return Arrays.<ViewManager>asList(
        new ReactWebViewManager()
    );
  }
}

然后在MainApplication中添加這個模塊

public class MainApplication extends Application implements ReactApplication {
  @Override
  protected List<ReactPackage> getPackages() {
   return Arrays.<ReactPackage>asList(
     new MainReactPackage(),
     new ReactWebViewPackage()  //WebView
   );
  }
}

以上就是Android需要修改的地方,ios我沒有嘗試過,應(yīng)該大差不差同一個道理。

2. 拷貝下圖中的文件到我們自己項目中的JS代碼目錄下,并修改一下名字

JS代碼目錄:

CustomWebView.android.js 有幾個地方需要修改。

/**
 * Copyright (c) 2015-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule CustomWebView  //此處需要修改名稱
 */

var RCT_WEBVIEW_REF = 'webview1'; //此處需要修改名稱

 render() {
  var webView =
   <NativeWebView
    onLoadingStart={this.onLoadingStart}
    onLoadingFinish={this.onLoadingFinish}
    onLoadingError={this.onLoadingError}
    onChange={this.onChange} //添加方法
   />;

  return (
   <View style={styles.container}>
    {webView}
    {otherView}
   </View>
  );
 }

 onChange = (event) => {  //添加方法
  this.updateNavigationState(event);
 };
}

var RCTWebView = requireNativeComponent('RCTWebView1', CustomWebView, CustomWebView.extraNativeComponentConfig); //修改名稱

module.exports = CustomWebView; //修改名稱

至此就完成自定義WebView模塊。也可以解決網(wǎng)頁是React實現(xiàn),不能導(dǎo)航的問題。

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • React key值的作用和使用詳解

    React key值的作用和使用詳解

    這篇文章主要介紹了React key值的作用和使用詳解,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-08-08
  • React如何避免子組件無效刷新

    React如何避免子組件無效刷新

    這篇文章主要介紹了React幾種避免子組件無效刷新的解決方案,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-03-03
  • 解決react-connect中使用forwardRef遇到的問題

    解決react-connect中使用forwardRef遇到的問題

    這篇文章主要介紹了解決react-connect中使用forwardRef遇到的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-05-05
  • React?高階組件與Render?Props優(yōu)缺點(diǎn)詳解

    React?高階組件與Render?Props優(yōu)缺點(diǎn)詳解

    這篇文章主要weidajai?介紹了React?高階組件與Render?Props優(yōu)缺點(diǎn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-11-11
  • react如何向數(shù)組中追加值

    react如何向數(shù)組中追加值

    這篇文章主要介紹了react如何向數(shù)組中追加值,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-09-09
  • React-router4路由監(jiān)聽的實現(xiàn)

    React-router4路由監(jiān)聽的實現(xiàn)

    這篇文章主要介紹了React-router4路由監(jiān)聽的實現(xiàn),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-08-08
  • React?Native與iOS?OC之間的交互示例詳解

    React?Native與iOS?OC之間的交互示例詳解

    這篇文章主要為大家介紹了React?Native與iOS?OC之間的交互示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-07-07
  • 利用React Router4實現(xiàn)的服務(wù)端直出渲染(SSR)

    利用React Router4實現(xiàn)的服務(wù)端直出渲染(SSR)

    這篇文章主要介紹了利用React Router4實現(xiàn)的服務(wù)端直出渲染(SSR),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2019-01-01
  • 教你使用vscode 搭建react-native開發(fā)環(huán)境

    教你使用vscode 搭建react-native開發(fā)環(huán)境

    本文記錄如何使用vscode打造一個現(xiàn)代化的react-native開發(fā)環(huán)境,旨在提高開發(fā)效率和質(zhì)量。本文給大家分享我遇到的問題及解決方法,感興趣的朋友跟隨小編一起看看吧
    2021-07-07
  • sass在react中的基本使用(實例詳解)

    sass在react中的基本使用(實例詳解)

    這篇文章主要介紹了sass在react中的基本使用,主要包括安裝sass和編寫APP.tsx中的基本dom,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-09-09

最新評論

莱州市| 遂宁市| 曲松县| 时尚| 揭阳市| 莱西市| 横峰县| 思茅市| 大丰市| 精河县| 峡江县| 嵊泗县| 蚌埠市| 庆元县| 新巴尔虎左旗| 曲沃县| 鹰潭市| 东方市| 南溪县| 柳州市| 繁峙县| 资中县| 达尔| 大邑县| 手游| 永仁县| 观塘区| 晋中市| 新闻| 林口县| 柳州市| 龙陵县| 犍为县| 定远县| 洮南市| 万荣县| 株洲县| 信丰县| 福清市| 彭阳县| 金溪县|