手写 React-Native 方法调用式的 Modal 弹框、Toast 提示


在使用 React-Native 的时候,经常看到一些第三方库的 Modal、Toast 使用方式是这样的:

/** 显示/隐藏 Modal */
Modal.show({/** 做一些快乐的事 */});
Modal.hide();
/** 显示/隐藏 Toast */
Toast.show('做一些开心的事');
Toast.hide();

那这种弹框在 RN 中是怎么实现的呢?

众所周知,在Web端项目中,实现类似的功能非常之简单:

const modal = document.createElement('div');
modal.style.position = 'fixed';
modal.innerHTML = '做一些快乐的事';
document.body.appendChild(modal);

在 RN 中没有 document 对象,元素也没有 appendChild 方法,该怎么做?

思路:
添加一个根元素的兄弟元素,其样式 “position: absolute, zIndex: 999” ,调用其静态方法使其重新 render 。

实现步骤:


  1. 创建一个 RootView 组件
/** 定义一个变量用来存储 RootView 实例 */
let rootViewInstance: RootView | undefined;

class RootView extends React.Component {
  constructor(props: {}) {
    super(props);
    rootViewInstance = this; // 将实例赋值给 rootViewInstance
  }

  public readonly state = {
    content: null
  };

  public static setContent(content) {
    rootViewInstance.setState({ content });
  }

  public static clearContent() {
    rootViewInstance.setState({ content: null });
  }

  render() {
    const { content } = this.state;
    return content && (
      {content}
    );
  }
}

const styles = StyleSheet.create({
  container: {
    position: 'absolute',
    top: 0, left: 0, bottom: 0, right: 0,
    zIndex: 999,
    flex: 1,
  }
});
  1. 修改项目入口文件,将 RootView 组件添加为根元素的兄弟元素
import { AppRegistry } from 'react-native';
import App from './src/app';
import RootView from '@/components/RootView';

const createRootApp = () => () => (
  
    
    
  
);

AppRegistry.registerComponent(appName, createRootApp);
  1. 使用
RootView.setContent(我是一个RootView);

当然,这样需要修改入口文件,组件的封装性并不好;
那怎么样才能实现组件的封装呢?

我们可以把组件提取出来,并重写 AppRegistry 的 registerComponent 方法来实现组件的封装:

let rootViewInstance: RootView | undefined = undefined;

class RootView extends Component {
  public constructor(props: {}) {
    super(props);
    rootViewInstance = this;
  }

  public readonly state = {
    content: null,
  };

  public static setContent = (view: JSX.Element) => {
    rootViewInstance!.setState({ content: view });
  };

  public static clearContent = () => {
    rootViewInstance!.setState({ content: null });
  };

  public render() {
    const { content } = this.state;
    return content && (
        
          {content}
        
    );
  }
}

const registerComponentOld = AppRegistry.registerComponent;

AppRegistry.registerComponent = (appKey, component) => {
  const createRootApp = () => {
    const OriginAppComponent = component(); // 获取原来的App根组件

    return () => (
      
        
        
      
    );
  };

  return registerComponentOld(appKey, createRootApp);
};

export default RootView;

const styles = StyleSheet.create({
  container: {
    position: 'relative',
    flex: 1,
  },
  rootView: {
    position: 'absolute',
    left: 0, right: 0, top: 0, bottom: 0,
    zIndex: 999,
    flex: 1,
  },
});

至此,一个简易的 RootView 组件就装好啦,如需 Modal、Toast 功能则可以基于此组件封装,比如一个 LoadingModal 组件:

import RootView from '@/components/RootView';

const LoadingModal = {
  show() {
    RootView.setContent(
      加载中……
    );
  },
  hide() {
    RootView.hide();
  },
};

大功告成,可以愉快的玩耍啦 ~

你可能感兴趣的:(手写 React-Native 方法调用式的 Modal 弹框、Toast 提示)