taroPop自定义弹层组件|Modal框|dialog对话框|仿微信/ios/android对话框
实现了自定义多种弹窗类型(msg/toast/ios/android)/弹窗样式、支持多个按钮事件/按钮样式、自动关闭、遮罩层、弹窗位置及自定义slot模板
如下图:H5+小程序+ReactNative端效果
支持以下自定义参数配置:
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}]
}
组件用法:
在页面引入自定义模态框组件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>
);
}
}
通过如下方式调用组件内show及close方法this.refs.taroPop.show({...options})
this.refs.taroPop.close()
- 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('您点击了前往设置!') } } ] })
调用方式和上面一样,不过是不同的参数配置不同而已。
/**
* @Title Taro自定义弹窗组件 - taroPop.jsx
* @Time andy by 2019-11-28
*/
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)
}
...
render() {
let {
isVisible, title, content, contentStyle, style, skin, icon, xclose, shade, shadeClose, opacity, time, end, anim, position, btns } = this.state
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
}
}
}
另外编译到RN需要特别注意样式问题,flex布局及最好使用BEM命名规则。
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
}
像上面,taro还提供了对于不同端环境变量判断,另外RN端使用到了Modal组件包裹。
到这里就基本介绍完了,后续会继续放送一些分享实例。👦👦