js弹出框自定义(js实现弹出框的插件)

今天给小伙伴们分享一个全新开发的React自定义对话框最近RLayer。

js弹出框自定义(js实现弹出框的插件)(1)

rlayer 基于react.js开发的PC桌面端交互式弹出框组件。融合了Dialog、Message、Notification、ActionSheet、Toast、Popover、Popconfirm等多种功能。

js弹出框自定义(js实现弹出框的插件)(2)

看名称就能联想到前端界有名的弹窗layer.js,其实在设计开发之初就有借鉴layer插件实现思想。

js弹出框自定义(js实现弹出框的插件)(3)

功能

  • 提供函数式调用方法 rlayer({…})
  • 12+弹框类型 (toast | footer | actionsheet | actionsheetPicker | android/ios | contextmenu | drawer | iframe | message | notify | popover)
  • 7+种弹窗动画 (scaleIn | fadeIn | footer | fadeInUp | fadeInDown | fadeInLeft | fadeInRight)

引入组件

在需要使用组件的页面引入rlayer组件。

// 引入弹框组件RLayerimport rlayer from './components/rlayer'

快速使用

引入后即可通过函数rlayer({…})来调用即可。

支持超过30+个参数自由搭配,快速实现定制化的各种效果。

// msg消息const showMsg = () => {    rlayer({        content: "这是一条msg消息提示",        shadeClose: false,        xclose: false,        time: 2    })}// confirm询问框const showConfirm = () => {    let $el = rlayer({        title: '询问标题',        content: "<div style='color:#0070f3;padding:30px;'>确认框(这里是确认框提示信息,这里确认框提示信息,这里是确认框提示信息)</div>",        shadeClose: false,        zIndex: 1001,        lockScroll: false,        resize: true,        dragOut: true,        btns: [            {                text: '取消',                click: () => {                    $el.close()                }            },            {                text: '确定',                style: {color: '#61dafb'},                click: () => {                    handleInfo()                }            }        ]    })}

js弹出框自定义(js实现弹出框的插件)(4)js弹出框自定义(js实现弹出框的插件)(5)js弹出框自定义(js实现弹出框的插件)(6)js弹出框自定义(js实现弹出框的插件)(7)js弹出框自定义(js实现弹出框的插件)(8)js弹出框自定义(js实现弹出框的插件)(9)

RLayer弹框模板

