基于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+iview分页组件的封装
Nov 17 Vue.js
解决vue页面刷新,数据丢失的问题
Nov 24 Vue.js
Vue Elenent实现表格相同数据列合并
Nov 30 Vue.js
vue3+typeScript穿梭框的实现示例
Dec 29 Vue.js
利用Vue实现简易播放器的完整代码
Dec 30 Vue.js
如何在VUE中使用vue-awesome-swiper
Jan 04 Vue.js
vue+echarts实现中国地图流动效果(步骤详解)
Jan 27 Vue.js
Vue-router编程式导航的两种实现代码
Mar 04 Vue.js
vite+vue3.0+ts+element-plus快速搭建项目的实现
Jun 24 Vue.js
Vue3.0中Ref与Reactive的区别示例详析
Jul 07 Vue.js
vue二维数组循环嵌套方式 循环数组、循环嵌套数组
Apr 24 Vue.js
vue实现input输入模糊查询的三种方式
Aug 14 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中使用Oracle数据库(4)
2006/10/09 PHP
php的sprintf函数的用法 控制浮点数格式
2014/02/14 PHP
Laravel框架实现的上传图片到七牛功能详解
2019/09/06 PHP
js AspxButton的客户端操作
2009/06/26 Javascript
Javascript调用C#代码
2011/01/17 Javascript
JS 进度条效果实现代码整理
2011/05/21 Javascript
js 页面关闭前的出现提示的实现代码
2011/05/25 Javascript
JavaScript实现页面实时显示当前时间的简单实例
2013/07/20 Javascript
原生的html元素选择器类似jquery选择器
2014/10/15 Javascript
jQuery实现按钮只点击一次后就取消点击事件绑定的方法
2015/06/26 Javascript
JavaScript判断数字是否为质数的方法汇总
2016/06/02 Javascript
vue组件发布到npm简单步骤
2017/11/30 Javascript
Node.js Express安装与使用教程
2018/05/11 Javascript
JavaScript使用prototype原型实现的封装继承多态示例
2018/08/31 Javascript
详解node和ES6的模块导出与导入
2020/02/19 Javascript
Bootstrap简单实用的表单验证插件BootstrapValidator用法实例详解
2020/03/29 Javascript
[02:47]2018年度DOTA2最佳辅助位选手4号位-完美盛典
2018/12/17 DOTA
Python中设置变量作为默认值时容易遇到的错误
2015/04/03 Python
python验证码图片处理(二值化)
2019/11/01 Python
python做接口测试的必要性
2019/11/20 Python
使用 Python 清理收藏夹里已失效的网站
2019/12/03 Python
python plotly画柱状图代码实例
2019/12/13 Python
Python如何实现的二分查找算法
2020/05/27 Python
Django模型验证器介绍与源码分析
2020/09/08 Python
英国著名国际平价时尚男装品牌:Topman
2016/08/27 全球购物
亚马逊印度站:Amazon.in
2017/10/15 全球购物
意大利奢侈品购物网站:Giglio
2018/01/05 全球购物
信息技术专业个人自我评价
2013/12/11 职场文书
消防安全管理制度
2014/02/01 职场文书
校园文化建设方案
2014/02/03 职场文书
机械制造专业毕业生求职信
2014/03/02 职场文书
结对共建工作方案
2014/06/02 职场文书
公司收款委托书范本
2014/09/20 职场文书
优秀团员事迹材料
2014/12/25 职场文书
师德师风个人总结
2015/02/06 职场文书
2019奶茶店创业计划书范本!
2019/07/15 职场文书