gpt4 book ai didi

react18hooks自定义移动端Popup弹窗组件RcPop

转载 作者:我是一只小鸟 更新时间:2023-07-31 14:31:49 26 4
gpt4 key购买 nike

基于 React18 Hooks 实现手机端弹框组件 RcPop 。

react-popup 基于 react18+hook 自定义多功能弹框组件。整合了 msg/alert/dialog/toast及android/ios 弹窗效果。支持 20+ 自定义参数、 组件式+函数式 调用方式,全方位满足各种弹窗场景需求.

引入组件

在需要使用弹窗的页面引入组件.

                          
                            //
                          
                          
                             引入自定义组件
                          
                          
import RcPop, { rcpop } from './components/rcpop'
                        

RcPop支持  组件式+函数式  两种调用方式.

组件写法 。

                          
                            <
                          
                          
                            RcPop
    
                          
                          
                            visible
                          
                          
                            ={visible}
    
                          
                          
                            title
                          
                          
                            ="标题"
                          
                          
                            
    content
                          
                          
                            ="弹窗内容"
                          
                          
                            
    type
                          
                          
                            ="android"
                          
                          
                            
    shadeClose
                          
                          
                            ="false"
                          
                          
                            
    closeable
    :btns
                          
                          
                            ="[
        {text: '取消', click: () => setVisible(false)},
        {text: '确认', style: {color: '#09f'}, click: handleOK},
    ]"
                          
                          
                            
    @onOpen
                          
                          
                            ={handleOpen}
    
                          
                          
                            @onClose
                          
                          
                            ={handleClose}

                          
                          
                            />
                          
                          
                            <
                          
                          
                            div
                          
                          
                            >
                          
                          这里是自定义弹窗内容,优先级高于content内容。
                          
                            </
                          
                          
                            div
                          
                          
                            >
                          
                          
                            </
                          
                          
                            RcPop
                          
                          
                            >
                          
                        

函数写法 。

                          
                            function
                          
                          
                             handlePopup() {
    rcpop({
        title: 
                          
                          '标题'
                          
                            ,
        content: `
                          
                          <div style="padding:20px;">
            <p>函数式调用:<em style="color:#999;">rcpop({...})</em></p>
        </div>`,

                          
                                    btns: [
            {
                text: 
                          
                          '取消'
                          
                            ,
                click: () 
                          
                          =>
                          
                             {
                    
                          
                          
                            //
                          
                          
                             关闭弹窗
                          
                          
                                                rcpop.close()
                }
            },
            {
                text: 
                          
                          '确认'
                          
                            ,
                style: {color: 
                          
                          '#09f'
                          
                            },
                click: () 
                          
                          =>
                          
                             {
                    rcpop({
                        type: 
                          
                          'toast'
                          
                            ,
                        icon: 
                          
                          'loading'
                          
                            ,
                        content: 
                          
                          '加载中...'
                          
                            ,
                        opacity: .
                          
                          2
                          
                            ,
                        time: 
                          
                          2
                          
                            
                    })
                }
            }
        ]
    })
}
                          
                        
  • msg类型

  • 自定义多按钮

                          
                            rcpop({
    title: 
                          
                          '标题'
                          
                            ,
    content: `
                          
                          <div style="color:#f90">
        <p>显示自定义弹窗内容</p>
    </div>`,

                          
                                btns: [
        { text: 
                          
                          '稍后提示'
                          
                             },
        { text: 
                          
                          '取消', click: () =>
                          
                             rcpop.close() },
        {
            text: 
                          
                          '立即更新'
                          
                            ,
            style: {color: 
                          
                          '#09f'
                          
                            },
            click: () 
                          
                          =>
                          
                             {
                
                          
                          
                            //
                          
                          
                             ...
                          
                          
                                        }
        }
    ]
})
                          
                        

  • ios弹窗类型

  • android弹窗类型

  • 长按/右键菜单

  • 自定义内容

                          
                            <
                          
                          
                            RcPop
    
                          
                          
                            visible
                          
                          
                            ={visible}
    
                          
                          
                            closeable
    xposition
                          
                          
                            ="top"
                          
                          
                            
    content
                          
                          
                            ="这里是内容信息"
                          
                          
                            
    btns
                          
                          
                            ={[
        
                          
                          
                            {text: '确认', style: {color: '#00d8ff'}, click: () 
                          
                          
                            =
                          
                          
                            >
                          
                          
                             setVisible(false)},
    ]}
    onOpen={()=> {
        console.log('弹窗开启...')
    }}
    onClose={()=>{
        console.log('弹窗关闭...')
        setVisible(false)
    }}
    >
    
                          
                          
                            <
                          
                          
                            div 
                          
                          
                            style
                          
                          
                            ={{padding: 
                          
                          
                            '15px'}}
                          
                          
                            >
                          
                          
                            <
                          
                          
                            img 
                          
                          
                            src
                          
                          
                            ={reactLogo} 
                          
                          
                            width
                          
                          
                            ="60"
                          
                          
                             onClick
                          
                          
                            ={handleContextPopup} 
                          
                          
                            />
                          
                          
                            <
                          
                          
                            h3 
                          
                          
                            style
                          
                          
                            ={{color:'#f60', 
                          
                          
                            'paddingTop':'10px'}}
                          
                          
                            >
                          
                          当 content 和 自定义插槽 内容同时存在,只显示插槽内容。
                          
                            </
                          
                          
                            h3
                          
                          
                            >
                          
                          
                            </
                          
                          
                            div
                          
                          
                            >
                          
                          
                            </
                          
                          
                            RcPop
                          
                          
                            >
                          
                        
                          
                            function
                          
                          
                             handleContextPopup(e) {
    let points 
                          
                          =
                          
                             [e.clientX, e.clientY]
    rcpop({
        type: 
                          
                          'contextmenu'
                          
                            ,
        follow: points,
        opacity: 
                          
                          0
                          
                            ,
        btns: [
            {text: 
                          
                          '标记备注信息'
                          
                            },
            {
                text: 
                          
                          '删除'
                          
                            ,
                style: {color:
                          
                          '#f00'
                          
                            },
                click: () 
                          
                          =>
                          
                             {
                    rcpop.close()
                }
            }
        ]
    })
}
                          
                        

