组件的二次封装(弹框为例)

实现思路(核心)

  • 封装时可借助ekement-ui(样式)
  • 利用好 $listener, $attr隔代传值,在组件中调用属性或方法
  • slot插槽的运用

$listener, $attr的详细用法:
https://blog.csdn.net/lqlq54321/article/details/106389054
*首次封装

<template>
  <div v-if="show">
    <div :class="{'base-dialog--mask': true, 'base-dialog--mask--white': styleType === 'white'}">
      <div class="base-dialog--content" :style="width&&{width:width}">
        <div class="base-dialog--header" :style="titleHeight&&{height:titleHeight, lineHeight: titleHeight}">
          <slot name="header">
            {
    
    {
    
    title}}
            <br ref="defaultFocus" tabindex="0" />
            <div class="base-dialog--header-close" @click="cancel" :style="iconSize&&{height:iconSize, width: iconSize}"></div>
          </slot>
        </div>
        <div class="base-dialog--main">
          <slot></slot>
        </div>
        <div v-if="!nofooter" class="base-dialog--footer">
          <slot name="footer">
            <template v-if="isConfirmDialog">
              <BaseButton class="del" @click="btnClick">{
    
    {
    
    submitBtnText}}</BaseButton>
              <BaseButton type="plain" class="cancel" @click="cancel">取消</BaseButton>
            </template>
            <template v-else>
              <BaseButton class="know" @click="closeDialog">我知道了</BaseButton>
            </template>
          </slot>
        </div>
      </div>
    </div>
  </div>
</template>
export default {
    
    
  inheritAttrs: false,
  components: {
    
    
    BaseButton,
  },
  props: {
    
    
    show: {
    
    
      type: Boolean,
      default: false,
    },
    title: String,
    width: String,
    submitBtnText: {
    
    
      type: String,
      default: "确定",
    },
    failBtnText: {
    
    
      type: String,
      default: "取消",
    },
    dialogType: {
    
    
      type: String,
      default: "confrim",
    },
    nofooter: {
    
    
      type: Boolean,
      default: false,
    },
  },
  computed: {
    
    
    isConfirmDialog() {
    
    
      return this.dialogType === "confrim";
    },
  },
  watch: {
    
    
    show: {
    
    
      handler(val) {
    
    
        if (val) {
    
    
          this.$emit("open");
          this.$nextTick(() => {
    
    
            if (!this.isConfirmDialog) {
    
    
              this.focus();
            } else {
    
    
              this.$refs.defaultFocus.focus();
            }
          });
        }
      },
      immediate: true,
    },
  },
  mounted() {
    
    
    const body = document.body;
    if (body.append) {
    
    
      body.append(this.$el);
    } else {
    
    
      body.appendChild(this.$el);
    }
  },
  destroyed() {
    
    
    this.$el.remove();
  },
  methods: {
    
    
    btnClick() {
    
    
      this.$emit("btnClick");
      this.closeDialog();
    },
    cancel() {
    
    
      this.$emit("cancel");
      this.closeDialog();
    },
    closeDialog() {
    
    
      this.$emit("close");
      this.$emit("update:show", false);
    },
    focus() {
    
    
      this.$nextTick(() => {
    
    
        deepRun(this.$refs.firstButton, "focus");
      });
    },
  },
};

注释:BaseButton为一个组件
二次封装

<template>
  <BaseDialog class="normal-dialog" ref="baseDialog" :show="show" v-bind="$attrs" v-on="$listeners">
    <div class="normalDiaglogContent">
      <slot></slot>
    </div>
  </BaseDialog>
</template>
import BaseDialog from "./BaseDialog.vue";
export default {
    
    
  components: {
    
     BaseDialog },
  inheritAttrs: false,
  props: {
    
     show: Boolean },
  watch: {
    
    
    show(val) {
    
    
      if (val) {
    
    
        this.$nextTick(() => {
    
    
          this.focus();
        });
      }
    }
  },
  methods: {
    
    
    focus() {
    
    
      this.$refs.baseDialog.focus();
    }
  }
};

猜你喜欢

转载自blog.csdn.net/lqlq54321/article/details/107961042