本篇文章记录仿写一个el-drawer组件细节,从而有助于大家更好了解饿了么ui对应组件具体工作细节。本文是elementui源码学习仿写系列的又一篇文章,后续闲暇了会不断更新并仿写其余组件。源码在github上,大家能够拉下来,npm start运行跑起来,联合正文有助于更好的了解。github仓库地址如下:https://github.com/shuirongsh...

什么是抽屉drawer组件

  • 同弹框dialog组件相似,UI展现略有不同
  • 个别抽屉是左右防线弹出和发出,高低方向不多
  • 可在抽屉外部进行代码补充操作
  • 某些状况下,抽屉组件比弹框组件更加好用一些

笔者对于抽屉组件的封装,就不写太多的解析阐明了,大家能够间接复制粘贴代码,搭配代码中的正文进行应用(联合本人公司业务封装)

笔者的抽屉组件实现,抛砖引玉。实现次要罕用的性能,道友们能够进行思维发散

效果图

先看一下抽屉组件的效果图

代码

应用时的代码

<template>  <div>    <h4>isShowDrawer.sync属性管制是否显示抽屉</h4>    <h4>title属性管制抽屉的头部题目</h4>    <h4>direction属性管制抽屉的4个方向</h4>    <h4>beforeClose函数属性敞开抽屉前的操作动作</h4>    <h4>showCloseIcon属性管制是否显示抽屉的敞开小按钮</h4>    <h4>isShowHeader属性管制是否显示抽屉的头部内容</h4>    <h4>mask属性管制是否显示抽屉的背景遮罩层</h4>    <h4>slot="title"具名插槽管制头部的题目内容</h4>    <h4>clickMaskClose属性管制是否可能点击背景遮罩层敞开抽屉</h4>    <br />    <my-drawer      :isShowDrawer.sync="isShowDrawer1"      title="上方弹出direction='top'"      direction="top"      :beforeClose="handleClose"      :showCloseIcon="false"    ></my-drawer>    <my-drawer      :isShowDrawer.sync="isShowDrawer2"      title="下方弹出"      direction="bottom"      :isShowHeader="false"    >      <h1>:isShowHeader="false"去掉抽屉的头部内容</h1>      <h1>:isShowHeader="false"去掉抽屉的头部内容</h1>      <h1>:isShowHeader="false"去掉抽屉的头部内容</h1>      <h1>:isShowHeader="false"去掉抽屉的头部内容</h1>      <h1>:isShowHeader="false"去掉抽屉的头部内容</h1>      <h1>:isShowHeader="false"去掉抽屉的头部内容</h1>      <h1>:isShowHeader="false"去掉抽屉的头部内容</h1>      <h1>:isShowHeader="false"去掉抽屉的头部内容</h1>      <h1>:isShowHeader="false"去掉抽屉的头部内容</h1>      <h1>:isShowHeader="false"去掉抽屉的头部内容</h1>      <h1>:isShowHeader="false"去掉抽屉的头部内容</h1>    </my-drawer>    <my-drawer      :isShowDrawer.sync="isShowDrawer3"      direction="left"      :mask="false"    >      <span slot="title">左侧命名插槽弹出哦^_^</span>      <span>没有背景遮罩层</span>    </my-drawer>    <my-drawer      :isShowDrawer.sync="isShowDrawer4"      direction="right"      :clickMaskClose="false"    >      <span slot="title">右侧命名插槽弹出哦^_^</span>      <span>设置点击背景遮罩层不敞开,只能点击小箭头,或自定义按钮敞开</span>      <br />      <br />      <br />      <br />      <el-button        @click="isShowDrawer4 = false"        type="success"        size="small"        plain        >自定义敞开</el-button      >    </my-drawer>    <el-button @click="topOpen" type="success" plain>上方弹出</el-button>    <el-button @click="bottomOpen" type="success" plain>下方弹出</el-button>    <el-button @click="leftOpen" type="success" plain>左侧弹出</el-button>    <el-button @click="rightOpen" type="success" plain>右侧弹出</el-button>  </div></template><script>export default {  data() {    return {      isShowDrawer1: false,      isShowDrawer2: false,      isShowDrawer3: false,      isShowDrawer4: false,    };  },  methods: {    topOpen() {      this.isShowDrawer1 = true;    },    bottomOpen() {      this.isShowDrawer2 = true;    },    leftOpen() {      this.isShowDrawer3 = true;    },    rightOpen() {      this.isShowDrawer4 = true;    },    handleClose(close) {      this.$confirm("确认敞开close()函数敞开")        .then((_) => {          close();        })        .catch((_) => {});    },  },};</script>

封装的抽屉组件代码

