vue3封装一个Dialog组件和showDialog函数

第一步:构建Dialog组件

提供了标题,内容插槽,加载loading,自定义按钮等一些基础功能

<template>
  <div>
    <div
      v-if="props.show"
      :class="$style['dialog']"
    >
      <div
        v-if="props.title"
        :class="$style['title']"
      >
        {{ props.title }}
      </div>
      <div :class="$style['mainer']">
        <slot />
      </div>
      <div :class="$style['footer']">
        <Button
          v-if="props.showCancelButton"
          :disabled="cancelLoading"
          :loading="cancelLoading"
          :class="$style['btn']"
          plain
          @click="handleCancel"
          >{{ props.cancelButtonText || '取消' }}</Button
        >
        <Button
          :disabled="confirmLoading"
          :loading="confirmLoading"
          :class="$style['btn']"
          type="primary"
          plain
          @click="handleConfirm"
          >{{ props.confirmButtonText || '确认' }}</Button
        >
      </div>
    </div>
    <div
      v-if="props.show"
      :class="$style['overlay']"
    ></div>
  </div>
</template>

<script setup lang="ts">
import { Button } from 'vant';
import { Props } from './type.ts';
import { shallowRef } from 'vue';

const props = withDefaults(defineProps<Props>(), {
  cancelButtonText: '',
  confirmButtonText: '',
  show: false,
  showCancelButton: false,
});
const confirmLoading = shallowRef(false);
const cancelLoading = shallowRef(false);
const handleConfirm = async () => {
  const result = props.confirm?.();
  if (result instanceof Promise) {
    confirmLoading.value = true;
    result.finally(() => {
      confirmLoading.value = false;
    });
  }
};

const handleCancel = async () => {
  const result = props.cancel?.();

  if (result instanceof Promise) {
    cancelLoading.value = true;
    result.finally(() => {
      cancelLoading.value = false;
    });
  }
};
</script>

<style lang="scss" module>
.footer {
  display: flex;
  align-items: center;
  padding: 5px;
  width: 100%;
  .btn {
    flex: 1;
    border: none;
  }
}

.dialog {
  width: 80%;
  position: fixed;
  top: 45%;
  left: 50%;
  transform: translate(-50%, -50%);
  background: white;
  padding: 20px 20px 0 20px;
  z-index: 2;
  overflow: hidden;
  transition: 0.3s;
  border-radius: 16px;
  transition-property: transform, opacity;
}

.overlay {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: rgba(0, 0, 0, 0.5);
  z-index: 1;
}
.title {
  font-weight: 400;
  font-size: 18px;
  color: #202020;
  line-height: 22px;
  text-align: center;
}
.mainer {
  margin-top: 5px;
}
</style>

第二步:构建showDialog函数

基于第一步的Dialog组件,封装函数,更便于使用

import Dialog from './index.vue';
import { render, ref, h, VNode } from 'vue';
import { ToastWrapperInstance } from 'vant';

export { Dialog };
interface Props {
  show?: boolean;
  title?: string;
  cancelButtonText?: string | boolean;
  confirmButtonText?: string | boolean;
  showCancelButton?: boolean;
  cancel?: () => void | Promise<void | ToastWrapperInstance>;
  confirm?: () => void | Promise<void | ToastWrapperInstance>;
  slotContent?: VNode | VNode[];
}
export function showDialog({
  show,
  showCancelButton,
  title,
  confirmButtonText,
  cancelButtonText,
  confirm,
  cancel,
  slotContent,
}: Props) {
  const showRef = ref(show);

  const handleConfirm = async () => {
    try {
      confirm?.();
    } catch (error) {
    } finally {
      closeDialog();
    }
  };

  const handleCancel = async () => {
    try {
      cancel?.();
    } catch (error) {
    } finally {
      closeDialog();
    }
  };

  const closeDialog = () => {
    showRef.value = false;
    setTimeout(() => {
      render(null, container);
    }, 200); // Ensure any closing animations can complete
  };

  //   const vnode = createVNode(Dialog, { //createVNode和h同效果
  const vnode = h(
    Dialog,
    {
      show: showRef.value,
      title: title,
      confirmButtonText,
      cancelButtonText,
      showCancelButton: showCancelButton,
      confirm: handleConfirm,
      cancel: handleCancel,
    },
    {
      default: () => {
        return slotContent ? slotContent : null;
      },
    },
  );

  const container = document.createElement('div');
  document.body.appendChild(container);
  render(vnode, container);
  return {
    closeDialog,
  };
}
export function showCancelDialog(options: Props) {
  return showDialog({
    ...options,
    showCancelButton: true,
  });
}

第三步:使用

    //第一种使用方式 
     <Dialog
        title="提示"
        :show="show"
        :show-cancel-button="true"
        :confirm="submit"
        :cancel="
          () => {
            show = false;
          }
        "
      >
        <div>是否确认,请填写理由</div>
      </Dialog>

    //第二种使用方式
    showDialog({ 
        show: true,
        title: '标题', 
        confirmButtonText: '确认通过',
        confirm: handleConfirm,
        onCancel: handleCancel,
        slotContent: [h('div', [h('div','测试1'),h('div',测试2)])] 
    });

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
封装一个全局的函数组件,你可以遵循以下步骤: 1. 在 `src` 目录下创建一个新的文件夹,例如 `components`,并在该文件夹中创建一个名为 `ElDialog.vue` 的文件。 2. 在 `ElDialog.vue` 文件中编写组件的代码,如下所示: ```html <template> <div v-if="visible" class="el-dialog"> <h2 class="el-dialog-title">{{ title }}</h2> <p class="el-dialog-content">{{ content }}</p> <!-- 其他内容... --> </div> </template> <script> import { defineComponent, reactive } from 'vue'; export default defineComponent({ name: 'ElDialog', props: { title: String, content: String, // 其他 props... }, setup(props) { const visible = reactive({ value: false }); return { visible, }; }, }); </script> <style scoped> .el-dialog { /* 样式定义 */ } .el-dialog-title { /* 样式定义 */ } .el-dialog-content { /* 样式定义 */ } </style> ``` 在上述代码中,我们使用了 `reactive` 函数来创建响应式数据 `visible`,用于控制组件的显示与隐藏。通过在父组件中修改 `visible.value` 的值,可以控制 `el-dialog` 的显示状态。 3. 在 `src` 目录下创建一个名为 `main.js` 的文件,并在其中注册全局的函数组件: ```javascript import { createApp } from 'vue'; import ElDialog from './components/ElDialog.vue'; const app = createApp(); app.component('el-dialog', ElDialog); app.mount('#app'); ``` 在上述代码中,我们使用 `app.component` 方法来注册 `el-dialog` 组件为全局组件。这样,在你的应用程序的任何地方,你都可以使用 `<el-dialog>` 标签来引用该组件。 4. 在你的应用程序的主入口文件中,例如 `App.vue`,使用 `<el-dialog>` 标签来调用该组件: ```html <template> <div id="app"> <!-- 其他内容... --> <el-dialog title="对话框标题" content="对话框内容"></el-dialog> </div> </template> <script> export default { // 组件的逻辑... }; </script> <style> /* 样式定义... */ </style> ``` 现在,你就可以在整个应用程序中使用 `<el-dialog>` 标签,并传递所需的属性来显示全局的函数组件了。 请注意,以上示例只是一个简单的演示,你可以根据实际需求进行更复杂的组件逻辑和样式定义。同时,也可以根据项目的具体情况,在全局注册组件时使用其他的标签名。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值