这次主打的是学习 React Hooks 开发自定义弹窗,之前也有开发过类似的弹层组件.

https://www.cnblogs.com/xiaoyan2017/p/14085142.html 。

https://www.cnblogs.com/xiaoyan2017/p/11589149.html 。

编码开发

在components目录下新建rcpop文件夹.

rcpop支持如下参数配置 。

                          
                            //
                          
                          
                             弹窗默认参数
                          
                          
const defaultProps =
                          
                             {
    
                          
                          
                            //
                          
                          
                             是否显示弹出层
                          
                          
    visible: 
                          
                            false
                          
                          
                            ,
    
                          
                          
                            //
                          
                          
                             弹窗唯一性标识
                          
                          
    id: 
                          
                            null
                          
                          
                            ,
    
                          
                          
                            //
                          
                          
                             弹窗标题
                          
                          
    title: ''
                          
                            ,
    
                          
                          
                            //
                          
                          
                             弹窗内容
                          
                          
    content: ''
                          
                            ,
    
                          
                          
                            //
                          
                          
                             弹窗类型(toast | footer | actionsheet | actionsheetPicker | ios | android | androidSheet | contextmenu)
                          
                          
    type: ''
                          
                            ,
    
                          
                          
                            //
                          
                          
                             toast图标(loading | success | fail)
                          
                          
    icon: ''
                          
                            ,
    
                          
                          
                            //
                          
                          
                             是否显示遮罩层
                          
                          
    shade: 
                          
                            true
                          
                          
                            ,
    
                          
                          
                            //
                          
                          
                             点击遮罩层关闭
                          
                          
    shadeClose: 
                          
                            true
                          
                          
                            ,
    
                          
                          
                            //
                          
                          
                             遮罩透明度
                          
                          
    opacity: ''
                          
                            ,
    
                          
                          
                            //
                          
                          
                             自定义遮罩层样式
                          
                          
                                overlayStyle: {},
    
                          
                          
                            //
                          
                          
                             是否圆角
                          
                          
    round: 
                          
                            false
                          
                          
                            ,
    
                          
                          
                            //
                          
                          
                             是否显示关闭图标
                          
                          
    closeable: 
                          
                            false
                          
                          
                            ,
    
                          
                          
                            //
                          
                          
                             关闭图标位置(left | right | top | bottom)
                          
                          
    closePosition: 'right'
                          
                            ,
    
                          
                          
                            //
                          
                          
                             关闭图标颜色
                          
                          
    closeColor: ''
                          
                            ,
    
                          
                          
                            //
                          
                          
                             动画类型(scaleIn | fadeIn | footer | fadeInUp | fadeInDown)
                          
                          
    anim: 'scaleIn'
                          
                            ,
    
                          
                          
                            //
                          
                          
                             弹窗出现位置(top | right | bottom | left)
                          
                          
    position: ''
                          
                            ,
    
                          
                          
                            //
                          
                          
                             长按/右键弹窗(坐标点)
                          
                          
    follow: 
                          
                            null
                          
                          
                            ,
    
                          
                          
                            //
                          
                          
                             弹窗关闭时长,单位秒
                          
                          
    time: 0
                          
                            ,
    
                          
                          
                            //
                          
                          
                             弹窗层级
                          
                          
    zIndex: 2023
                          
                            ,
    
                          
                          
                            //
                          
                          
                             弹窗按钮组(text | style | disabled | click)
                          
                          
    btns: 
                          
                            null
                          
                          
                            ,
    
                          
                          
                            //
                          
                          
                             指定挂载的节点(仅对标签组件有效)
                          
                          
                            //
                          
                          
                             teleport = () => document.body,
                          
                          
    teleport: 
                          
                            null
                          
                          
                            ,
    
                          
                          
                            //
                          
                          
                             弹窗打开回调
                          
                          
    onOpen: () =>
                          
                             {},
    
                          
                          
                            //
                          
                          
                             弹窗关闭回调
                          
                          
    onClose: () =>
                          
                             {},
    
                          
                          
                            //
                          
                          
                             点击遮罩层回调
                          
                          
    onClickOverlay: () =>
                          
                             {},
    
                          
                          
                            //
                          
                          
                             自定义样式
                          
                          
                                customStyle: {},
    
                          
                          
                            //
                          
                          
                             类名
                          
                          
    className: 
                          
                            null
                          
                          
                            ,
    
                          
                          
                            //
                          
                          
                             默认插槽内容
                          
                          
    children: 
                          
                            null
                          
                          
                            
}
                          
                        

