不管在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...