服务器之家:专注于服务器技术及软件下载分享
分类导航

node.js|vue.js|jquery|angularjs|React|json|js教程|

服务器之家 - 编程语言 - JavaScript - vue.js - 基于Vue3.0开发轻量级手机端弹框组件V3Popup的场景分析

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

2021-12-23 15:34xiaoyan2017 vue.js

这篇文章主要介绍了基于Vue3.0开发轻量级手机端弹框组件V3Popup,本文通过场景分析给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

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

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

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

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

◆ 快速引入

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

?
1
2
3
4
5
6
7
8
9
10
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同样支持标签式+函数式两种调用方式。

标签写法

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<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>

函数写法

?
1
2
3
4
5
6
7
8
9
10
11
12
13
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 方式挂载。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
// vue2.x中调用
methods: {
  showdialog() {
    this.$v3popup({...})
  }
}
 
// vue3.x中调用
setup() {
  // 获取上下文
  const { ctx } = getcurrentinstance()
  ctx.$v3popup({...})
}

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 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支持如下参数配置。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|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模板

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<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>
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/**
 * @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来实现函数式调用。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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自定义弹框组件内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://www.cnblogs.com/xiaoyan2017/p/14210820.html

延伸 · 阅读

精彩推荐
  • vue.js用vite搭建vue3应用的实现方法

    用vite搭建vue3应用的实现方法

    这篇文章主要介绍了用vite搭建vue3应用的实现方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下...

    Asiter7912022-01-22
  • vue.jsVue2.x-使用防抖以及节流的示例

    Vue2.x-使用防抖以及节流的示例

    这篇文章主要介绍了Vue2.x-使用防抖以及节流的示例,帮助大家更好的理解和学习使用vue框架,感兴趣的朋友可以了解下...

    Kyara6372022-01-25
  • vue.js梳理一下vue中的生命周期

    梳理一下vue中的生命周期

    看过很多人讲vue的生命周期,但总是被绕的云里雾里,尤其是自学的同学,可能js的基础也不是太牢固,听起来更是吃力,那我就已个人之浅见,以大白话...

    CRMEB技术团队7992021-12-22
  • vue.jsVue多选列表组件深入详解

    Vue多选列表组件深入详解

    这篇文章主要介绍了Vue多选列表组件深入详解,这个是vue的基本组件,有需要的同学可以研究下...

    yukiwu6752022-01-25
  • vue.js详解vue 表单绑定与组件

    详解vue 表单绑定与组件

    这篇文章主要介绍了vue 表单绑定与组件的相关资料,帮助大家更好的理解和学习使用vue框架,感兴趣的朋友可以了解下...

    Latteitcjz6432022-02-12
  • vue.jsVue项目中实现带参跳转功能

    Vue项目中实现带参跳转功能

    最近做了一个手机端系统,其中遇到了父页面需要携带参数跳转至子页面的问题,现已解决,下面分享一下实现过程,感兴趣的朋友一起看看吧...

    YiluRen丶4302022-03-03
  • vue.jsVue2.x 项目性能优化之代码优化的实现

    Vue2.x 项目性能优化之代码优化的实现

    这篇文章主要介绍了Vue2.x 项目性能优化之代码优化的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋...

    优小U9632022-02-21
  • vue.jsVue中引入svg图标的两种方式

    Vue中引入svg图标的两种方式

    这篇文章主要给大家介绍了关于Vue中引入svg图标的两种方式,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的...

    十里不故梦10222021-12-31