基於Taro+react自定義彈出層組件|Modal框|Toast輕提示框|dialog對話框|msg信息框|仿微信對話框
taro多端實踐之:taroPop模態框組件 (H5+小程序+ReactNative)
taro的旨意是實現多端應用,不過網上大多taro彈窗組件都是針對H5及小程序的,而且一些特殊效果需重新開發,如是自己就試着開發,畢竟之前也有用taro做過自定義導航欄組件。
taroPop組件支持自定義彈窗類型(msg/toast/ios/android)/彈窗樣式、多按鈕事件/按鈕樣式、自動關閉、遮罩層、彈窗顯示位置及自定義內容模板。
支持多參數配置
/**
* @ 彈窗默認配置
*/
static defaultProps = {
isVisible: false, //彈窗顯示
title: '', //標題
content: '', //內容
contentStyle: null, //內容樣式
style: null, //自定義彈窗樣式
skin: '', //彈窗風格
icon: '', //彈窗圖標
xclose: false, //自定義關閉按鈕
shade: true, //遮罩層
shadeClose: true, //點擊遮罩關閉
opacity: '', //遮罩透明度
time: 0, //自動關閉時間
end: null, //銷燬彈窗回調函數
position: '', //彈窗位置顯示
btns: null, //彈窗按鈕 [{...args}, {...args}]
}
用法
在頁面引入taroPop彈窗組件
import TaroPop from '@components/taroPop'
import Taro from '@tarojs/taro'
import { View, Text } from '@tarojs/components'
// 引入自定義彈窗組件
import TaroPop from '@components/taroPop'
export default class TaroPopDemo extends Taro.Component {
...
render() {
return (
<View className="taro-container">
...
{/* 引入彈窗模板 */}
<TaroPop ref="taroPop" />
</View>
);
}
}
通過this.refs方式調用組件內show、close方法
this.refs.taroPop.show({...options})
this.refs.taroPop.close()
/**
* 顯示彈窗事件
*/
show = (options) => {
this.setState({
...this.props, ...options, isVisible: true
})
}
/**
* 關閉彈窗事件
*/
close = () => {
this.setState({...this.props})
this.timer && clearTimeout(this.timer)
delete this.timer
typeof this.state.end === 'function' && this.state.end.call(this)
}
/**
* 點擊遮罩關閉
*/
shadeClick = () => {
if(!this.state.shadeClose) return
this.close()
}
另外還支持自定義彈窗內容模板,只需把頁面上的模板寫成如下即可,調用方式還和上面一樣
<TaroPop ref="taroPopTpl">
...
</TaroPop>
◆ msg消息框效果
this.refs.taroPop.show({
content: 'Taro消息提示框(3s後窗口關閉)',
shade: true,
shadeClose: true,
time: 3,
anim: 'fadeIn',
})
◆ ios彈窗效果
let taroPop = this.refs.taroPop
taroPop.show({
skin: 'ios',
title: '消息提示',
content: 'ios彈窗效果 (彈窗內容,用於告知當前狀態、提示信息和解決方法,描述文字/文案儘量控制在三行內)',
shadeClose: false,
btns: [
{
text: '取消',
style: {color: '#6190e8'},
onClick() {
taroPop.close()
}
},
{
text: '不再提醒',
style: {color: '#6190e8'},
onClick() {
console.log('您點擊了前往設置!')
}
}
]
})
◆ 輕提示Toast效果
let taroPop = this.refs.taroPop
taroPop.show({
skin: 'toast',
content: 'loading',
icon: 'loading', //success | info | error | loading
shade: false,
time: 3
})
對於不同端使用一些兼容性處理,需要判斷各端環境並渲染相應模板,對於RN,則使用Modal
let taroEnv = process.env.TARO_ENV
// 渲染窗體
if (taroEnv === 'rn') {
return (
<Modal transparent={true} visible={isVisible} onRequestClose={this.close}>
{renderTpl}
</Modal>
)
}else if (taroEnv === 'h5' || taroEnv === 'weapp'){
return isVisible && renderTpl
}
另外對於樣式兼容性也需要注意,尤其是編譯到reactNative端,各種千奇百怪的問題,有些抓狂~~
/**
* @Title Taro自定義彈窗組件 - taroPop.js
* @Time andy by 2019-11-28
* @About Q:282310962 wx:xy190310
*/
import Taro from '@tarojs/taro'
import { View, Text, Image } from '@tarojs/components'
import { Modal, ActivityIndicator, TouchableHighlight } from 'react-native'
import classNames from 'classnames'
import './index.scss'
export default class TaroPop extends Taro.Component {
/**
* @ 彈窗默認配置
*/
static defaultProps = {
isVisible: false, //彈窗顯示
title: '', //標題
content: '', //內容
contentStyle: null, //內容樣式
style: null, //自定義彈窗樣式
skin: '', //彈窗風格
icon: '', //彈窗圖標
xclose: false, //自定義關閉按鈕
shade: true, //遮罩層
shadeClose: true, //點擊遮罩關閉
opacity: '', //遮罩透明度
time: 0, //自動關閉時間
end: null, //銷燬彈窗回調函數
anim: 'scaleIn', //彈窗動畫
position: '', //彈窗位置顯示
btns: null, //彈窗按鈕 [{...args}, {...args}]
}
constructor(props) {
super(props)
this.state = {
...this.props,
}
this.timer = null
}
/**
* @ 顯示彈窗事件
*/
show = (options) => {
this.setState({
...this.props, ...options, isVisible: true
})
}
/**
* @ 關閉彈窗事件
*/
close = () => {
this.setState({...this.props})
this.timer && clearTimeout(this.timer)
delete this.timer
typeof this.state.end === 'function' && this.state.end.call(this)
}
/**
* @ 點擊遮罩關閉
*/
shadeClick = () => {
if(!this.state.shadeClose) return
this.close()
}
render() {
let { isVisible, title, content, contentStyle, style, skin, icon, xclose, shade, shadeClose, opacity, time, end, anim, position, btns } = this.state
let toastIcon = {
loading: require('./skin/loading.png'),
success: require('./skin/success.png'),
error: require('./skin/error.png'),
info: require('./skin/info.png'),
}
let taroEnv = process.env.TARO_ENV
...
// 渲染H5、RN模板
const renderTpl = (
<View className="taroPop">
{/* 遮罩 */}
{shade ? <View className="atpop__ui_mask" style={{opacity: opacity == '' ? .6 : opacity}} onClick={this.shadeClick} /> : null}
{/* 窗體 */}
<View className="atpop__ui_main">
<View className={classNames('atpop__ui_child', skin && 'atpop__' + skin, position && 'atpop__ui_child-' + position)} style={style}>
{/* 標題 */}
{title ? <Text className={classNames('atpop__ui_tit', skin && 'atpop__ui_tit-' + skin)}>{title}</Text> : null}
{/* 內容 */}
{content ? <View className="atpop__ui_cnt">
{/* toast內容 */}
{icon && skin === 'toast' ?
<View className="atpop__ui_toast">
{icon === 'loading' && taroEnv === 'rn' ?
<ActivityIndicator color="rgba(255,255,255,.5)" size={24} /> : <Image className={classNames('atpop__ui_toast-img', icon=='loading' && 'atpop__ui_toast-img-loading')} src={toastIcon[icon]} mode="aspectFit" />
}
</View>
:
null
}
{/* 文本內容 */}
<Text className={classNames('atpop__ui_cntxt', skin && 'atpop__ui_cntxt-' + skin)} style={contentStyle}>{content}</Text>
</View>
:
this.props.children
}
{/* 按鈕 */}
{btns ? <View className={classNames('atpop__ui_btns', skin && 'atpop__ui_btns-' + skin)}>
{btns.map((item, i) => {
return taroEnv === 'rn' ?
<TouchableHighlight className={classNames('atpop__ui_btn', skin && 'atpop__ui_btn-' + skin)} activeOpacity={1} underlayColor='rgba(200,200,200,.3)' key={i} onPress={item.onClick}>
<Text className={classNames('atpop__ui_btntxt', skin && 'atpop__ui_btntxt-' + skin)} style={item.style}>{item.text}</Text>
</TouchableHighlight>
:
<View className={classNames('atpop__ui_btn', skin && 'atpop__ui_btn-' + skin)} key={i} onClick={item.onClick}>
<Text className={classNames('atpop__ui_btntxt', skin && 'atpop__ui_btntxt-' + skin)} style={item.style}>{item.text}</Text>
</View>
})}
</View>
:
null
}
</View>
{/* xclose */}
{xclose ? <View className="atpop__ui_xclose" onClick={this.close}><Image className="atpop__ui_xclose-img" src={require('./skin/error.png')} mode="aspectFit" /></View> : null}
</View>
</View>
)
// 渲染窗體
if (taroEnv === 'rn') {
return (
<Modal transparent={true} visible={isVisible} onRequestClose={this.close}>
{renderTpl}
</Modal>
)
}else if (taroEnv === 'h5' || taroEnv === 'weapp'){
return isVisible && renderTpl
}
}
}
到這裏就基本介紹差不多了,後續會繼續分享一些實踐案例~~
最後附上基於vue+uniapp自定義彈窗組件
https://blog.csdn.net/yanxinyun1990/article/details/101594213
https://blog.csdn.net/yanxinyun1990/article/details/102475628