基于Vue3.0开发轻量级手机端弹框组件V3Popup的场景分析


Posted in Vue.js onDecember 30, 2020

之前有分享一个vue2.x移动端弹框组件,今天给大家带来的是Vue3实现自定义弹框组件。

V3Popup 基于vue3.x实现的移动端弹出框组件,集合msg、alert、dialog、modal、actionSheet、toast等多种效果。支持20+种自定义参数配置,旨在通过极简的布局、精简的调用方式解决多样化的弹框场景。

基于Vue3.0开发轻量级手机端弹框组件V3Popup的场景分析

v3popup 在开发之初参考借鉴了Vant3、ElementPlus等组件化思想。并且功能效果和之前vue2.0保持一致。

◆ 快速引入

在main.js中全局引入v3popup组件。

import { createApp } from 'vue'
import App from './App.vue'

const app = createApp(App)

// 引入弹窗组件v3popup
import V3Popup from './components/v3popup'

app.use(V3Popup)
app.mount('#app')

v3popup同样支持标签式+函数式两种调用方式。

标签写法

<v3-popup 
  v-model="showDialog"
  title="标题"
  content="<p style='color:#df6a16;padding:10px;'>这里是内容信息!</p>"
  type="android"
  shadeClose="false"
  xclose
  :btns="[
    {text: '取消', click: () => showDialog=false},
    {text: '确认', style: 'color:#f90;', click: handleOK},
  ]"
  @success="handleOpen"
  @end="handleClose"
/>
  <template #content>这里是自定义插槽内容信息!</template>
</v3-popup>

函数写法

let $el = this.$v3popup({
  title: '标题',
  content: '<p style='color:#df6a16;padding:10px;'>这里是内容信息!</p>',
  type: 'android',
  shadeClose: false,
  xclose: true,
  btns: [
    {text: '取消', click: () => { $el.close(); }},
    {text: '确认', style: 'color:#f90;', click: () => handleOK},
  ],
  onSuccess: () => {},
  onEnd: () => {}
})

Vue3.0中挂载全局函数有2种方式app.config.globalPropertiesapp.provide

通过 app.config.globalProperties.$v3popup = V3Popup 方式挂载。

// vue2.x中调用
methods: {
  showDialog() {
    this.$v3popup({...})
  }
}

// vue3.x中调用
setup() {
  // 获取上下文
  const { ctx } = getCurrentInstance()
  ctx.$v3popup({...})
}

通过 app.provide('v3popup', V3Popup) 方式挂载。

// vue2.x中调用
methods: {
  showDialog() {
    this.v3popup({...})
  }
}

// vue3.x中调用
setup() {
  const v3popup = inject('v3popup')
  
  const showDialog = () => {
    v3popup({...})
  }

  return {
    v3popup,
    showDialog
  }
}

不过vue.js作者是推荐使用 provide inject 方式来挂载原型链函数。

◆ 效果预览

基于Vue3.0开发轻量级手机端弹框组件V3Popup的场景分析

基于Vue3.0开发轻量级手机端弹框组件V3Popup的场景分析

基于Vue3.0开发轻量级手机端弹框组件V3Popup的场景分析

基于Vue3.0开发轻量级手机端弹框组件V3Popup的场景分析

基于Vue3.0开发轻量级手机端弹框组件V3Popup的场景分析

基于Vue3.0开发轻量级手机端弹框组件V3Popup的场景分析

基于Vue3.0开发轻量级手机端弹框组件V3Popup的场景分析

基于Vue3.0开发轻量级手机端弹框组件V3Popup的场景分析

◆ 参数配置

v3popup支持如下参数配置。

|props参数|
v-model     是否显示弹框
title      标题
content     内容(支持String、带标签内容、自定义插槽内容)***如果content内容比较复杂,推荐使用标签式写法
type      弹窗类型(toast | footer | actionsheet | actionsheetPicker | android | ios)
popupStyle   自定义弹窗样式
icon      toast图标(loading | success | fail)
shade      是否显示遮罩层
shadeClose   是否点击遮罩时关闭弹窗
opacity     遮罩层透明度
round      是否显示圆角
xclose     是否显示关闭图标
xposition    关闭图标位置(left | right | top | bottom)
xcolor     关闭图标颜色
anim      弹窗动画(scaleIn | fadeIn | footer | fadeInUp | fadeInDown)
position    弹出位置(top | right | bottom | left)
follow     长按/右键弹窗(坐标点)
time      弹窗自动关闭秒数(1、2、3)
zIndex     弹窗层叠(默认8080)
teleport    指定挂载节点(默认是挂载组件标签位置,可通过teleport自定义挂载位置) teleport="body | #xxx | .xxx"
btns      弹窗按钮(参数:text|style|disabled|click)
++++++++++++++++++++++++++++++++++++++++++++++
|emit事件触发|
success     层弹出后回调(@success="xxx")
end       层销毁后回调(@end="xxx")
++++++++++++++++++++++++++++++++++++++++++++++
|event事件|
onSuccess    层打开回调事件
onEnd      层关闭回调事件