弹窗组件模板 。

                          
                            const renderNode = () => {
    return (
        
                          
                          
                            <
                          
                          
                            div 
                          
                          
                            ref
                          
                          
                            ={ref} 
                          
                          
                            className
                          
                          
                            ={classNames('rc__popup', 
                          
                          
                            options.className, {'rc__popup-closed': closed})} id
                          
                          
                            ={options.id} 
                          
                          
                            style
                          
                          
                            ={{'display': 
                          
                          
                            !opened.current ? 'none' : undefined}}
                          
                          
                            >
                          
                          
                            
            {/* 遮罩层 */}
            { isTrue(options.shade) && 
                          
                          
                            <
                          
                          
                            div 
                          
                          
                            className
                          
                          
                            ="rcpopup__overlay"
                          
                          
                             onClick
                          
                          
                            ={handleShadeClick} 
                          
                          
                            style
                          
                          
                            ={{'opacity': 
                          
                          
                            options.opacity, 'zIndex': oIndex-1, ...options.overlayStyle}}
                          
                          
                            ></
                          
                          
                            div
                          
                          
                            >
                          
                          
                             }
            {/* 窗体 */}
            
                          
                          
                            <
                          
                          
                            div 
                          
                          
                            className
                          
                          
                            ="rcpopup__wrap"
                          
                          
                             style
                          
                          
                            ={{'zIndex': 
                          
                          
                            oIndex}}
                          
                          
                            >
                          
                          
                            <
                          
                          
                            div
                    
                          
                          
                            ref
                          
                          
                            ={childRef}
                    
                          
                          
                            className
                          
                          
                            ={classNames(
                        
                          
                          
                            'rcpopup__child',
                        {
                            [`anim-${options.anim}`]: options.anim,
                            [`popupui__${options.type}`]: options.type,
                            'round': options.round
                        },
                        options.position
                    )}
                    style
                          
                          
                            ={popStyles}
                
                          
                          
                            >
                          
                          
                            
                    { options.title && 
                          
                          
                            <
                          
                          
                            div 
                          
                          
                            className
                          
                          
                            ="rcpopup__title"
                          
                          
                            >
                          
                          {options.title}
                          
                            </
                          
                          
                            div
                          
                          
                            >
                          
                          
                             }
                    { (options.type == 'toast' && options.icon) && 
                          
                          
                            <
                          
                          
                            div 
                          
                          
                            className
                          
                          
                            ={classNames('rcpopup__toast', 
                          
                          
                            options.icon)} dangerouslySetInnerHTML
                          
                          
                            ={{__html: 
                          
                          
                            ToastIcon[options.icon]}}
                          
                          
                            ></
                          
                          
                            div
                          
                          
                            >
                          
                          
                             }
                    {/* 内容 */}
                    { options.children ? 
                          
                          
                            <
                          
                          
                            div 
                          
                          
                            className
                          
                          
                            ="rcpopup__content"
                          
                          
                            >
                          
                          {options.children}
                          
                            </
                          
                          
                            div
                          
                          
                            >
                          
                           : options.content ? 
                          
                            <
                          
                          
                            div 
                          
                          
                            className
                          
                          
                            ="rcpopup__content"
                          
                          
                             dangerouslySetInnerHTML
                          
                          
                            ={{__html: 
                          
                          
                            options.content}}
                          
                          
                            ></
                          
                          
                            div
                          
                          
                            >
                          
                          
                             : null }
                    {/* 按钮组 */}
                    { options.btns && 
                        
                          
                          
                            <
                          
                          
                            div 
                          
                          
                            className
                          
                          
                            ="rcpopup__actions"
                          
                          
                            >
                          
                          
                            
                            {
                                options.btns.map((btn, index) => {
                                    return 
                          
                          
                            <
                          
                          
                            span 
                          
                          
                            className
                          
                          
                            ={classNames('btn', 
                          
                          
                            {'btn-disabled': btn.disabled})} key
                          
                          
                            ={index} 
                          
                          
                            style
                          
                          
                            ={btn.style} 
                          
                          
                            dangerouslySetInnerHTML
                          
                          
                            ={{__html: 
                          
                          
                            btn.text}} onClick
                          
                          
                            ={e =
                          
                          
                            >
                          
                           handleActions(e, index)}>
                          
                            </
                          
                          
                            span
                          
                          
                            >
                          
                          
                            
                                })
                            }
                        
                          
                          
                            </
                          
                          
                            div
                          
                          
                            >
                          
                          
                            
                    }
                    { isTrue(options.closeable) && 
                          
                          
                            <
                          
                          
                            div 
                          
                          
                            className
                          
                          
                            ={classNames('rcpopup__xclose', 
                          
                          
                            options.closePosition)} style
                          
                          
                            ={{'color': 
                          
                          
                            options.closeColor}} onClick
                          
                          
                            ={close}
                          
                          
                            ></
                          
                          
                            div
                          
                          
                            >
                          
                          
                             }
                
                          
                          
                            </
                          
                          
                            div
                          
                          
                            >
                          
                          
                            </
                          
                          
                            div
                          
                          
                            >
                          
                          
                            </
                          
                          
                            div
                          
                          
                            >
                          
                          
                            
    )
}
                          
                        