<template>  <!-- 抽屉关上敞开过渡成果依据name去指定 -->  <transition :name="computedName">    <!-- clickMaskCloseFn搭配@click.stop -->    <div      @click="clickMaskCloseFn"      class="myDrawerWrap"      :class="{ isShowDrawerMask: mask }"      v-show="isShowDrawer"    >      <div        ref="drawerContentRef"        :class="['drawerContent']"        :style="computedDrawerPosition"        @click.stop      >        <header v-show="isShowHeader" class="drawerHeader">          <slot name="title">            <span>{{ title }}</span>          </slot>          <i class="el-icon-close" @click="closeDrawer" v-show="showCloseIcon">          </i>        </header>        <section class="drawerBody">          <slot></slot>        </section>      </div>    </div>  </transition></template><script>const directionArr = ["top", "bottom", "left", "right"]; // "ttb","btt","ltr","rtl"const moveObj = {  top: "topMove",  bottom: "bottomMove",  left: "leftMove",  right: "rightMove",};export default {  name: "myDrawer",  props: {    // 是否显示抽屉    isShowDrawer: {      type: Boolean,      default: false,    },    // 是否显示抽屉头部内容    isShowHeader: {      type: Boolean,      default: true,    },    // 父组件传过来的抽屉题目值    title: {      type: String,      default: "我是title",    },    // 是否显示敞开小图标    showCloseIcon: {      type: Boolean,      default: true,    },    // 是否开启抽屉背景遮罩层    mask: {      type: Boolean,      default: true,    },    // 点击遮罩层敞开默认为true    clickMaskClose: {      type: Boolean,      default: true,    },    // 校验抽屉的4个方向    direction: {      type: String,      default: "right",      validator(val) {        return directionArr.includes(val);      },    },    // 接管父组件传递过去的敞开函数,会中断敞开抽屉的操作    beforeClose: {      type: Function,    },  },  computed: {    // 动态控制上下左右的抽屉内容区的地位以及抽屉的宽度    computedDrawerPosition() {      let positionObj = {        width:          (this.direction == "left") | (this.direction == "right")            ? "30%"            : "100%",        height:          (this.direction == "top") | (this.direction == "bottom")            ? "30%"            : "100%",      };      positionObj[this.direction] = 0;      return positionObj;    },    // 动态控制抽屉从上下左右进入和退出    computedName() {      return moveObj[this.direction]; // topMove、bottomMove、leftMove、rightMove    },  },  methods: {    // 点击遮罩层敞开弹框    clickMaskCloseFn() {      if (this.clickMaskClose == true) {        this.closeDrawer();      } else {        /* 这里要管制一下冒泡事件,留神第十行应用@click.stop           不管制冒泡的话,点击内容区也会导致弹出框敞开*/        return;      }    },    // 筹备敞开抽屉弹出框    closeDrawer() {      console.log(888);      // 若传递了beforeClose函数,就抛出敞开函数,供内部应用      if (this.beforeClose) {        this.beforeClose(this.close);      }      // 没有beforeClose函数,间接敞开即可      else {        this.close();      }    },    // 敞开抽屉弹出框    close() {      this.$emit("update:isShowDrawer", false); // 敞开      this.$emit("shutDown"); // 并抛出一个shutDown告诉事件    },  },};</script><style lang='less' scoped>// 根本款式.myDrawerWrap {  position: fixed;  width: 100%;  height: 100%;  top: 0;  left: 0;  z-index: 999;  overflow: hidden;  .drawerContent {    // 搭配定位的形式管制在上下左右的那个方位    position: absolute;    background-color: #fff;    box-shadow: 2px 2px 12px 0 rgba(0, 0, 0, 0.24);    display: flex;    flex-direction: column;    // 抽屉头部    .drawerHeader {      width: 100%;      height: 48px;      box-sizing: border-box;      padding: 12px;      display: flex;      align-items: center;      justify-content: space-between;      font-weight: bolder;      color: #333;      i {        cursor: pointer;      }    }    // 抽屉内容体局部    .drawerBody {      width: 100%;      box-sizing: border-box;      padding: 12px;      flex: 1;      overflow-y: auto;    }  }}// 遮罩层即为背景色.isShowDrawerMask {  background-color: rgba(0, 0, 0, 0.3);}/*  下方是抽屉过渡动画的重点*/// 上方进入和退出.topMove-enter-active,.topMove-leave-active {  transition: all 0.36s ease-in-out;  transform: translateY(0%);  opacity: 1;}.topMove-enter,.topMove-leave {  transform: translateY(-100%);  opacity: 0;}.topMove-leave-to {  transform: translateY(-100%);  opacity: 0;}// 下方进入和退出.bottomMove-enter-active,.bottomMove-leave-active {  transition: all 0.36s ease-in-out;  transform: translateY(0);  opacity: 1;}.bottomMove-enter,.bottomMove-leave {  transform: translateY(100%);  opacity: 0;}.bottomMove-leave-to {  transform: translateY(100%);  opacity: 0;}// 左侧进入和退出.leftMove-enter-active,.leftMove-leave-active {  transition: all 0.36s ease-in-out;  transform: translateX(0%);  opacity: 1;}.leftMove-enter,.leftMove-leave {  transform: translateX(-100%);  opacity: 0;}.leftMove-leave-to {  transform: translateX(-100%);  opacity: 0;}// 右侧进入和退出.rightMove-enter-active,.rightMove-leave-active {  transition: all 0.36s ease-in-out;  transform: translateX(0);  opacity: 1;}.rightMove-enter,.rightMove-leave {  transform: translateX(100%);  opacity: 0;}.rightMove-leave-to {  transform: translateX(100%);  opacity: 0;}</style>

总结

  • A bad pen is better than a good memory
  • 残缺代码在github上哦(还有其余笔者封装的组件)