React Native实现Toast轻提示和loading

  • React Native实现Toast轻提示和loading已关闭评论
  • 116 次浏览
  • A+
所属分类:Web前端
摘要

使用react native的小伙伴都知道,官方并未提供轻提示组件,只提供了ToastAndroid API,顾名思义,只能再安卓环境下使用,对于ios就爱莫能助,故此,只能通过官方的核心组件,自行封装,实现Toast功能


React Native 封装Toast

前言

使用react native的小伙伴都知道,官方并未提供轻提示组件,只提供了ToastAndroid API,顾名思义,只能再安卓环境下使用,对于ios就爱莫能助,故此,只能通过官方的核心组件,自行封装,实现Toast功能

实现

创建文件

首先我们需要创建一个Toast组件,引入对应需要的依赖,icon等等
声明数据类型,通用方法

import React, {Component} from 'react'; import {View, Text, StyleSheet, Animated, Easing} from 'react-native'; import icon_success from '../assets/images/icon-success.png'; import icon_error from '../assets/images/icon-error.png'; import icon_loading from '../assets/images/icon-loading.png'; import icon_warning from '../assets/images/icon-warning.png';  type StateType = {   isVisible: boolean;   icon: any;   message: string; };  type ParamsType = string | {message: string; duration?: number}; function getParams(data: ParamsType): {message: string; duration: number} {   let msg!: string;   let dur!: number;   if (typeof data === 'string') {     msg = data;     dur = 2000;   } else {     msg = data.message;     dur = data.duration != null ? data.duration : 2000;   }   return {     message: msg,     duration: dur,   }; } 

实现样式和UI层次渲染

我们需要创建一个class,接收参数,并根据不同的条件渲染:success、error、warning、show、loading等
并抛出自己的实例

class ToastComponent extends Component<{} | Readonly<{}>, StateType> {   timeout!: NodeJS.Timeout;   rotate: Animated.Value = new Animated.Value(0);   constructor(props: {} | Readonly<{}>) {     super(props);     this.state = {       isVisible: false,       icon: null,       message: '',     };     Toast.setToastInstance(this);   }   showToast(icon: any, message: string, duration: number) {     this.setState({       isVisible: true,       icon,       message,     });     if (duration !== 0) {       const timeout = setTimeout(() => {         this.closeToast();       }, duration);       this.timeout = timeout;     }   }   showRotate() {     Animated.loop(       Animated.timing(this.rotate, {         toValue: 360,         duration: 1000,         easing: Easing.linear,         useNativeDriver: true,       }),     ).start();   }   closeToast() {     this.setState({       isVisible: false,       icon: null,       message: '',     });     if (this.timeout) {       clearTimeout(this.timeout);     }   }    render() {     const {isVisible, icon, message} = this.state;     return isVisible ? (       <View style={style.root}>         <View style={[style.main, icon === null ? null : style.mainShowStyle]}>           {icon && (             <Animated.Image               style={[                 style.icon,                 {                   transform: [                     {                       rotate: this.rotate.interpolate({                         inputRange: [0, 360],                         outputRange: ['0deg', '360deg'],                       }),                     },                   ],                 },               ]}               source={icon}             />           )}           <Text style={style.tip}>{message}</Text>         </View>       </View>     ) : null;   } }  const style = StyleSheet.create({   root: {     height: '100%',     backgroundColor: 'transparent',     position: 'absolute',     top: 0,     left: 0,     right: 0,     bottom: 0,     zIndex: 99999,     alignItems: 'center',     justifyContent: 'center',   },   main: {     maxWidth: 200,     maxHeight: 200,     backgroundColor: '#00000099',     borderRadius: 8,     alignItems: 'center',     justifyContent: 'center',     padding: 20,   },   mainShowStyle: {     minWidth: 140,     minHeight: 140,   },   icon: {     width: 36,     height: 36,     resizeMode: 'cover',     marginBottom: 20,   },   tip: {     fontSize: 14,     color: '#fff',     fontWeight: 'bold',     textAlign: 'center',   }, }); 

抛出对外调用的方法

此时我们需要再声明一个class,对外抛出方法以供调用
最后导出即可

class Toast extends Component<{} | Readonly<{}>, {} | Readonly<{}>> {   static toastInstance: ToastComponent;   static show(data: ParamsType) {     const {message, duration} = getParams(data);     this.toastInstance.showToast(null, message, duration);   }   static loading(data: ParamsType) {     const {message, duration} = getParams(data);     this.toastInstance.showToast(icon_loading, message, duration);     this.toastInstance.showRotate();   }   static success(data: ParamsType) {     const {message, duration} = getParams(data);     this.toastInstance.showToast(icon_success, message, duration);   }   static error(data: ParamsType) {     const {message, duration} = getParams(data);     this.toastInstance.showToast(icon_error, message, duration);   }   static warning(data: ParamsType) {     const {message, duration} = getParams(data);     this.toastInstance.showToast(icon_warning, message, duration);   }   static clear() {     if (this.toastInstance) {       this.toastInstance.closeToast();     }   }   static setToastInstance(toastInstance: ToastComponent) {     this.toastInstance = toastInstance;   }   render() {     return null;   } };  export {Toast, ToastComponent}; 

组件挂载

我们需要将UI层组件在入口TSX文件进行挂载,不然Toast无法渲染

/* APP.tsx */ import React from 'react'; import {StatusBar} from 'react-native'; import {SafeAreaProvider} from 'react-native-safe-area-context';  import {ToastComponent} from './src/components/Toast';  const Stack = createStackNavigator();  function App(): JSX.Element {   return (     <SafeAreaProvider>       <StatusBar barStyle="dark-content" backgroundColor="#EAF7FF" />       <ToastComponent />     </SafeAreaProvider>   ); }  export default App;  

API调用

挂载完成,接下来,在我们需要用到的地方,调用即可

import {Toast} from '../../components/Toast';  //  Toast.success('登录成功'); Toast.error('密码错误'); Toast.warning('我是警告'); Toast.loading('加载中,请稍后'); Toast.loading({message: "我是不关闭的Toast", duration: 0}) Toast.success({message: "我是2秒后关闭的Toast", duration: 2000}); Toast.clear(); // 手动关闭