Vue3 二次封装组件

710 阅读1分钟

通过v-model二次封装组件el-dialog组件

官方例子:cn.vuejs.org/guide/compo…

//父组件
import { ref } from 'vue';
import type { Ref } from 'vue';
const dialogVisible: Ref<boolean> = ref(false);
function handleClose(done: Function):void {
  ElMessageBox.confirm('Are you sure to close this dialog?')
    .then(():void => {
      done();
    })
    .catch(():void => {
      // catch error
    });
}

 <AiDialog
    v-model="dialogVisible"
    :destroy-on-close="false"
    :before-close="handleClose"
    close-on-press-escape
    close-on-click-modal
  ></AiDialog>
//子组件

<script setup lang="ts">
import { computed } from 'vue';
import { IStyleComputed } from '../utils/type';
const emit = defineEmits(['update:modelValue']);
// interface IProps {
//   title: string;
// }
// const props = withDefaults(defineProps<IProps>(), {});
const props = defineProps({
  // 开关
  modelValue: {
    type: Boolean,
    required: true,
  },
  // 标题
  title: {
    type: String,
    default: '标题',
  },
  // 宽度
  width: {
    type: String,
    default: '30%',
  },
  // 是否全屏
  fullscreen: {
    type: Boolean,
    default: false,
  },
  // marginTop的默认值
  top: {
    type: String,
    defalut: '15vh',
  },
  // 是否需要遮罩
  modal: {
    type: Boolean,
    default: true,
  },
  // 是否插入body元素上
  appendToBody: {
    type: Boolean,
    default: true,
  },
  // 开启时是否锁定滚动条
  lockScroll: {
    type: Boolean,
    default: true,
  },
  // 自定义class类
  class: {
    type: String,
    default: '',
  },
  // Dialog 打开的延时时间,单位毫秒
  openDelay: {
    type: Number,
    default: 0,
  },
  // Dialog 关闭的延时时间,单位毫秒
  closeDelay: {
    type: Number,
    default: 0,
  },
  // 是否可以通过点击 modal 关闭 Dialog
  closeOnClickModal: {
    type: Boolean,
    defalut: false,
  },
  // 是否可以通过按下 ESC 关闭 Dialog
  closeOnPressEscape: {
    type: Boolean,
    defalut: false,
  },
  // 是否显示关闭按钮
  showClose: {
    type: Boolean,
    default: true,
  },
  // 可拖拽
  draggable: {
    type: Boolean,
    default: true,
  },
  // 是否让 Dialog 的 header 和 footer 部分居中排列
  center: {
    type: Boolean,
    default: false,
  },
  // 垂直居中
  alignCenter: {
    type: Boolean,
    default: true,
  },
  // 是否销毁
  destroyOnClose: {
    type: Boolean,
    defalut: false,
  },
  // 背景颜色
  backgroundColor: {
    type: String,
    default: 'white',
  },
  // 边框阴影
  boxShadow: {
    type: String,
    default:
      '0px 12px 32px 4px rgba(0, 0, 0, .04), 0px 8px 20px rgba(0, 0, 0, .08)',
  },
  // 头部样式
  headerStyle: {
    type: Object,
    default: {
      padding: '20px',
    },
  },
  // 内容区域样式
  mainStyle: {
    type: Object,
    default: {
      padding: '30px 20px',
    },
  },
  // 底部区域样式
  footerStyle: {
    type: Object,
    default: {
      padding: '20px',
      textAlign: 'right',
    },
  },
  //关闭函数
  beforeClose: {
    type: Function,
  },
});

const styleComputed = computed<IStyleComputed>(() => {
  return {
    backgroundColor: props.backgroundColor,
    boxShadow: props.boxShadow,
  };
});
const dialogVisibleComputed = computed({
  get() {
    return props.modelValue;
  },
  set(val) {
    emit('update:modelValue', val);
  },
});
// 打开
function open(): void {
  // console.log('打开');
}
// 打开动画结束时
function opened(): void {
  // console.log('动画结束');
}
// 关闭
function close(): void {
  // console.log('关闭');
}
// 关闭动画结束时
function closed(): void {
  // console.log('关闭动画结束时');
}
// 输入焦点聚焦在 Dialog 内容时的回调
function openAutoFocus(): void {
  // console.log('输入焦点聚焦在 Dialog');
}
// 输入焦点从 Dialog 内容失焦时的回调
function closeAutoFocus(): void {
  // console.log('输入焦点从 Dialog 内容失焦时的回调');
}
// 关闭前的回调,会暂停 Dialog 的关闭. 回调函数内执行 done 参数方法的时候才是真正关闭对话框的时候.
function beforeCloseFn(done: Function): void {
  if (props.beforeClose) {
    props.beforeClose(done);
  } else {
    done();
  }
}
</script>

<template>
  <!-- 封装对话框组件 -->
  <el-dialog
    v-model="dialogVisibleComputed"
    :title="props.title"
    :width="props.width"
    :fullscreen="props.fullscreen"
    :top="props.top"
    :modal="props.modal"
    :append-to-body="props.appendToBody"
    :lock-scroll="props.lockScroll"
    :class="props.class"
    :open-delay="props.openDelay"
    :close-delay="props.closeDelay"
    :close-on-click-modal="props.closeOnClickModal"
    :close-on-press-escape="props.closeOnPressEscape"
    :show-close="props.showClose"
    :draggable="props.draggable"
    :center="props.center"
    :align-center="props.alignCenter"
    :destroy-on-close="props.destroyOnClose"
    :before-close="beforeCloseFn"
    @open="open"
    @opened="opened"
    @close="close"
    @closed="closed"
    @open-auto-focus="openAutoFocus"
    @close-auto-focus="closeAutoFocus"
    :style="styleComputed"
  >
    <template #header>
      <div :style="props.headerStyle">
        <slot name="header">{{ props.title }}</slot>
      </div>
    </template>
    <div :style="props.mainStyle">
      <slot><span>This is a message</span></slot>
    </div>
    <template #footer>
      <div :style="props.footerStyle">
        <slot name="footer">
          <span class="dialog-footer">
            <el-button @click="emit('update:modelValue', !props.modelValue)"
              >Cancel</el-button
            >
            <el-button
              type="primary"
              @click="emit('update:modelValue', !props.modelValue)"
            >
              Confirm
            </el-button>
          </span></slot
        >
      </div>
    </template>
  </el-dialog>
</template>

<style scoped lang="scss"></style>
<style lang="scss">
.el-dialog__header {
  padding: 0;
  // margin-right: 0;
}
.el-dialog__body {
  padding: 0;
}
.el-dialog__footer {
  padding: 0;
  text-align: unset;
}
</style>

以上!