概述
如上图:在功能效果及UI上基本保持和之前vue2.x的完美一致。
引入组件
在main.js中全局引入使用。
import { createApp } from 'vue'
import App from './App.vue'
// 引入弹窗组件v3popup
import V3Popup from './components/v3popup'
createApp(App).use(V3Popup).mount('#app')
同样的支持组件式和函数式两种灵活调用方式。
组件式
<!-- 提示框 -->
<v3-popup v-model="showMsg" anim="fadeIn" content="msg提示框测试(3s后窗口关闭)" shadeClose="false" time="3" />
<!-- 询问框 -->
<v3-popup v-model="showConfirm" shadeClose="false" xclose z-index="2020"
content="<div style='color:#1be769;padding:20px;'>确认框(这里是确认框提示信息,这里确认框提示信息,这里是确认框提示信息)</div>"
:btns="[
{text: '取消', click: () => showConfirm=false},
{text: '确定', style: 'color:#f90;', click: handleInfo},
]"
/>
函数式
let $el = this.$v3popup({
title: '标题',
content: '<div style='color:#f90;padding:10px;'>这里是内容信息!</div>',
type: 'android',
shadeClose: false,
xclose: true,
btns: [
{text: '取消', click: () => { $el.close(); }},
{text: '确认', style: 'color:#f90;', click: () => handleOK},
],
onSuccess: () => {},
onEnd: () => {}
})
大家都知道在vue2.x中可以通过prototype原型链挂载全局方法,那么在vue3中如何挂载全局方法呢?
其实vue3提供了两种可供全局调用的方法。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
}
}
不过尤大大更是推荐使用 provide inject
这种方式。大家可以根据项目情况,自行选择合适的方式即可。
参数配置
v3popup提供了**20+**种参数任意搭配组合。
|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 层关闭回调事件
以上自定义参数足以应对各种弹窗应用场景。
<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实现弹窗的模板及核心逻辑处理部分。
vue2.x中可以通过Vue.extend
扩展实例方法来实现函数调用。
// vue2.x实现函数调用
import Vue from 'vue';
import VuePopup from './popup.vue';
let PopupConstructor = Vue.extend(VuePopup);
let $instance;
$instance = new PopupConstructor({
propsData: options
});
...
那么在vue3.0中则是需要通过createApp
或createVNode render
来实现
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.0开发自定义弹出框组件就介绍到这里。最近正在筹备vue3实例项目,届时也会分享出来。希望以上分享对大家有些帮助!
Flutter+Dart仿微信App聊天实例
❤️ 结语
如果你觉得这篇内容对你有启发或帮助,那么可以帮我三个小忙:
- 转发/点赞,让更多的人也能看到这篇分享。
- 加关注、不迷路,不定期分享原创技术知识。
- 也看看其它历史文章。
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!