栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > Web开发 > Vue.js

React.js仿layer弹窗|react自定义全局对话框RLayer

Vue.js 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

React.js仿layer弹窗|react自定义全局对话框RLayer

介绍

rlayer 一款基于react.js构建的pc网页端全局弹窗组件。支持顺滑拖拽、缩放、全屏及最大化效果。拥有精美UI及极简API调用。

内置30+参数配置、10+弹框类型、7+动画效果
支持 alert、Dialog、Message、Notification、ActionSheet、Toast、Popover 等多样化弹窗类型。

RLayer设计开发灵感来自之前的VLayer自定义弹框组件。

引入组件

在需要用到弹窗功能的页面引入即可。

// 引入RLayer
import rlayer from './components/rlayer';

通过rlayer({})即可快速调用一个弹窗实例。

showConfirm = () => {
    let $rlayer = rlayer({
 title: '标题信息',
 content: "显示弹窗内容。",
 shadeClose: true,
 zIndex: 1000,
 lockScroll: true,
 resize: true,
 dragOut: false,
 btns: [
     {
  text: '取消',
  click: () => {
      $rlayer.close()
  }
     },
     {
  text: '确定',
  style: {color: '#005eff'},
  click: () => {
      // ...
  }
     }
 ]
    })
}

参数配置

rlayer.js支持30+参数自定义配置。任意搭配实现需要的效果。

static defaultProps = {
    // 参数
    id: '',  // {string} 控制弹层唯一标识,相同id共享一个实例
    title: '',      // {string} 标题
    content: '',    // {string|element} 内容(支持字符串或组件)
    type: '',// {string} 弹框类型(toast|footer|actionsheet|actionsheetPicker|android|ios|contextmenu|drawer|iframe)
    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} 弹框动画(scaleIn|fadeIn|footer|fadeInUp|fadeInDown|fadeInLeft|fadeInRight)
    position: 'auto',      // {string|array} 弹框位置(auto|['150px','100px']|t|r|b|l|lt|rt|lb|rb)
    drawer: '',     // {string} 抽屉弹框(top|right|bottom|left)
    follow: null,   // {string|array} 跟随定位弹框(支持.xxx #xxx 或 [e.clientX,e.clientY])
    time: 0, // {number} 弹框自动关闭秒数(1|2|3...)
    zIndex: 8090,   // {number} 弹框层叠
    topmost: false, // {bool} 是否置顶当前弹框
    area: 'auto',   // {string|array} 弹框宽高(auto|'250px'|['','200px']|['650px','300px'])
    maxWidth: 375,  // {number} 弹框最大宽度(只有当area:'auto'时设定才有效)
    maximize: false,// {bool} 是否显示最大化按钮
    fullscreen: false,     // {bool} 是否全屏弹框
    fixed: true,    // {bool} 是否固定弹框
    drag: '.rlayer__wrap-tit',    // {string|bool} 拖拽元素(可自定义拖动元素drag:'#xxx' 禁止拖拽drag:false)
    dragOut: false, // {bool} 是否允许拖拽到浏览器外
    lockAxis: null, // {string} 限制拖拽方向可选: v 垂直、h 水平,默认不限制
    resize: false,  // {bool} 是否允许拉伸弹框
    btns: null,     // {array} 弹框按钮(参数:text|style|disabled|click)
 
    // 事件
    success: null,  // {func} 层弹出后回调
    end: null,      // {func} 层销毁后回调
}

rlayer.js编码实现

render() {
    let opt = this.state
 
    return (
 <>
 
     {}
     { opt.shade &&  }
     
     { opt.title &&  }
     
  { opt.content ? 
  <>
      {
      opt.type == 'iframe' ? 
      (
   
      )
      : 
      (opt.type == 'message' || opt.type == 'notify' || opt.type == 'popover') ? 
      (
   
   { opt.icon &&  }
   
{ opt.title &&  }
{ typeof opt.content == 'string' ? 

:
{opt.content}
}
   
   
      )
      : 
      (
   typeof opt.content == 'string' ? 
   ()
   :
   opt.content
      )
      }
  
  :
  null
  }
     
     { opt.btns && 
  {
      opt.btns.map((btn, index) => {
   return 
      })
  }
  
     }
     { opt.xclose &&  }
     { opt.maximize &&  }
     { opt.resize &&  }
     
     
 
 
    )
}


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 {
    static defaultProps = {
 // ...
    }
 
    constructor(props) {
 super(props)
 this.state = {
     opened: false,
     closeCls: '',
     toastIcon: {
  // ...
     },
     messageIcon: {
  // ...
     },
     rlayerOpts: {},
     tipArrow: null,
 }
 
 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 = () => {
 // ...
 
 this.autopos()
 
 // 全屏弹框
 if(fullscreen) {
     this.full()
 }
 
 // 弹框拖拽|缩放
 this.move()
    }
 
    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)
 
 rlayero.style.left = pS[0] + 'px'
 rlayero.style.top = pS[1] + 'px'
    }
 
    // 最大化弹框
    full = () => {
 // ...
    }
 
    // 恢复弹框
    restore = () => {
 // ...
    }
 
    // 拖拽|缩放弹框
    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)
 }
    }
 
    render() {
 let opt = this.state
 return (
     <>
     
  { opt.shade &&  }
  
  { opt.title &&  }
  { opt.type == 'toast' && opt.icon ?  : null }
  
      { opt.content ? 
      <>
   {
   opt.type == 'iframe' ? 
   (

   )
   : 
   (opt.type == 'message' || opt.type == 'notify' || opt.type == 'popover') ? 
   (

{ opt.icon &&  }

    { opt.title &&  }
    { typeof opt.content == 'string' ? 
    
    :
    {opt.content}
    }


   )
   : 
   (
typeof opt.content == 'string' ? 
()
:
opt.content
   )
   }
      
      :
      null
      }
  
  {}
  { opt.btns && 
      {
   opt.btns.map((btn, index) => {
return 
   })
      }
      
  }
  { opt.xclose &&  }
  { opt.maximize &&  }
  { opt.resize &&  }
  
  
     
     
 )
    }
}

rlayer组件支持自定义拖拽位置 drag:'#aaa',是否可以拖动到窗口外 dragOut:true。
另外还支持iframe弹框,只需设置 type:'iframe',content传入网址就行。
配置 fullscreen:true 即可显示全屏弹窗。

ok,基于react.js开发全局自定义弹窗就分享到这里。希望大家能喜欢。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/240102.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号