vue3中将一个简单的弹窗提示组件转变为函数调用
简单的弹窗组件
<template>
<transition name="fadeInUp">
<div class="modal-alert"
id="modal-alert"
v-show="showModal"
>
<div class="modal-alert-inner">
<span class="modal-icon"></span>
<p class="modal-p">{{ textTips }}</p>
<div class="modal-btns-box">
<button type="button"
class="modal-btn"
@click="clickBtn"
>
{{ textButton }}
</button>
<div class="modal-close" @click="close"></div>
</div>
</div>
</div>
</transition>
</template>
<script type="text/ecmascript-6">
import { hasParentWithClassInArray } from "@/common/js/fns";
export default {
name: "modal-alert",
emits: ['clickBtn', 'close'],
props: {
textTips: {
type: String,
default() {
return '无';
}
},
textButton: {
type: String,
default() {
return '无';
}
}
},
mounted() {
this.showModal = true;
this.clickOtherCloseModal();
},
data() {
return {
showModal: false
}
},
methods: {
clickBtn() {
this.$emit('clickBtn');
this.close();
},
open() {
this.showModal = true;
},
close() {
this.showModal = false;
// 关闭之后就卸载点击事件
document.body.removeEventListener('click', this.handleModal);
this.$emit('close');
},
handleModal(event) {
const classes = ['talking-roles-select-list', 'history-list-wrapper', 'm-header-menu-btn'];
const clickedElement = event.target;
const parentInArr = hasParentWithClassInArray(clickedElement, classes);
if (parentInArr) {
this.close();
}
},
// 点击其他地方关闭此弹窗
clickOtherCloseModal() {
document.body.addEventListener('click', this.handleModal);
},
},
}
</script>
<style lang="less" rel="stylesheet/less" scoped>
@import "@/common/less/variable";
/* 响应式PC */
@media screen and (min-width: 641px) {
.modal-alert {
position: fixed;
z-index: @zindex-VI;
width: calc((100% - @aside-left-width) * 0.6);
left: @aside-left-width;
right: 0;
bottom: 190px;
margin: 0 auto;
background-color: #fff;
box-shadow: 0 0px 8px @color-bg-l;
border-radius: 50px;
.modal-alert-inner {
padding: 15px 20px;
display: flex;
align-items: center;
justify-content: space-between;
}
.modal-p {
display: inline-block;
padding-left: 15px;
flex: 1;
line-height: 20px;
padding-right: 10px;
}
.modal-icon {
display: inline-block;
width: 24px;
height: 24px;
background: url("icon-tips.svg") center center no-repeat;
background-size: auto 100%;
}
.modal-close {
width: 24px;
height: 24px;
background: url("icon-close.svg") center center no-repeat;
background-size: auto 80%;
cursor: pointer;
}
.modal-btns-box {
flex: 0 0 150px;
display: flex;
align-items: center;
justify-content: space-between;
}
.modal-btn {
background: #fed547;
height: 36px;
padding: 0 20px;
border-radius: 5px;
cursor: pointer;
&:hover {
background: #e4bf3e;
}
}
}
}
/* 响应式PC end */
/* 响应式 M */
@media screen and (max-width: 640px) {
.modal-alert {
position: fixed;
z-index: @zindex-VI;
width: calc(100% - 40px);
left: 0;
right: 0;
bottom: 120px;
margin: 0 auto;
background-color: #fff;
box-shadow: 0 0px 8px darken(@color-bg-l, 10%);
border-radius: 10px;
.modal-alert-inner {
padding: 15px 20px;
}
.modal-p {
display: inline-block;
padding: 0 32px 0 32px;
line-height: 20px;
background: url("icon-tips.svg") left center no-repeat;
background-size: auto 24px;
}
.modal-icon {
display: inline-block;
width: 24px;
height: 24px;
background: url("icon-tips.svg") center center no-repeat;
background-size: auto 100%;
display: none;
}
.modal-close {
width: 24px;
height: 24px;
background: url("icon-close.svg") center center no-repeat;
background-size: auto 80%;
cursor: pointer;
position: absolute;
top: 13px;
right: 10px;
}
.modal-btns-box {
display: flex;
align-items: center;
justify-content: center;
padding-top: 15px;
}
.modal-btn {
background: #fed547;
height: 40px;
width: 70%;
border-radius: 5px;
cursor: pointer;
&:hover {
background: #e4bf3e;
}
}
}
}
/* 响应式 M end */
</style>
注意,关闭状态一定要在创建一次之后,在组件内部进行维护!
将组件封装成函数
import { createApp, h } from 'vue';
import ModalAlert from '@/components/modal-alert/modal-alert';
export function useModalAlert() {
return function (options = {}) {
const { textTips, textButton, onClickBtn, onClose } = options;
const modalWrapperID = 'modal-alert-wrapper';
// 动画执行时间
const animateDuration = 300;
// 如果存在外层元素 那么就组织继续创建
if (document.getElementById(modalWrapperID)) {
return;
}
// 创建一个 div 作为组件的挂载点
const div = document.createElement('div');
div.id = modalWrapperID;
document.body.appendChild(div);
const app = createApp({
render() {
return h(ModalAlert, {
textTips,
textButton,
onClickBtn: () => {
onClickBtn && onClickBtn();
setTimeout(() => {
app.unmount(div);
// document.body.removeChild(div);
}, animateDuration);
},
onClose: () => {
onClose && onClose();
setTimeout(() => {
app.unmount(div);
document.body.removeChild(div);
}, animateDuration);
}
});
}
});
app.mount(div);
};
}
解释:
1、这里使用setTimeOut是为了保证弹窗动画效果的执行
useModalAlert
函数使用 Vue 3 的createApp
创建了一个新的应用实例,并将你的modal-alert
组件挂载到一个新创建的div
上。在
showModal
函数中,可以传递textTips
、textButton
和事件处理函数onClick
和onClose
,这些将传递给modal-alert
组件的 props 和事件。当用户点击确认按钮或关闭按钮时,组件会被卸载,并从 DOM 中移除。
调用示例
setup
<template>
<div>
<button @click="showMyModal">Show Modal</button>
</div>
</template>
<script>
export default {
setup() {
const showMyModal = () => {
showModal();
};
return { showMyModal };
}
};
</script>
或者
import { useModalAlert } from '@/utils/useModalAlert'; // 假设你将函数放在 utils 文件夹中
export default {
setup() {
const showModal = useModalAlert();
const showMyModal = () => {
showModal({
textTips: 'This is a tip message',
textButton: 'Confirm',
onClick: () => {
console.log('Button clicked');
},
onClose: () => {
console.log('Modal closed');
}
});
};
return { showMyModal };
}
};
非setup中调用
<template>
<div>
<button @click="showModalAlert">Show Modal</button>
</div>
</template>
<script>
import { useModalAlert } from '@/utils/useModalAlert'; // 假设你将函数放在 utils 文件夹中
export default {
name: 'MyComponent',
methods: {
showModalAlert() {
const showModal = useModalAlert();
showModal({
textTips: 'This is a tip message',
textButton: 'Confirm',
onClick: () => {
console.log('Button clicked');
// this.somehandle() 执行组件中的其他方法
},
onClose: () => {
console.log('Modal closed');
}
});
}
}
};
</script>