完整代码块 。

                          
                            /*
                          
                          
                            *
 * @title    基于react18 hooks自定义移动端弹窗组件
 * @author   YXY  Q: 282310962
 * @date     2023/07/25
 
                          
                          
                            */
                          
                          
                            
import { useState, useEffect, createRef, useRef, forwardRef, useImperativeHandle } from 
                          
                          'react'
                          
                            
import { createPortal } from 
                          
                          'react-dom'
                          
                            
import { createRoot } from 
                          
                          'react-dom/client'


                          
                            //
                          
                          
                             ...
                          
                          
                            
const RcPop 
                          
                          = forwardRef((props, ref) =>
                          
                             {
    const mergeProps 
                          
                          =
                          
                             {
        ...defaultProps,
        ...props
    }
    
    const [options, setOptions] 
                          
                          =
                          
                             useState(mergeProps)
    const [oIndex, setOIndex] 
                          
                          =
                          
                             useState(options.zIndex)
    const [closed, setClosed] 
                          
                          = useState(
                          
                            false
                          
                          
                            )
    const [followStyle, setFollowStyle] 
                          
                          =
                          
                             useState({
        position: 
                          
                          'absolute'
                          
                            ,
        left: 
                          
                          '-999px'
                          
                            ,
        top: 
                          
                          '-999px'
                          
                            
    })

    const opened 
                          
                          = useRef(
                          
                            false
                          
                          
                            )
    const childRef 
                          
                          =
                          
                             useRef()
    const stopTimer 
                          
                          = useRef(
                          
                            null
                          
                          
                            )

    const popStyles 
                          
                          = options.follow ?
                          
                             { ...followStyle, ...options.customStyle } : { ...options.customStyle }

    const isTrue 
                          
                          = (str) => /^true$/
                          
                            i.test(str)

    const ToastIcon 
                          
                          =
                          
                             {
        loading: 
                          
                          '<svg viewBox="25 25 50 50"><circle fill="none" cx="50" cy="50" r="20"></circle></svg>'
                          
                            ,
        success: 
                          
                          '<svg viewBox="0 0 1024 1024"><path d="M512 85.333c235.648 0 426.667 191.019 426.667 426.667S747.648 938.667 512 938.667 85.333 747.648 85.333 512 276.352 85.333 512 85.333zm-74.965 550.4l-90.582-90.581a42.667 42.667 0 1 0-60.33 60.33l120.704 120.705a42.667 42.667 0 0 0 60.33 0L768.811 424.49a42.667 42.667 0 1 0-60.288-60.331L436.992 635.648z" /></svg>'
                          
                            ,
        error: 
                          
                          '<svg viewBox="0 0 1024 1024"><path d="M512 85.333C276.352 85.333 85.333 276.352 85.333 512S276.352 938.667 512 938.667 938.667 747.648 938.667 512 747.648 85.333 512 85.333zm128.427 606.72l-129.75-129.749-129.066 129.024a35.968 35.968 0 1 1-50.902-50.901L459.733 511.36 329.301 380.928a35.968 35.968 0 1 1 50.859-50.944l130.475 130.475 129.706-129.75a35.968 35.968 0 1 1 50.944 50.902L561.536 511.36l129.75 129.75a35.968 35.968 0 1 1-50.902 50.943z" /></svg>'
                          
                            ,
        warning: 
                          
                          '<svg viewBox="0 0 1024 1024"><path d="M512 941.12q-89.28 0-167.52-34.08t-136.32-92.16T116 678.08t-34.08-168T116 342.56t92.16-136.32 136.32-92.16T512 80t168 34.08 136.8 92.16 92.16 136.32 34.08 167.52-34.08 168-92.16 136.8T680 907.04t-168 34.08zM460.16 569.6q0 23.04 14.88 38.88T512 624.32t37.44-15.84 15.36-38.88V248q0-23.04-15.36-36.96T512 197.12t-37.44 14.4-15.36 37.44zM512 688.64q-27.84 0-47.52 19.68t-19.68 47.52 19.68 47.52T512 823.04t48-19.68 20.16-47.52T560 708.32t-48-19.68z"/></svg>'
                          
                            ,
        info: 
                          
                          '<svg viewBox="0 0 1024 1024"><path d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm84 343.1l-87 301.4c-4.8 17.2-7.2 28.6-7.2 33.9 0 3.1 1.3 6 3.8 8.7s5.2 4 8.1 4c4.8 0 9.6-2.1 14.4-6.4 12.7-10.5 28-29.4 45.8-56.8l14.4 8.5c-42.7 74.4-88 111.6-136.1 111.6-18.4 0-33-5.2-43.9-15.5-10.9-10.3-16.3-23.4-16.3-39.2 0-10.5 2.4-23.7 7.2-39.9l58.9-202.7c5.7-19.5 8.5-34.2 8.5-44.1 0-6.2-2.7-11.7-8.1-16.5-5.4-4.8-12.7-7.2-22-7.2-4.2 0-9.3.1-15.3.4l5.5-17L570.4 407H596v.1zm17.8-88.7c-12.2 12.2-26.9 18.2-44.1 18.2-17 0-31.5-6.1-43.7-18.2-12.2-12.2-18.2-26.9-18.2-44.1s6-31.9 18-44.1c12-12.1 26.6-18.2 43.9-18.2 17.5 0 32.3 6.1 44.3 18.2 12 12.2 18 26.9 18 44.1s-6.1 31.9-18.2 44.1z"/></svg>'
                          
                            ,
    }

    
                          
                          
                            /*
                          
                          
                            *
     * 开启弹窗
     
                          
                          
                            */
                          
                          
                            function
                          
                          
                             open(params) {
        params 
                          
                          &&
                          
                             setOptions({ ...options, ...params })

        
                          
                          
                            if
                          
                          (options.type == 'toast'
                          
                            ) {
            options.time 
                          
                          = options.time || 3
                          
                            
        }
        
                          
                          
                            if
                          
                          (opened.current) 
                          
                            return
                          
                          
                            
        opened.current 
                          
                          = 
                          
                            true
                          
                          
                            
        
        setOIndex(
                          
                          ++index +
                          
                             options.zIndex)
        options.onOpen
                          
                          ?
                          
                            .()

        
                          
                          
                            //
                          
                          
                             右键/长按菜单
                          
                          
                            if
                          
                          
                            (options.follow) {
            setTimeout(() 
                          
                          =>
                          
                             {
                let rcpop 
                          
                          =
                          
                             childRef.current
                let oW, oH, winW, winH, pos

                oW 
                          
                          =
                          
                             rcpop.clientWidth
                oH 
                          
                          =
                          
                             rcpop.clientHeight
                winW 
                          
                          =
                          
                             window.innerWidth
                winH 
                          
                          =
                          
                             window.innerHeight
                pos 
                          
                          = getPos(options.follow[0], options.follow[1
                          
                            ], oW, oH, winW, winH)

                setFollowStyle({
                    ...followStyle,
                    left: pos[
                          
                          0
                          
                            ],
                    top: pos[
                          
                          1
                          
                            ]
                })
            })
        }

        
                          
                          
                            if
                          
                          
                            (options.time) {
            clearTimeout(stopTimer.current)
            stopTimer.current 
                          
                          = setTimeout(() =>
                          
                             {
                close()
            }, options.time 
                          
                          * 1000
                          
                            )
        }
    }

    
                          
                          
                            /*
                          
                          
                            *
     * 关闭弹窗
     
                          
                          
                            */
                          
                          
                            function
                          
                          
                             close() {
        
                          
                          
                            if
                          
                          (!opened.current) 
                          
                            return
                          
                          
                            
        setClosed(
                          
                          
                            true
                          
                          
                            )
        setTimeout(() 
                          
                          =>
                          
                             {
            setClosed(
                          
                          
                            false
                          
                          
                            )
            opened.current 
                          
                          = 
                          
                            false
                          
                          
                            
            
            options.onClose
                          
                          ?
                          
                            .()
            clearTimeout(stopTimer.current)
        }, 
                          
                          200
                          
                            )
    }

    
                          
                          
                            //
                          
                          
                             点击遮罩层
                          
                          
                            function
                          
                          
                             handleShadeClick(e) {
        options.onClickOverlay
                          
                          ?
                          
                            .(e)
        
                          
                          
                            if
                          
                          
                            (isTrue(options.shadeClose)) {
            close()
        }
    }

    
                          
                          
                            //
                          
                          
                             点击按钮组
                          
                          
                            function
                          
                          
                             handleActions(e, index) {
        let btn 
                          
                          =
                          
                             options.btns[index]
        
                          
                          
                            if
                          
                          (!
                          
                            btn.disabled) {
            btn
                          
                          ?.click?
                          
                            .(e)
        }
    }

    
                          
                          
                            //
                          
                          
                             抽离的React的classnames操作类
                          
                          
                            function
                          
                          
                             classNames() {
        
                          
                          
                            var
                          
                           hasOwn =
                          
                             {}.hasOwnProperty
        
                          
                          
                            var
                          
                           classes =
                          
                             []
        
                          
                          
                            for
                          
                           (
                          
                            var
                          
                           i = 0; i < arguments.length; i++
                          
                            ) {
            
                          
                          
                            var
                          
                           arg =
                          
                             arguments[i]
            
                          
                          
                            if
                          
                           (!arg) 
                          
                            continue
                          
                          
                            var
                          
                           argType = 
                          
                            typeof
                          
                          
                             arg
            
                          
                          
                            if
                          
                           (argType === 'string' || argType === 'number'
                          
                            ) {
                classes.push(arg)
            } 
                          
                          
                            else
                          
                          
                            if
                          
                           (Array.isArray(arg) &&
                          
                             arg.length) {
                
                          
                          
                            var
                          
                           inner = classNames.apply(
                          
                            null
                          
                          
                            , arg)
                
                          
                          
                            if
                          
                          
                             (inner) {
                    classes.push(inner)
                }
            } 
                          
                          
                            else
                          
                          
                            if
                          
                           (argType === 'object'
                          
                            ) {
                
                          
                          
                            for
                          
                           (
                          
                            var
                          
                           key 
                          
                            in
                          
                          
                             arg) {
                    
                          
                          
                            if
                          
                           (hasOwn.call(arg, key) &&
                          
                             arg[key]) {
                        classes.push(key)
                    }
                }
            }
        }
        
                          
                          
                            return
                          
                           classes.join(' '
                          
                            )
    }

    
                          
                          
                            //
                          
                          
                             获取挂载节点
                          
                          
                            function
                          
                          
                             getTeleport(getContainer) {
        const container 
                          
                          = 
                          
                            typeof
                          
                           getContainer == 'function' ?
                          
                             getContainer() : getContainer
        
                          
                          
                            return
                          
                           container ||
                          
                             document.body
    }
    
                          
                          
                            //
                          
                          
                             设置挂载节点
                          
                          
                            function
                          
                          
                             renderTeleport(getContainer, node) {
        
                          
                          
                            if
                          
                          
                            (getContainer) {
            const container 
                          
                          =
                          
                             getTeleport(getContainer)
            
                          
                          
                            return
                          
                          
                             createPortal(node, container)
        }
        
                          
                          
                            return
                          
                          
                             node
    }

    
                          
                          
                            //
                          
                          
                             获取弹窗坐标点
                          
                          
                            function
                          
                          
                             getPos(x, y, ow, oh, winW, winH) {
        let l 
                          
                          = (x + ow) > winW ? x -
                          
                             ow : x;
        let t 
                          
                          = (y + oh) > winH ? y -
                          
                             oh : y;
        
                          
                          
                            return
                          
                          
                             [l, t];
    }

    const renderNode 
                          
                          = () =>
                          
                             {
        
                          
                          
                            return
                          
                          
                             (
            
                          
                          <div ref={ref} className={classNames('rc__popup', options.className, {'rc__popup-closed': closed})} id={options.id} style={{'display': !opened.current ? 'none' : undefined}}>
                          
                            
                {
                          
                          
                            /*
                          
                          
                             遮罩层 
                          
                          
                            */
                          
                          
                            }
                { isTrue(options.shade) 
                          
                          && <div className="rcpopup__overlay" onClick={handleShadeClick} style={{'opacity': options.opacity, 'zIndex': oIndex-1, ...options.overlayStyle}}></div> }
                {
                          
                            /*
                          
                          
                             窗体 
                          
                          
                            */
                          
                          
                            }
                
                          
                          <div className="rcpopup__wrap" style={{'zIndex': oIndex}}>
                    <
                          
                            div
                        ref
                          
                          =
                          
                            {childRef}
                        className
                          
                          =
                          
                            {classNames(
                            
                          
                          'rcpopup__child'
                          
                            ,
                            {
                                [`anim
                          
                          -
                          
                            ${options.anim}`]: options.anim,
                                [`popupui__${options.type}`]: options.type,
                                
                          
                          'round'
                          
                            : options.round
                            },
                            options.position
                        )}
                        style
                          
                          =
                          
                            {popStyles}
                    
                          
                          >
                          
                            
                        { options.title 
                          
                          && <div className="rcpopup__title">{options.title}</div> }
                        { (options.type == 'toast' && options.icon) && <div className={classNames('rcpopup__toast', options.icon)} dangerouslySetInnerHTML={{__html: ToastIcon[options.icon]}}></div> }
                        {
                          
                            /*
                          
                          
                             内容 
                          
                          
                            */
                          
                          
                            }
                        {
                          
                          
                            /*
                          
                          
                            { (options.children || options.content) && <div className="rcpopup__content">{options.children || options.content}</div> }
                          
                          
                            */
                          
                          
                            }
                        { options.children 
                          
                          ? <div className="rcpopup__content">{options.children}</div> : options.content ? <div className="rcpopup__content" dangerouslySetInnerHTML={{__html: options.content}}></div> : 
                          
                            null
                          
                          
                             }
                        {
                          
                          
                            /*
                          
                          
                             按钮组 
                          
                          
                            */
                          
                          
                            }
                        { options.btns 
                          
                          && 
                            <div className="rcpopup__actions">
                          
                            
                                {
                                    options.btns.map((btn, index) 
                          
                          =>
                          
                             {
                                        
                          
                          
                            return
                          
                           <span className={classNames('btn', {'btn-disabled': btn.disabled})} key={index} style={btn.style} dangerouslySetInnerHTML={{__html: btn.text}} onClick={e => handleActions(e, index)}></span>

                          
                                                                })
                                }
                            
                          
                          </div>

                          
                                                    }
                        { isTrue(options.closeable) 
                          
                          && <div className={classNames('rcpopup__xclose', options.closePosition)} style={{'color': options.closeColor}} onClick={close}></div> }
                    </div>
                </div>
            </div>

                          
                                    )
    }

    useEffect(() 
                          
                          =>
                          
                             {
        props.visible 
                          
                          &&
                          
                             open()
        
                          
                          !props.visible &&
                          
                             close()
    }, [props.visible])

    
                          
                          
                            //
                          
                          
                             暴露指定的方法给父组件调用
                          
                          
    useImperativeHandle(ref, () =>
                          
                             ({
        open,
        close
    }))
    
    
                          
                          
                            return
                          
                           renderTeleport(options.teleport ||
                          
                             mergeProps.teleport, renderNode())
})
                          
                        

