- A+
所属分类:Web前端
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(); // 手动关闭