一、背景

element-ui组件的样式是固定的,比如我们常用的那些组件,table,button,icon,tab等等。当我们需要的样式和element组件有偏差的时候,我们可以通过针对element组件进行二次封装,然后通过Vue.component()方法,定义到全局,来解决我们当前的项目需求

二、 分析

(1)有利于紧密贴合业务,提高开发效率
(2)封装的组件越来越多,业务能得到实际的解决,并能形成公司独特组件库
(3)提高开发者组件设计能力
(4)需要长期维护,当官方库最初更新尤其是对封装组件影响较大时,需要对应更新,维护成本较大

三、示例封装el-dialog

  1. 不能简单的进行el-组件写在封装组件内,在进行调用是不会生效,相当于父组件再引用的时候直接展示了组件,需要加标签,这个element组件库文档说明中是有预留api的,例如el-dialog中:
    使用时,要注意slot结构,
     <slot name="title" />
     <slot />
     <span slot="footer" class="dialog-footer">
       <slot name="footer" />
     </span>
  1. 子组件在封装的时候,主要是将原本封装好的属性 再次重新罗列,如果需求只是用一部分功能 只需要把基本功能都加上即可,但是对于高复用的组件来说,就需要把el-dialog的所有属性都进行罗列,其中,值得注意的是对话框有一个右上角关闭功能,这个按钮功能主要起到可直接关闭当前对话框以及遮罩层功能,对于封装组件来说控制对话框的显示隐藏是通过属性:visible来实现的,但是对于封装组件是通过调用组件方:父组件通过props传递,props是一种单向数据传递方式,故不能通过改变visible值为false来进行关闭弹窗,饿了么团队使用了一种语法糖方法来进行是实现
<el-dialog
      id="kydialog"
      :show="show"
      :title="title"
      :visible.sync="visible"
      :width="width"
      :modal="false"
      :fullscreen="fullscreen"
      :top="top"
      :append-to-body="appendToBody"
      :lock-scroll="lockScroll"
      :custom-class="customClass"
      :close-on-click-modal="closeOnClickModal"
      :close-on-press-escape="closeOnPressEscape"
      :show-close="showClose"
      :before-close="beforeClose"
      :center="center"
      :destroy-on-close="destroyOnClose"
      :inner-dialog="innerDialog"
      @open="open"
      @opened="opened"
      @close="close"
      @closed="closed"
      @shadeShow="shadeShow"
      @clearShade="clearShade"
    >
      <slot />
      <span slot="footer" class="dialog-footer">
        <slot name="footer" />
      </span>
    </el-dialog>

其中visible属性较为特殊,需要加上sync修饰符,element官方给的写法也是如此,visible.sync,但是当二次封装的时候,在是父组件调用二次封装的组件使用visible时,点击右上角的“×”会造成无法关闭,源码中实现利用的是sync语法糖来实现改变父组件传来的visible值,来实现关闭对话框,如果直接关闭也可再二次封装组件中添加close方法 ,将关闭控制值,放到close中去,而下面的调用方法,是将语法糖直接写在二次封装的组件中,这样,对于使用方的父组件来说,更少的修改,用户体验较好

export default {
  props: {
    show: { type: Boolean, default: false }
  },
  data() {
    return {
      visible: this.show
    }
  },
  watch: {
    show: {
      immediate: true,
      handler(show) {
        this.visible = this.show
      }
    }
  },
  methods: {
    OnClose() {
      this.$emit('update:show', false)
    }
  }
}
  1. 当使用el-dialog对话框自定义头部信息时,如果直接使用上述封装的组件,会发现自定义头部消失,这是因为自定义头部内容相当于覆盖已经封装的组件头部,但是由于二次封装就已经将el-dialog的头部进行覆盖封装了,所以想在已经覆盖封装的组件头部内容上在进行自定义封装,显然是无效的,解决方法,只需加一个属性来进行判断,来控制对话框头部是否是二次封装的slot,来实现,封装中结构(控制属性定义为custom-header)
  <div v-if="customHeader" slot="title">
        <slot name="title" />
     </div>
     <slot v-else name="title" />
     <slot />
     <span slot="footer" class="dialog-footer">
        <slot name="footer" />
     </span>
  1. 这样在使用对话框自定义头部时只需要加上custom-header为true的属性即可,
    父组件使用
<template>
    <kj-dialog
      title="提示"
      :show.sync="dialogVisible"
      width="30%"
      center
    >
      <div slot="title" class="header-title">
        <span style="line-height:24px;font-size:18px;color:red;">你好</span>
      </div>
      <span>需要注意的是内容是默认不居中的</span>
      <span slot="footer" class="dialog-footer">
        <el-button @click="centerDialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="centerDialogVisible = false">确 定</el-button>
      </span>
    </kj-dialog>
</template>

遮罩层样式

.v-modal {
  position: fixed;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  opacity: .5;
  background: #000;
  /* z-index: 2000; 
 background: rgba(0, 0, 0, 0.6);
	*/
}
Logo

前往低代码交流专区

更多推荐