react动态设置className,于是抽离封装了classNames函数.

                          
                            //
                          
                          
                             抽离的React的classnames操作类
                          
                          
                            function
                          
                          
                             classNames() {
    
                          
                          
                            var
                          
                           hasOwn =
                          
                             {}.hasOwnProperty
    
                          
                          
                            var
                          
                           classes =
                          
                             []
    
                          
                          
                            for
                          
                           (
                          
                            var
                          
                           i = 0; i < arguments.length; i++
                          
                            ) {
        
                          
                          
                            var
                          
                           arg =
                          
                             arguments[i]
        
                          
                          
                            if
                          
                           (!arg) 
                          
                            continue
                          
                          
                            var
                          
                           argType = 
                          
                            typeof
                          
                          
                             arg
        
                          
                          
                            if
                          
                           (argType === 'string' || argType === 'number'
                          
                            ) {
            classes.push(arg)
        } 
                          
                          
                            else
                          
                          
                            if
                          
                           (Array.isArray(arg) &&
                          
                             arg.length) {
            
                          
                          
                            var
                          
                           inner = classNames.apply(
                          
                            null
                          
                          
                            , arg)
            
                          
                          
                            if
                          
                          
                             (inner) {
                classes.push(inner)
            }
        } 
                          
                          
                            else
                          
                          
                            if
                          
                           (argType === 'object'
                          
                            ) {
            
                          
                          
                            for
                          
                           (
                          
                            var
                          
                           key 
                          
                            in
                          
                          
                             arg) {
                
                          
                          
                            if
                          
                           (hasOwn.call(arg, key) &&
                          
                             arg[key]) {
                    classes.push(key)
                }
            }
        }
    }
    
                          
                          
                            return
                          
                           classes.join(' '
                          
                            )
}
                          
                        

