本篇文章记录仿写一个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上哦(还有其余笔者封装的组件)