欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Taro自定义Modal对话框组件|taro仿微信、android弹窗

程序员文章站 2022-04-14 20:07:59
基于Taro多端实践TaroPop:自定义模态框|dialog对话框|msg消息框|Toast提示 taro自定义弹出框支持编译到多端H5/小程序/ReactNative,还可以自定义弹窗类型/弹窗样式、多按钮事件/样式、自动关闭、遮罩层、弹窗显示位置及自定义内容模板 用法 ▍在相应页面引入组件 i ......

基于taro多端实践taropop:自定义模态框|dialog对话框|msg消息框|toast提示

taro自定义弹出框支持编译到多端h5/小程序/reactnative,还可以自定义弹窗类型/弹窗样式、多按钮事件/样式、自动关闭、遮罩层、弹窗显示位置及自定义内容模板

Taro自定义Modal对话框组件|taro仿微信、android弹窗

用法

 ▍在相应页面引入组件

 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>
        );
    }
}

通过ref方式调用组件内show、close方法

 this.refs.taropop.show({...options}) 

 this.refs.taropop.close() 

 ▍自定义弹窗模板内容(如下图)

Taro自定义Modal对话框组件|taro仿微信、android弹窗

只需把页面上的模板写成如下即可,调用方式还和上面一样

<taropop ref="taropoptpl">
    ...
</taropop>

支持多种参数配置:

/** 
 * @ 弹窗默认配置 
 */
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}]
}
/** 
 * 显示弹窗事件 
 */
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()
}

◆ msg消息框提示

Taro自定义Modal对话框组件|taro仿微信、android弹窗

Taro自定义Modal对话框组件|taro仿微信、android弹窗

this.refs.taropop.show({
    content: 'taro自定义模态modal弹窗',
    shadeclose: false,
    style: {backgroundcolor: 'rgba(0,0,0,.7)', borderradius: 6},
    contentstyle: {color: '#fff', fontsize: 12, padding: 12},
    time: 3,
    opacity: .2,
})

◆ toast轻提示效果(success | error | info | loading四种图标

Taro自定义Modal对话框组件|taro仿微信、android弹窗

let taropop = this.refs.taropop
taropop.show({
    skin: 'toast',
    content: 'loading',
    icon: 'loading', //success | info | error | loading
    shade: false,
    time: 3
})

◆ android弹窗效果

Taro自定义Modal对话框组件|taro仿微信、android弹窗

let taropop = this.refs.taropop
taropop.show({
    skin: 'android',
    title: '邮件提醒',
    content: '系统检测到你未开启新邮件提醒功能,为了保证新邮件能及时收到提醒,请前往系统 [设置] - [应用] 中开启',
    shadeclose: false,
    
    btns: [
        {
            text: '取消',
            onclick() {
                taropop.close()
            }
        },
        {
            text: '前往设置',
            style: {color: '#4eca33'},
            onclick() {
                console.log('您点击了前往设置!')
            }
        }
    ]
})

emmmm,看了如上展示及调用方式,是否觉得还不错哟!哈哈哈,这可是花了无数个日夜采坑的结果。

尤其是编译到reactnative端,各种千奇百怪的问题,有些抓狂~~

Taro自定义Modal对话框组件|taro仿微信、android弹窗

Taro自定义Modal对话框组件|taro仿微信、android弹窗

Taro自定义Modal对话框组件|taro仿微信、android弹窗

Taro自定义Modal对话框组件|taro仿微信、android弹窗

Taro自定义Modal对话框组件|taro仿微信、android弹窗

Taro自定义Modal对话框组件|taro仿微信、android弹窗

Taro自定义Modal对话框组件|taro仿微信、android弹窗

另外对于不同端的一些兼容性处理,需要判断各端环境并渲染相应模板,对于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
}

另外在样式处理上也需注意rn端兼容性。

/**
 * @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
        }
    }
}

好了,以上就是taro自定义弹窗组件实现方式,希望能有帮助✊✊~~