vue3封装一个好用的函数式弹窗组件

1,310 阅读2分钟

最近的公司开发任务中,遇到了要自己封装弹窗组件的需求,于是就撸了一个... 领导希望这个方法满足以下条件:

支持懒加载(异步加载函数)  
props传参  
事件绑定  
provide inject 注入数据  
各种自定义插槽  
暴露内部方法

下面是一个满足您要求的 Vue 3 函数式弹窗组件的实现示例。这个弹窗组件支持懒加载、props 传参、事件绑定、provide/inject 注入数据、各种自定义插槽,并且暴露内部方法。

1. 创建弹窗组件

首先,创建一个名为 Modal.vue 的组件:

  <div v-if="isVisible" class="modal-overlay">
    <div class="modal">
      <h2>{{ title }}</h2>
      <div class="modal-content">
        <slot name="header"></slot> <!-- 自定义头部插槽 -->
        <slot></slot> <!-- 默认插槽 -->
        <slot name="footer"></slot> <!-- 自定义底部插槽 -->
      </div>
      <button @click="close">关闭</button>
    </div>
  </div>
</template>

<script>
import { ref, watch, provide, inject } from 'vue';

export default {
  name: 'Modal',
  props: {
    title: {
      type: String,
      default: '弹窗标题',
    },
    visible: {
      type: Boolean,
      default: false,
    },
  },
  setup(props, { emit }) {
    const isVisible = ref(props.visible);

    // 提供内部方法
    const close = () => {
      isVisible.value = false;
      emit('update:visible', false);
    };

    // 监听 visible 属性的变化
    watch(() => props.visible, (newVal) => {
      isVisible.value = newVal;
    });

    // Provide inject example
    const modalData = { close };
    provide('modalData', modalData);

    return {
      isVisible,
      close,
    };
  },
};
</script>

<style scoped>
.modal-overlay {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(0, 0, 0, 0.5);
  display: flex;
  justify-content: center;
  align-items: center;
}

.modal {
  background: white;
  padding: 20px;
  border-radius: 5px;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
</style>

2. 创建弹窗控制函数

接下来,创建一个函数来控制弹窗的显示。可以在 src/utils/modal.js 中实现:

import Modal from '../components/Modal.vue';

const modalInstance = {
  app: null,
  instance: null,
};

const showModal = async (title, props = {}, slots = {}) => {
  if (!modalInstance.app) {
    // 懒加载 Modal 组件
    const { default: Modal } = await import('../components/Modal.vue');

    modalInstance.app = createApp({
      setup() {
        const isVisible = ref(true);

        const close = () => {
          isVisible.value = false;
          setTimeout(() => {
            modalInstance.app.unmount();
            modalInstance.app = null;
          }, 300); // 等待动画结束后卸载
        };

        return () => h(Modal, {
          title,
          visible: isVisible.value,
          'onUpdate:visible': close,
          ...props, // 传递 props
        }, slots); // 传递插槽
      },
    });

    modalInstance.instance = modalInstance.app.mount(document.createElement('div'));
    document.body.appendChild(modalInstance.instance.$el);
  }
};

export { showModal };

3. 使用弹窗

在你的 Vue 组件中,可以通过调用 showModal 函数来显示弹窗,并传递 props 和插槽内容。例如:

  <div>
    <button @click="openModal">打开弹窗</button>
  </div>
</template>

<script>
import { showModal } from '../utils/modal';

export default {
  name: 'App',
  methods: {
    openModal() {
      showModal('欢迎', { someProp: 'someValue' }, {
        header: () => <div>自定义头部内容</div>,
        default: () => <div>这是弹窗的主体内容!</div>,
        footer: () => <div>自定义底部内容</div>,
      });
    },
  },
};
</script>

4. 总结

以上代码实现了一个支持懒加载、props 传参、事件绑定、provide/inject 注入数据、各种自定义插槽,并且暴露内部方法的 Vue 3 函数式弹窗组件。用户可以通过调用 showModal 函数来打开弹窗,并传递自定义内容作为插槽。你可以根据需要进一步扩展这个弹窗组件,例如添加更多的样式、动画效果或其他功能。