vue2 函数式调用一个弹框组件
注册为组件的方式,做个弹框很容易。但是用过ant design vue 等框架,你会发现人家的弹框都是通过函数调用的,类似于这样:
this.$confirm({
content: 'destroy all',
onOk() {
return new Promise((resolve, reject) => {
setTimeout(Math.random() > 0.5 ? resolve : reject, 1000);
}).catch(() => console.log('Oops errors!'));
},
cancelText: 'Click to destroy all',
onCancel() {
self.destroyAll();
},
});
并且弹出后,在body底部,并不在业务的html中。
这个可以这么做的思路:做一个vue实例,把他挂载到body上。下面直接上代码:
src/components/Modal/index.vue
<template>
<div class="mask" v-show="visiable" @click="cancel">
<div class="modal" @click.stop="() => {}">
<h2>{{ title }}</h2>
<div class="content" v-html="content"></div>
<footer>
<div class="btn" @click="cancel">取消</div>
<div class="btn" @click="ok">确定</div>
</footer>
</div>
</div>
</template>
<script>
export default {
props: {
title: {
type: String,
default: "",
},
content: {
type: String,
default: "",
},
onCancel: {
type: Function,
default: () => {},
},
onOk: {
type: Function,
default: () => {},
},
},
data() {
return {
visiable: false,
};
},
methods: {
open() {
this.visiable = true;
},
cancel() {
this.onCancel();
this.visiable = false;
},
ok() {
this.onOk();
this.visiable = false;
},
},
};
</script>
<style lang="less" scoped>
.mask {
position: fixed;
left: 0;
right: 0;
top: 0;
bottom: 0;
z-index: 10000;
background-color: rgba(0, 0, 0, 0.55);
}
.modal {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: 600px;
padding: 0 34px;
background-color: #fff;
border-radius: var(--btn-radius);
h2 {
height: 80px;
font-size: 20px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #272727;
line-height: 80px;
border-bottom: 1px dashed rgba(151, 151, 151, 0.2);
}
.content {
font-size: 16px;
margin: 36px 0 50px;
}
footer {
display: flex;
justify-content: space-between;
margin-bottom: 50px;
.btn {
width: 180px;
height: 44px;
border-radius: 2px;
border: 1px solid rgba(102, 102, 102, 0.7);
text-align: center;
line-height: 44px;
cursor: pointer;
&:last-child {
background: var(--btn-bg);
color: #fff;
}
}
}
/deep/.price-num {
font-size: 20px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: var(--text-1);
}
}
</style>
src/components/Modal/index.js(核心代码)
import Vue from "vue";
import Modal from "./Index.vue"; // 引入弹窗组件
const ModalComponent = Vue.extend(Modal);
let app;
Modal.open = (options) => {
if (options === 'cancel') {
app && app.cancel();
return;
}
app = new ModalComponent(
{ propsData: options }
).$mount();
document.body.appendChild(app.$el);
Vue.nextTick(() => {
app.open();
});
};
export default Modal; // 导出
main.js
import $modal from '@/components/modal/index.js' Vue.prototype.$modal = $modal.open;
组件里调用举例:
this.$modal({
title: "再租一台",
content: "租用和目标机器,配置相同的一台机器,可选择GPU数量",
onOk: () => {
this.$router.push({
path: "/store/hire",
query: {
gpuType: cObj.Gpu_type,
node: "全部",
mirrorImage: cObj.Image,
mirrorImageLabel: cObj.Image,
dateNum:
cObj.Use_mode === 0
? 0
: Math.round((cObj.Due_time - cObj.Ctime) / 24 / 3600),
gpuNum: cObj.Gpu_num,
os: cObj.ContainerType.includes("kvm") ? "kvm" : "docker",
performance: cObj.Performance,
},
});
},
});
优化,vue是个单页面应用SPA。在路由变化时,应该隐藏弹框:
router.beforeEach(async (to, from, next) => {
Vue.prototype.$modal('cancel');
})

浙公网安备 33010602011771号