基于Vue3.0开发的轻量级手机端弹框组件V3Popup。

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

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

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.globalProperties  app.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 方式来挂载原型链函数。

◆ 效果预览

◆ 参数配置

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开发自定义弹框组件就分享到这里。希望对大家有些帮助哈!

最后附上一个Next.js实例项目

Next+React.js桌面端聊天:https://www.cnblogs.com/xiaoyan2017/p/14195483.html

vue3系列:vue3.0自定义弹框组件V3Popup|vue3.x手机端弹框组件的更多相关文章

  1. DT6.0二次最后一次开发插件-手机端熊掌号定时提交

    今天写完这个,就是DT6.0最后开放的插件,因为群里的朋友需要,就写了一个适合DT6的手机端定时插件.不过个人还是喜欢7.0的版本,7.0的插件在上几期分享了,今天就不过多说了! 我这个是初成品,改善 ...

  2. 整理:手机端弹出提示框,使用的bootstrap中的模态框(modal,弹出层),比kendo弹出效果好

    效果图: 我的代码示例: <!--提示模态框--> <div class="modal fade" id="myModal" tabindex ...

  3. ios 手机端 input 框上方有内阴影

    解决方案 方法1: <!--如果 ui 样式里有边框,可以用外层盒子设置边框--> input{ border:none; } 方法2: //在IOS下,input 和textarea表单 ...

  4. 手机端用swiper组件 轮播图设置后右侧出现空白 及 部分手机浏览器打开网页空白

    我的方法是设置内容css overflow:hidden;width:100%; ok. 之前搜到一个方法也可以,就是设置css height: auto;overflow-y: scroll; 但是 ...

  5. vue3系列:vue3.0自定义虚拟滚动条V3Scroll|vue3模拟滚动条组件

    基于Vue3.0构建PC桌面端自定义美化滚动条组件V3Scroll. 前段时间有分享一个Vue3 PC网页端弹窗组件,今天带来最新开发的Vue3.0版虚拟滚动条组件. V3Scroll 使用vue3. ...

  6. vue3系列:vue3.0自定义全局弹层V3Layer|vue3.x pc桌面端弹窗组件

    基于Vue3.0开发PC桌面端自定义对话框组件V3Layer. 前两天有分享一个vue3.0移动端弹出层组件,今天分享的是最新开发的vue3.0版pc端弹窗组件. V3Layer 一款使用vue3.0 ...

  7. vue.js2.0 自定义组件初体验

    理解 组件(Component)是 Vue.js 最强大的功能之一.组件可以扩展 HTML 元素,封装可重用的代码.在较高层面上,组件是自定义元素, Vue.js 的编译器为它添加特殊功能.在有些情况 ...

  8. React Native实战系列教程之自定义原生UI组件和VideoView视频播放器开发

    React Native实战系列教程之自定义原生UI组件和VideoView视频播放器开发   2016/09/23 |  React Native技术文章 |  Sky丶清|  4 条评论 |  1 ...

  9. vue2.0 自定义 折叠列表(Accordion)组件

    1.自定义  折叠列表 Accordion.vue (1)sass  版本 <!-- 折叠列表 组件 --> <template> <nav :class="$ ...

随机推荐

  1. 在EXCEL带有字母的数字下拉如何能自动排序

    在excel中0,1,2,3,4,5,6,7,8,9会自动排序,a,b,c,d,e,f,g.....会自动排序,所以可以分布来实现. 例如排序:fish1a.png,fish1b.png,fish1c ...

  2. linux下定时任务的简单示例

    1.方式一:用sleep实现定时任务: 1.1 编辑shell脚本,如下sleep_aa.sh: #!/bin/bash t1=`date "+%Y-%m-%d %H:%M:%S" ...

  3. C和指针---结构和联合

    一.结构 1.C提供了两种类型的聚合数据类型---数组.结构.数组是相同类型的元素集合,它的每个元素长度相同,故可以通过下标引用或指针间接访问来选择的;而结构可以把不同类型的值存储在一起,由于结构的成 ...

  4. 区块链知识博文1: 共识算法之争(PBFT,Raft,PoW,PoS,DPoS,Ripple)

    注:这是本人读到的关于共识算法最全和最好的分享博文,系统的介绍了拜占庭容错技术以及共识算法的原理和常用共识算法,原文链接请见后. 目录 一.拜占庭容错技术(Byzantine Fault Tolera ...

  5. 第2.2节 Python的语句

    上节已经介绍了极简的Python代码编写,已经用到了赋值语句,本节对Python的程序语句进行介绍. 一. 常用命令 在介绍Python语句之前,先介绍一下几个有用的Python命令. dir(模块名 ...

  6. PyQt(Python+Qt)学习随笔:Designer中PushButton按钮default、atuoDefault属性

    引言 1.default.atuoDefault属性仅在父窗口为对话窗才生效,其他窗口类型设置这两个属性没有意义: 2.按钮的按压触发除了鼠标键之外,也可以使用回车键和空格键触发,这两个属性正是控制回 ...

  7. upload 注意php远程安全模式屏蔽函数

    进来:上传一个一句话php,果然不行:改成jpg后缀,上传成功:接着写一个.htaccess文件去把.jpg解析成.php,如下: AddType application/x-httpd-php .j ...

  8. (8)ASP.NET Core3.1 Ocelot Consul服务注册与发现

    1.服务注册与发现(Service Discovery) ●服务注册:我们通过在每个服务实例写入注册代码,实例在启动的时候会先去注册中心(例如Consul.ZooKeeper.etcd.Eureka) ...

  9. 转:解释lsh

    Locality sensitive hashing - LSH explained The problem of finding duplicate documents in a list may ...

  10. AcWing 328. 芯片 (二进制写法)

    题目链接 我自闭了,调了一下午,我居然认为 \(2, 3\) 凑不出 \(7\),我怕是个孤儿. 这是一位非要用二进制写的勇士. 首先定义状态 \(S\),若 \(S\) 的二进制第 \(k\) 位为 ...