class RLayerComponent extends React.Component {    // ...    render() {        let opt = this.state        return (            <>            <div className={domUtils.classNames('rui__layer', {'rui__layer-closed': opt.closeCls})} id={opt.id} style={{display: opt.opened?'block':'none'}}>                {/* 遮罩 */}                { opt.shade && <div className="rlayer__overlay" onClick={this.shadeClicked} style={{opacity: opt.opacity}}></div> }                {/* 窗体 */}                <div className={domUtils.classNames('rlayer__wrap', opt.anim&&'anim-'+opt.anim, opt.type&&'popui__'+opt.type, opt.drawer&&'popui__drawer-'+opt.drawer, opt.xclose&&'rlayer-closable', opt.tipArrow)} style={{...opt.layerStyle}}>                { opt.title && <div className='rlayer__wrap-tit' dangerouslySetInnerHTML={{__html: opt.title}}></div> }                { opt.type == 'toast' && opt.icon ? <div className={domUtils.classNames('rlayer__toast-icon', 'rlayer__toast-'+opt.icon)} dangerouslySetInnerHTML={{__html: opt.toastIcon[opt.icon]}}></div> : null }                <div className='rlayer__wrap-cntbox'>                    { opt.content ?                     <>                        {                        opt.type == 'iframe' ?                         (                            <iframe scrolling='auto' allowtransparency='true' frameBorder='0' src={opt.content}></iframe>                        )                        :                         (opt.type == 'message' || opt.type == 'notify' || opt.type == 'popover') ?                         (                            <div className='rlayer__wrap-cnt'>                            { opt.icon && <i className={domUtils.classNames('rlayer-msg__icon', opt.icon)} dangerouslySetInnerHTML={{__html: opt.messageIcon[opt.icon]}}></i> }                            <div className='rlayer-msg__group'>                                { opt.title && <div className='rlayer-msg__title' dangerouslySetInnerHTML={{__html: opt.title}}></div> }                                { typeof opt.content == 'string' ?                                 <div className='rlayer-msg__content' dangerouslySetInnerHTML={{__html: opt.content}}></div>                                :                                <div className='rlayer-msg__content'>{opt.content}</div>                                }                            </div>                            </div>                        )                        :                         (                            typeof opt.content == 'string' ?                             (<div className='rlayer__wrap-cnt' dangerouslySetInnerHTML={{__html: opt.content}}></div>)                            :                            opt.content                        )                        }                    </>                    :                    null                    }                </div>                {/* btns */}                { opt.btns && <div className='rlayer__wrap-btns'>                    {                        opt.btns.map((btn, index) => {                            return <span className={domUtils.classNames('btn', {'btn-disabled': btn.disabled})} key={index} style={{...btn.style}} dangerouslySetInnerHTML={{__html: btn.text}} onClick={this.btnClicked.bind(this, index)}></span>                        })                    }                    </div>                }                { opt.xclose && <span className={domUtils.classNames('rlayer__xclose', !opt.maximize&&opt.xposition)} style={{color: opt.xcolor}} onClick={this.close}></span> }                { opt.maximize && <span className='rlayer__maximize' onClick={this.maximizeClicked}></span> }                { opt.resize && <span className='rlayer__resize'></span> }                </div>                {/* 修复拖拽卡顿 */}                <div className='rlayer__dragfix'></div>            </div>            </>        )    }}

默认参数配置

class RLayerComponent extends React.Component {    /**     * 弹出框默认配置     */    static defaultProps = {        // 参数        id: '',                       // {string} 控制弹层唯一标识,相同id共享一个实例        title: '',                    // {string} 标题        content: '',              // {string|element} 内容(支持字符串或组件)        type: '',                   // {string} 弹框类型        layerStyle: '',          // {object} 自定义弹框样式        icon: '',                  // {string} Toast图标(loading|success|fail)        shade: true,           // {bool} 是否显示遮罩层        shadeClose: true,    // {bool} 是否点击遮罩层关闭弹框        lockScroll: true,       // {bool} 是否弹框显示时将body滚动锁定        opacity: '',                // {number|string} 遮罩层透明度        xclose: true,             // {bool} 是否显示关闭图标        xposition: 'right',     // {string} 关闭图标位置(top|right|bottom|left)        xcolor: '#333',         // {string} 关闭图标颜色        anim: 'scaleIn',        // {string} 弹框动画        position: 'auto',      // {string|array} 弹框位置        drawer: '',               // {string} 抽屉弹框(top|right|bottom|left)        follow: null,            // {string|array} 跟随定位弹框        time: 0,                  // {number} 弹框自动关闭秒数(1|2|3...)        zIndex: 8090,        // {number} 弹框层叠        topmost: false,      // {bool} 是否置顶当前弹框        area: 'auto',           // {string|array} 弹框宽高        maxWidth: 375,    // {number} 弹框最大宽度(只有当area:'auto'时设定才有效)        maximize: false,     // {bool} 是否显示最大化按钮        fullscreen: false,      // {bool} 是否全屏弹框        fixed: true,                  // {bool} 是否固定弹框        drag: '.rlayer__wrap-tit',    // {string|bool} 拖拽元素        dragOut: false,               // {bool} 是否允许拖拽到浏览器外        lockAxis: null,         // {string} 限制拖拽方向可选: v 垂直、h 水平,默认不限制        resize: false,           // {bool} 是否允许拉伸弹框        btns: null,              // {array} 弹框按钮(参数:text|style|disabled|click)        // 事件        success: null,         // {func} 层弹出后回调        end: null,              // {func} 层销毁后回调    }		// ...}

/** * ReactJs|Next.js弹出框组件RLayer */import React from 'react'import ReactDOM from 'react-dom'// 引入操作类import domUtils from './utils/dom'let $index = 0, $lockCount = 0, $timer = {}class RLayerComponent extends React.Component {    constructor(props) {        super(props)        this.state = {            // ...        }        this.closeTimer = null    }    componentDidMount() {        window.addEventListener('resize', this.autopos, false)    }    componentWillUnmount() {        window.removeEventListener('resize', this.autopos, false)        clearTimeout(this.closeTimer)    }    /**     * 打开弹框     */    open = (options) => {        options.id = options.id || `rlayer-${domUtils.generateId()}`        this.setState({            ...this.props, ...options, opened: true,        }, () => {            const { success } = this.state            typeof success === 'function' && success.call(this)            this.auto()            this.callback()        })    }    /**     * 关闭弹框     */    close = () => {        const { opened, time, end, remove, rlayerOpts, action } = this.state        if(!opened) return        this.setState({ closeCls: true })        clearTimeout(this.closeTimer)        this.closeTimer = setTimeout(() => {            this.setState({                closeCls: false,                opened: false,            })            if(rlayerOpts.lockScroll) {                $lockCount--                if(!$lockCount) {                    document.body.style.paddingRight = ''                    document.body.classList.remove('rc-overflow-hidden')                }            }            if(time) {                $index--            }            if(action == 'update') {                document.body.style.paddingRight = ''                document.body.classList.remove('rc-overflow-hidden')            }            rlayerOpts.isBodyOverflow && (document.body.style.overflow = '')            remove()            typeof end === 'function' && end.call(this)        }, 200);    }    // 弹框位置    auto = () => {        // ...    }    autopos = () => {        const { opened, id, fixed, follow, position } = this.state        if(!opened) return        let oL, oT        let dom = document.querySelector('#' + id)        let rlayero = dom.querySelector('.rlayer__wrap')        if(!fixed || follow) {            rlayero.style.position = 'absolute'        }        let area = [domUtils.client('width'), domUtils.client('height'), rlayero.offsetWidth, rlayero.offsetHeight]        oL = (area[0] - area[2]) / 2        oT = (area[1] - area[3]) / 2        if(follow) {            this.offset()        } else {            typeof position === 'object' ? (                oL = parseFloat(position[0]) || 0, oT = parseFloat(position[1]) || 0            ) : (                position == 't' ? oT = 0 :                 position == 'r' ? oL = area[0] - area[2] :                 position == 'b' ? oT = area[1] - area[3] :                 position == 'l' ? oL = 0 :                 position == 'lt' ? (oL = 0, oT = 0) :                 position == 'rt' ? (oL = area[0] - area[2], oT = 0) :                 position == 'lb' ? (oL = 0, oT = area[1] - area[3]) :                position == 'rb' ? (oL = area[0] - area[2], oT = area[1] - area[3]) :                 null            )            rlayero.style.left = parseFloat(fixed ? oL : domUtils.scroll('left') + oL) + 'px'            rlayero.style.top = parseFloat(fixed ? oT : domUtils.scroll('top') + oT) + 'px'        }    }    // 跟随元素定位    offset = () => {        const { id, follow } = this.state        let oW, oH, pS        let dom = document.querySelector('#' + id)        let rlayero = dom.querySelector('.rlayer__wrap')        oW = rlayero.offsetWidth        oH = rlayero.offsetHeight        pS = domUtils.getFollowRect(follow, oW, oH)        this.setState({ tipArrow: pS[2] })        rlayero.style.left = pS[0] + 'px'        rlayero.style.top = pS[1] + 'px'    }    // 最大化弹框    full = () => {        // ...    }    // 恢复弹框    restore = () => {        const { id, maximize, rlayerOpts } = this.state        let dom = document.querySelector('#' + id)        let rlayero = dom.querySelector('.rlayer__wrap')        let otit = dom.querySelector('.rlayer__wrap-tit')        let ocnt = dom.querySelector('.rlayer__wrap-cntbox')        let obtn = dom.querySelector('.rlayer__wrap-btns')        let omax = dom.querySelector('.rlayer__maximize')        let t = otit ? otit.offsetHeight : 0        let b = obtn ? obtn.offsetHeight : 0        if(!rlayerOpts.lockScroll) {            rlayerOpts.isBodyOverflow = false            this.setState({rlayerOpts})            document.body.style.overflow = ''        }        maximize && omax.classList.remove('maximized')        rlayero.style.left = parseFloat(rlayerOpts.rect[0]) + 'px'        rlayero.style.top = parseFloat(rlayerOpts.rect[1]) + 'px'        rlayero.style.width = parseFloat(rlayerOpts.rect[2]) + 'px'        rlayero.style.height = parseFloat(rlayerOpts.rect[3]) + 'px'        ocnt.style.height = parseFloat(rlayerOpts.rect[3] - t - b) + 'px'    }    // 拖拽|缩放弹框    move = () => {        // ...    }    // 事件处理    callback = () => {        const { time } = this.state        // 倒计时关闭弹框        if(time) {            $index++            // 防止重复计数            if($timer[$index] != null) clearTimeout($timer[$index])            $timer[$index] = setTimeout(() => {                this.close()            }, parseInt(time) * 1000);        }    }    // 点击最大化按钮    maximizeClicked = (e) => {        let o = e.target        if(o.classList.contains('maximized')) {            // 恢复            this.restore()        } else {            // 最大化            this.full()        }    }    // 点击遮罩层    shadeClicked = () => {        if(this.state.shadeClose) {            this.close()        }    }    // 按钮事件    btnClicked = (index, e) => {        let btn = this.state.btns[index]        if(!btn.disabled) {            typeof btn.click === 'function' && btn.click(e)        }    }}

js弹出框自定义(js实现弹出框的插件)(10)js弹出框自定义(js实现弹出框的插件)(11)

好了,以上就是基于React.js实现PC端弹出框组件,希望对大家有所帮助哈!

免责声明:本文仅代表文章作者的个人观点,与本站无关。其原创性、真实性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容文字的真实性、完整性和原创性本站不作任何保证或承诺,请读者仅作参考,并自行核实相关内容。文章投诉邮箱:anhduc.ph@yahoo.com

    分享
    投诉
    首页