十五分钟两百行代码,手写一个vue项目全局通用的弹框

前言:

我们在写vue项目时,弹框是非常常用的组件,并且在同一个项目中,弹框大多类似。所以我们可以抽离封装出一个通用的弹框;

因为vue3可向下兼容,所以作者这边会使用vue2的写法,vue3写法大同小异。

第一步:新建相关文件

一般来说是在src/components/dialog下新建如下两个文件:

  1. index.vue:该文件是组件内容相关的,用来书写弹框组件的结构、样式、和动态逻辑;
  2. index.js:该文件使用虚拟节点创建组件内容,并且注册组件。

第二步:书写组件内容

index.vue组件内容如下:

  1. 结构 + js 代码
<template>
  <div class="default-message" :id="boxId">
    <div class="default-message-content">
      <div class="default-message-title">{{ title }}</div>
      <div class="default-message-value" v-html="message"></div>
      <div class="default-message-btns">
        <div
          class="default-message-cancle default-message-btn"
          v-if="cancelBtnHtml"
          @click.prevent.stop="handleCancel"
        >
          {{ cancelBtnHtml }}
        </div>
        <div
          class="default-message-submit default-message-btn"
          @click.prevent.stop="handleOk"
        >
          {{ okBtnHtml }}
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import i18n from "@/i18n";
import { defineComponent } from "vue";
export default defineComponent({
  name: "Dialog",
  data() {
    return {
      i18nTitle: '',
      i18nOkBtn: '',
    };
  },
  props: {
    boxId: {
      type: String,
      default: "",
    },
    // 标题
    title: {
      type: String,
      default: "",
    },
    // 内容
    message: {
      type: String,
      default: "",
    },
    // 确定按钮文字
    okBtnHtml: {
      type: String,
      default: '',
    },
    // 取消按钮文字
    cancelBtnHtml: {
      type: String,
      default: "",
    },
    // 成功回调
    ok_function: {
      type: Function,
    },
    // 失败回调
    cancel_function: {
      type: Function,
    },
  },
  methods: {
    handleCancel() {
      this.removeModal();
      this.cancel_function && this.cancel_function();
    },
    handleOk() {
      this.removeModal();
      this.ok_function && this.ok_function();
    },
    removeModal() {
      const modelDom = document.getElementById(
        "__default__container__content__"
      );
      if (modelDom) {
        document.body.removeChild(modelDom);
      }
    },
  },
  created() {
    this.i18nTitle = i18n.global.t('modal_warm_tip_title');
    this.i18nOkBtn = i18n.global.t('activity_ok');
  },
});
</script>

结构说明:

  • .default-message使我们整个弹框的容器,一般宽高都设置为100%,这个部分会有一个半透明的背景色(覆盖页面内容,防止弹框了还能操作页面);
  • .default-message-content为整个弹框的内容区域,包括标题、提示信息、取消按钮、确定按钮;
  • 取消按钮和确定按钮支持执行传入的事件,方便我们在弹框弹出后点击按钮执行相应操作;
  1. 样式
<style lang="less" scoped>
.default-message {
  position: fixed;
  right: 0;
  top: 0;
  bottom: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: 1000;
  background: rgba(0, 0, 0, 0.7);

  .default-message-title {
    color: #333;
    margin: 0;
    line-height: 1.5;
    font-size: 18px;
    min-height: 18px;
    padding-top: 20px;
    text-overflow: ellipsis;
    font-weight: bold;
    cursor: move;
    text-align: center;
  }

  .default-message-content {
    width: 85%;
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate3d(-50%, -50%, 0);
    background-color: #fff;
    border-radius: 6px;
    transition: all 0.2s ease-in;
    color: #999;
    font-size: 18px;
  }

  .default-message-value {
    padding: 28px 18px;
    text-align: center;
    position: relative;
    color: #999;
    text-align: center;
    font-size: 14px;
    color: rgba(102, 102, 102, 1);
  }
  .default-message-btns {
    // border-top: 1px solid #ddd;
    display: flex;
    height: 60px;
    position: relative;
    &:after {
      position: absolute;
      content: "";
      display: inline-block;
      left: 0;
      right: 0;
      top: 0;
      height: 1px;
      transform: scaleY(0.5);
      background: #ddd;
    }
    .default-message-btn {
      flex: 1;
      display: flex;
      align-items: center;
      justify-content: center;
      font-size: 16px;
      padding: 0 3px;
    }
    .default-message-submit {
      color: #26a2ff;
    }
    .default-message-cancle {
      color: #999;
      position: relative;
      &:after {
        position: absolute;
        content: "";
        display: inline-block;
        top: 0;
        right: 0;
        bottom: 0;
        width: 1px;
        transform: scaleX(0.5);
        background: #ddd;
      }
    }
  }
  @keyframes fadeIn {
    from {
      opacity: 0;
    }
    to {
      opacity: 1;
    }
  }
}
</style>

第三步:注册成全局组件

import {createVNode, render} from 'vue';
import MessageConstructor from './index.vue';

const $dialog = function (options) {
  // 已存在一个弹窗则不重复渲染
  if (!document.getElementById ('__default__container__content__')) {
    // 创建div
    const container = document.createElement ('div');
    // container.className = `__default__container__message__`;
    container.id = '__default__container__content__';
    //创建虚拟节点
    const vm = createVNode (MessageConstructor, options);
    //渲染虚拟节点
    render (vm, container);
    document.body.appendChild (container);
  }
};

export default {
  //组件注册
  install (app) {
    app.config.globalProperties.$dialog = $dialog;
  },
};

到这里,我们的弹框组件就完成了,接下来我们来使用看看。

项目中使用弹框

使用的方法也非常简单,所见即所得。

app.config.globalProperties.$dialog({
  title: "弹框标题",
  message: "弹框提示信息文案",
  okBtnHtml: "确定",
  cancelBtnHtml: "取消",
  ok_function: () => {
    console.log("点击弹框确定按钮处理函数");
  },
  cancel_function: () => {
    console.log("点击弹框取消按钮处理函数");
  }
});

说明:

  1. 标题、提示文案、以及取消和确定按钮文案,我们这边直接传入,ok_function是确定按钮的回调,我们可以在这里做任何点击确定后想做的事,包括发送请求和异步操作,cancel_function同理。
  2. 弹框图片示例:

写在后面

这是一个比较基础的弹框组件,这边示例的代码是比较全的,对细节要求不大的小伙伴可以直接用;

背景颜色、字体、布局等这些细节,因为每个业务场景不同,大家可以根据自己的需要适当调整;

弹框是固定单位的,如果小伙伴的项目需要使用响应式大小,直接对应替换大小单位即可;

对你有帮助的话给作者点点关注吧,你的支持是我不断更新的动力!Peace and love~~

posted @ 2024-08-23 09:13  雾散声声慢  阅读(188)  评论(6编辑  收藏  举报