不管在web端仍是原生Native应用,弹窗使用场景都随处可见,弹窗UI设计的好坏很大程度上直接决定用户体验。如微信、支付宝的弹窗交互就操做方便、使用温馨。html
很早以前就有使用h5开发过手机端弹窗,最近一直在捣鼓react-native技术,踩了很多坑。就想着用react-native技术作个自定义Modal弹窗来实践一把。react
rnPop是一个基于React/React-Native技术开发的高自定义弹窗组件,仿制了android、ios、微信弹窗效果。结合了原生Modal及react能力,使得弹窗高度自定义化,调用优雅、简洁、方便。android
参考了不少别人自定义react-native弹窗调用方式,无非就是下面这样ios
// 引入rnPop.js组件 import RNPop from '../utils/rnPop/rnPop.js' render() { return ( <View style={styles.container}> ... {/* 引入弹窗模板 */} <RNPop ref="rnPop" /> </View> ) } 显示:this.refs.rnPop.show({...options}); 隐藏:this.refs.rnPop.hide();
这种调用方式是能够访问组件内部方法,如show、hide方法,可总感受代码不够优雅,并且不能全局调用。程序员
在弹窗内部定义两个静态方法web
/************************** * 显示弹窗事件(处理传参) */ static show = (args) => { _this.setState({ ..._this.props, ...args, isVisible: true }, _this.in) } /************************** * 关闭弹窗事件 */ static close = () => { _this.out() }
经过react-native全局变量global,对外提供全局调用接口rnPop小程序
/************************** * 实例化弹窗接口 */ const Popup = (args) => { RNPop.show(args) } Popup.close = () => { RNPop.close() } global.rnPop = Popup
这样就能够很是优雅的使用rnPop({...options}) 、 rnPop.close()方式进行弹窗调用了。微信小程序
//msg提示 handlePress01 = ()=> { rnPop({ content: 'msg消息提示框(5s后窗口关闭)', shade: true, shadeClose: false, time: 5, xtime: true, anim: 'fadeIn', }); } //msg提示(黑色背景) handlePress02 = ()=> { rnPop({ content: '自定义弹窗背景', shade: false, style: {backgroundColor: 'rgba(17,17,17,.7)', borderRadius: 6}, contentStyle: {color: '#fff', padding: 10}, time: 2 }); }
react-native自定义toast支持四种图标 success/info/error/loadingreact-native
//Toast演示 handlePress15 = ()=> { rnPop({ skin: 'toast', content: '操做成功', icon: 'success', //success | info | error | loading shade: false, time: 3 }); }
//ios对话框 handlePress16 = ()=> { rnPop({ skin: 'footer', content: 'Apple ID \n 282310962@qq.com', shadeClose: false, anim: 'bottom', btns: [ { text: '注销帐号', style: {color: '#30a4fc'}, onPress() { console.log('您点击了恢复!'); } }, { text: '删除', style: {color: '#e63d23'}, onPress() { console.log('您点击了删除!'); //删除回调提示 rnPop({ anim: 'fadeIn', content: '您点击了删除功能', shade: true, time: 3 }); } }, { text: '取消', style: {color: '#999'}, onPress() { console.log('您点击了取消!'); rnPop.close(); } } ] }); }
// android 样式 handlePress20 = ()=>{ rnPop({ skin: 'android', title: '发现新版本', content: '程序员GG紧急修复了一个闪退bug,给您带来的不便敬请谅解。\n\n[近期更新]\n 一、新增资讯&话题入口 \n 二、新增详情页面长按分享功能', shadeClose: false, btns: [ { text: '知道了', onPress() { rnPop.close(); console.log("知道了"); } }, { text: '更新', style: {color: '#4eca33'}, onPress() { console.log('您点击了更新!'); } } ] }); }
还支持对传入content参数进行自定义模板 content: string | object微信
// 自定义调用 handlePressAA = () => { rnPop({ content: ( <DefineCp /> // <View style={{alignItems: 'center', justifyContent: 'center'}}> // <Image style={{height: 200, width: 200}} source={require('../assets/qrcode.jpg')} /> // <Text style={{color: '#999'}}>长按或扫一扫二维码,加我好友</Text> // <View><Text onPress={rnPop.close} style={{backgroundColor: '#61dafb', borderRadius: 20, color: '#fff', marginTop: 15, marginBottom: 10, paddingVertical: 5, paddingHorizontal: 50}}>保存二维码</Text></View> // </View> ), anim: 'bottom' }); }
// 自定义模板 const DefineCp = () => { return ( <View style={{alignItems: 'center', justifyContent: 'center'}}> <Image style={{height: 200, width: 200}} source={require('../assets/qrcode.jpg')} /> <Text style={{color: '#999'}}>长按或扫一扫二维码,加我好友</Text> <View><Text onPress={rnPop.close} style={{backgroundColor: '#61dafb', borderRadius: 20, color: '#fff', marginTop: 15, marginBottom: 10, paddingVertical: 5, paddingHorizontal: 50}}>保存二维码</Text></View> </View> ) }
/** * @Title react-native弹窗插件 rnPop-v1.0 beta (UTF-8) * @Create 2019/08/01 10:00:50 GMT+0800 (中国标准时间) * @Author andy Q:282310962 wx:xy190310 */ 'use strict' import React, {Component} from 'react' import { Animated, Easing, StyleSheet, Dimensions, PixelRatio, TouchableHighlight, Modal, View, Text, Image, ActivityIndicator } from 'react-native' const pixel = PixelRatio.get() const {width, height} = Dimensions.get('window') export default class RNPop extends Component{ /************************** * 弹窗配置参数 */ static defaultProps = { isVisible: false, //弹窗显示 title: '', //标题 content: '', //内容 style: null, //自定义弹窗样式 {object} contentStyle: null, //内容样式 skin: '', //自定义弹窗风格 icon: '', //自定义弹窗图标 shade: true, //遮罩层 shadeClose: true, //点击遮罩层关闭 opacity: '', //遮罩层透明度 time: 0, //弹窗自动关闭秒数 xtime: false, //显示关闭秒数 anim: 'scaleIn', //弹窗动画(scaleIn / fadeIn / top / bottom / left / right) follow: null, //跟随定位(适用于在长按位置定位弹窗) position: '', //弹窗位置 btns: null, //弹窗按钮(不设置则不显示按钮)[{...options}, {...options}] } constructor(props){ super(props) this.state = { ...this.props, animatedValue: new Animated.Value(0), } this.timer = null } render(){ let opt = this.state // __自定义toast图标 let slotImg = { success: require('./skin/success.png'), error: require('./skin/error.png'), info: require('./skin/info.png'), } return ( ... ) } // 执行动画 in = () => { Animated.timing( this.state.animatedValue, {easing: Easing.linear, duration: 300, toValue: 1} ).start() } out = () => { Animated.timing( this.state.animatedValue, {easing: Easing.linear, duration: 100, toValue: 0} ).start(()=>{ this.setState({ ...this.props }) }) this.timer && clearTimeout(this.timer) delete this.timer } /************************** * 显示弹窗事件(处理传参) */ static show = (args) => { _this.setState({ ..._this.props, ...args, isVisible: true }, _this.in) } /************************** * 关闭弹窗事件 */ static close = () => { _this.out() } }
附上以前的h5移动端和微信小程序弹窗
h5手机端弹窗:https://www.cnblogs.com/xiaoy...
h5网页版弹窗:https://www.cnblogs.com/xiaoy...
wx小程序弹窗:https://www.cnblogs.com/xiaoy...