非常方便的实现各种动态操作className类.

通过  createRoot  将弹窗组件挂载到body,实现函数式调用.

                          
                            /*
                          
                          
                            *
 * 函数式弹窗组件
 * rcpop({...}) | rcpop.close()
 
                          
                          
                            */
                          
                          
                            
let popRef 
                          
                          =
                          
                             createRef()

                          
                          
                            function
                          
                           Popup(options =
                          
                             {}) {
    options.id 
                          
                          = options.id || 'rcpopup-' + Math.floor(Math.random() * 10000
                          
                            )

    
                          
                          
                            //
                          
                          
                             判断id唯一性
                          
                          
    let rnode =
                          
                             document.querySelector(`#${options.id}`)
    
                          
                          
                            if
                          
                          (options.id && rnode) 
                          
                            return
                          
                          
                            

    const div 
                          
                          = document.createElement('div'
                          
                            )
    document.body.appendChild(div)

    const root 
                          
                          =
                          
                             createRoot(div)
    root.render(
        
                          
                          <
                          
                            RcPop
            ref
                          
                          =
                          
                            {popRef}
            visible
                          
                          ={
                          
                            true
                          
                          
                            }
            {...options}
            onClose
                          
                          ={() =>
                          
                             {
                let node 
                          
                          =
                          
                             document.querySelector(`#${options.id}`)
                
                          
                          
                            if
                          
                          (!node) 
                          
                            return
                          
                          
                            
                root.unmount()
                document.body.removeChild(div)
            }}
        
                          
                          />

                          
                                )

    
                          
                          
                            return
                          
                          
                             popRef
}
                          
                        

OK,以上就是react18 hook实现自定义弹窗的一些小分享,希望对大家有所帮助~~💪 。

  。

最后此篇关于react18hooks自定义移动端Popup弹窗组件RcPop的文章就讲到这里了,如果你想了解更多关于react18hooks自定义移动端Popup弹窗组件RcPop的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com