v3popup.vue模板

<template>
  <div ref="elRef" v-show="opened" class="vui__popup" :class="{'vui__popup-closed': closeCls}" :id="id">
    <!-- //蒙层 -->
    <div v-if="JSON.parse(shade)" class="vui__overlay" @click="shadeClicked" :style="{opacity}"></div>
    <div class="vui__wrap">
      <div class="vui__wrap-section">
        <div class="vui__wrap-child" :class="['anim-'+anim, type&&'popupui__'+type, round&&'round', position]" :style="[popupStyle]">
          <div v-if="title" class="vui__wrap-tit" v-html="title"></div>
          <div v-if="type=='toast'&&icon" class="vui__toast-icon" :class="['vui__toast-'+icon]" v-html="toastIcon[icon]"></div>
          <!-- 判断插槽是否存在 -->
          <template v-if="$slots.content">
            <div class="vui__wrap-cnt"><slot name="content" /></div>
          </template>
          <template v-else>
            <div v-if="content" class="vui__wrap-cnt" v-html="content"></div>
          </template>
          <slot />
          <div v-if="btns" class="vui__wrap-btns">
            <span v-for="(btn, index) in btns" :key="index" class="btn" :style="btn.style" @click="btnClicked($event, index)" v-html="btn.text"></span>
          </div>
          <span v-if="xclose" class="vui__xclose" :class="xposition" :style="{'color': xcolor}" @click="close"></span>
        </div>
      </div>
    </div>
  </div>
</template>
/**
 * @Desc   Vue3.0自定义弹框组件V3Popup
 * @Time   andy by 2020-12
 * @About  Q:282310962 wx:xy190310
 */
<script>
  import { onMounted, ref, reactive, watch, toRefs, nextTick } from 'vue'
  let $index = 0, $locknum = 0, $timer = {}
  export default {
    props: {
      // 接收父组件v-model值,如果v-model:open,则这里需写open: {...}
      modelValue: { type: Boolean, default: false },
      // 标识符,相同ID共享一个实例
      id: {
        type: String, default: ''
      },
      title: String,
      content: String,
      type: String,
      popupStyle: String,
      icon: String,
      shade: { type: [Boolean, String], default: true },
      shadeClose: { type: [Boolean, String], default: true },
      opacity: { type: [Number, String], default: '' },
      round: Boolean,
      xclose: Boolean,
      xposition: { type: String, default: 'right' },
      xcolor: { type: String, default: '#333' },
      anim: { type: String, default: 'scaleIn' },
      position: String,
      follow: { type: Array, default: null },
      time: { type: [Number, String], default: 0 },
      zIndex: { type: [Number, String], default: '8080' },
      teleport: [String, Object],
      btns: {
        type: Array, default: null
      },
      onSuccess: { type: Function, default: null },
      onEnd: { type: Function, default: null },
    },
    emits: [
      'update:modelValue'
    ],
    setup(props, context) {
      const elRef = ref(null)

      const data = reactive({
        opened: false,
        closeCls: '',
        toastIcon: {
          ...
        }
      })

      onMounted(() => {
        ...
      })

      // 监听弹层v-model
      watch(() => props.modelValue, (val) => {
        if(val) {
          open()
        }else {
          close()
        }
      })

      // 打开弹层
      const open = () => {
        if(data.opened) return
        data.opened = true
        typeof props.onSuccess === 'function' && props.onSuccess()

        const dom = elRef.value
        dom.style.zIndex = getZIndex() + 1

        ...

        // 倒计时
        if(props.time) {
          $index++
          // 避免重复操作
          if($timer[$index] !== null) clearTimeout($timer[$index])
          $timer[$index] = setTimeout(() => {
            close()
          }, parseInt(props.time) * 1000)
        }

        // 长按|右键菜单
        if(props.follow) {
          ...
        }
      }

      // 关闭弹层
      const close = () => {
        if(!data.opened) return

        data.closeCls = true
        setTimeout(() => {
          ...

          context.emit('update:modelValue', false)
          typeof props.onEnd === 'function' && props.onEnd()
        }, 200)
      }

      // 点击遮罩层
      const shadeClicked = () => {
        if(JSON.parse(props.shadeClose)) {
          close()
        }
      }
      // 按钮事件
      const btnClicked = (e, index) => {
        let btn = props.btns[index];
        if(!btn.disabled) {
          typeof btn.click === 'function' && btn.click(e)
        }
      }
      
      ...

      return {
        ...toRefs(data),
        elRef,
        close,
        shadeClicked,
        btnClicked,
      }
    }
  }
</script>

Vue3中可通过createApp或createVNode | render 来挂载实例到body来实现函数式调用。

import { createApp } from 'vue'
import PopupConstructor from './popup.vue'

let $inst
// 创建挂载实例
let createMount = (opts) => {
  const mountNode = document.createElement('div')
  document.body.appendChild(mountNode)

  const app = createApp(PopupConstructor, {
    ...opts, modelValue: true,
    remove() {
      app.unmount(mountNode)
      document.body.removeChild(mountNode)
    }
  })
  return app.mount(mountNode)
}

