vue3基于element-plus封装一套可拖拽的弹框

934 阅读1分钟

在我们日常开发中已经遇到各种弹框,今天封装了一套可拖拽弹框,开箱可用:

在componnets下新建Dialog文件, 里面再建index.vue,代码如下:

  • 里面有用到scss的样式,这些可自定义
<script setup>
  const props = defineProps({
    appendToBody: {
      type: Boolean,
      default: false,
    },
    lockScroll: {
      type: Boolean,
      default: true,
    },
    width: {
      type: [String, Number],
      default: '50%',
    },
    modelValue: {
      type: Boolean,
      default: false,
    },
    title: {
      type: String,
      default: '',
    },
    showClose: {
      type: Boolean,
      default: true,
    },
    showFullscreen: {
      type: Boolean,
      default: false,
    },
    draggable: {
      type: Boolean,
      default: true,
    },
    loading: {
      type: Boolean,
      default: false,
    },
  })
  const emit = defineEmits(['update:modelValue'])

  const dialogVisible = useVModel(props, 'modelValue', emit)
  const isFullscreen = ref(false)

  const closeDialog = () => {
    dialogVisible.value = false
  }
  const setFullscreen = () => {
    isFullscreen.value = !isFullscreen.value
  }
</script>

<template>
  <div class="main-dialog">
    <el-dialog
      v-model="dialogVisible"
      v-bind="$attrs"
      :append-to-body="appendToBody"
      :draggable="draggable"
      :fullscreen="isFullscreen"
      :lock-scroll="lockScroll"
      :show-close="false"
      :width="width"
    >
      <template #header>
        <slot name="header">
          <span class="el-dialog__title">{{ title }}</span>
        </slot>
        <div class="main-dialog__headerbtn">
          <button
            v-if="showFullscreen"
            aria-label="fullscreen"
            type="button"
            @click="setFullscreen"
          >
            <el-icon v-if="isFullscreen" icon="fullscreen-exit-line" />
            <el-icon v-else icon="fullscreen-line" />
          </button>
          <button
            v-if="showClose"
            aria-label="close"
            type="button"
            @click="closeDialog"
          >
            <el-icon icon="close-circle-line" />
          </button>
        </div>
      </template>
      <div v-loading="loading">
        <slot></slot>
      </div>
      <template #footer>
        <slot name="footer"></slot>
      </template>
    </el-dialog>
  </div>
</template>

<style lang="scss" scoped>
  .main-dialog {
    &__headerbtn {
      position: absolute;
      top: var(--el-dialog-padding-primary);
      right: var(--el-dialog-padding-primary);
    }

    button {
      padding: 0;
      margin-left: 15px;
      font-size: var(--el-message-close-size, 16px);
      color: var(--el-color-info);
      cursor: pointer;
      background: transparent;
      border: none;
      outline: none;
      transition: $base-transition;
      &:hover i {
        color: var(--el-color-primary);
      }
    }

    :deep(.el-dialog) {
      &.is-fullscreen {
        top: 0px !important;
        left: 0px !important;
        display: flex;
        flex-direction: column;

        .el-dialog__body {
          flex: 1;
          overflow: auto;
        }

        .el-dialog__footer {
          padding-bottom: 10px;
          border-top: 1px solid var(--el-border-color-base);
        }
      }
    }
  }
</style>

用法如下:

  • 新建DialogDemo引入dialog组件, 绑定v-model
<template>
  <mian-dialog
    v-model="dialogVisible"
    show-fullscreen
    title="测试title"
    width="600px"
  >
    我是内容展示
    <template #footer>
      <el-button @click="dialogVisible = false">取 消</el-button>
      <el-button type="primary" @click="dialogVisible = false">确 定</el-button>
    </template>
  </vab-dialog>
</template>

<script>
  import MainDialog from '@/components/Dialog'

  export default defineComponent({
    name: 'DialogDemo',
    components: {
      MainDialog,
    },
    setup() {
      const state = reactive({
        dialogVisible: false,
      })
      return {
        ...toRefs(state),
      }
    },
  })
</script>

<style></style>

组件使用

  • 引入上面的组件
<template>
  <div class="dialog-drag-container">
    <el-button type="primary" @click="handleClick">可拖拽弹窗</el-button>
    <dialog-demo ref="dialogRef" />
  </div>
</template>

<script>
  export default defineComponent({
    name: 'DialogDrag',
    components: {
      DialogDemo: defineAsyncComponent(() => import('./components/DialogDemo')),
    },
    setup() {
      const state = reactive({
        dialogRef: '',
      })
      const handleClick = () => {
        state['dialogRef'].dialogVisible = true
      }
      return {
        ...toRefs(state),
        handleClick,
      }
    },
  })
</script>

  • 以上就是完整代码, 赋值即可查看效果,如有不足,欢迎大家补充