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');
})

  

 

posted @ 2022-04-26 16:34  小虫1  阅读(980)  评论(1编辑  收藏  举报