function V3Popup(options = {}) {
  options.id = options.id || 'v3popup_' + generateId()
  $inst = createMount(options)
  
  return $inst
}

V3Popup.install = app => {
  app.component('v3-popup', PopupConstructor)
  // app.config.globalProperties.$v3popup = V3Popup
  app.provide('v3popup', V3Popup)
}

这样就实现了在vue3中注册原型链函数和v3-popup组件,就可以使用函数式调用了。

基于Vue3.0开发轻量级手机端弹框组件V3Popup的场景分析

到此这篇关于基于Vue3.0开发轻量级手机端弹框组件V3Popup的场景分析的文章就介绍到这了,更多相关Vue3自定义弹框组件内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Vue.js 相关文章推荐
一篇超完整的Vue新手入门指导教程
Nov 18 Vue.js
vue祖孙组件之间的数据传递案例
Dec 07 Vue.js
Vue使用鼠标在Canvas上绘制矩形
Dec 24 Vue.js
Vue 集成 PDF.js 实现 PDF 预览和添加水印的步骤
Jan 22 Vue.js
用vite搭建vue3应用的实现方法
Feb 22 Vue.js
手写Vue2.0 数据劫持的示例
Mar 04 Vue.js
vue中data改变后让视图同步更新的方法
Mar 29 Vue.js
Vue中foreach数组与js中遍历数组的写法说明
Jun 05 Vue.js
一定要知道的 25 个 Vue 技巧
Nov 02 Vue.js
详解Vue slot插槽
Nov 20 Vue.js
Vue h函数的使用详解
Feb 18 Vue.js
关于vue-router-link选择样式设置
Apr 30 Vue.js
SpringBoot+Vue 前后端合并部署的配置方法
Dec 30 #Vue.js
vue中实现点击空白区域关闭弹窗的两种方法
Dec 30 #Vue.js
梳理一下vue中的生命周期
Dec 30 #Vue.js
Vue实现简易购物车页面
Dec 30 #Vue.js
利用Vue实现简易播放器的完整代码
Dec 30 #Vue.js
vue+element UI实现树形表格
Dec 29 #Vue.js
vue实现树状表格效果
Dec 29 #Vue.js
You might like
简单的php数据库操作类代码(增,删,改,查)
2013/04/08 PHP
PHP中is_file()函数使用指南
2015/05/08 PHP
php自动加载方式集合
2016/04/04 PHP
PHP Yaf框架的简单安装使用教程(推荐)
2016/06/08 PHP
Thinkphp开发--集成极光推送
2017/09/15 PHP
php生成复杂验证码(倾斜,正弦干扰线,黏贴,旋转)
2018/03/12 PHP
初学Jquery插件制作 在SageCRM的查询屏幕隐藏部分行的功能
2011/12/26 Javascript
js实时获取系统当前时间实例代码
2013/06/28 Javascript
多种方式实现JS调用后台方法进行数据交互
2013/08/20 Javascript
JQuery页面图片切换和新闻列表滚动效果的具体实现
2013/09/26 Javascript
用Jquery.load载入页面实现局部刷新
2014/01/22 Javascript
jquery中map函数与each函数的区别实例介绍
2014/06/23 Javascript
在Linux上用forever实现Node.js项目自启动
2014/07/09 Javascript
flash+jQuery实现可关闭及重复播放的压顶广告
2015/04/15 Javascript
jQuery实现浮动层随浏览器滚动条滚动的方法
2015/09/22 Javascript
JavaScript利用HTML DOM进行文档操作的方法
2016/03/28 Javascript
jQuery表格插件datatables用法汇总
2016/03/29 Javascript
jQuery如何跳转到另一个网页 就这么简单
2016/12/28 Javascript
理解Angular的providers给Http添加默认headers
2017/07/04 Javascript
vue项目实现github在线预览功能
2018/06/20 Javascript
javascript定时器的简单应用示例【控制方块移动】
2019/06/17 Javascript
vue微信分享插件使用方法详解
2020/02/18 Javascript
Python图形绘制操作之正弦曲线实现方法分析
2017/12/25 Python
python+pyqt5编写md5生成器
2019/03/18 Python
关于Python作用域自学总结
2019/06/10 Python
详解将Pandas中的DataFrame类型转换成Numpy中array类型的三种方法
2019/07/06 Python
Python 调用 Outlook 发送邮件过程解析
2019/08/08 Python
Python字符编码转码之GBK,UTF8互转
2020/02/09 Python
3种适用于Python的疯狂秘密武器及原因解析
2020/04/29 Python
荷兰优雅女装网上商店:Heine
2016/11/14 全球购物
班子个人四风问题整改措施
2014/10/04 职场文书
代领报检证委托书范本
2014/10/11 职场文书
结婚保证书(卖身契)
2015/02/26 职场文书
初中毕业生自我评价
2015/03/02 职场文书
2015年度优秀员工推荐信
2015/03/23 职场文书
大学运动会加油稿
2015/07/22 职场文书