<template> <div class="drawer"> <div :class="maskClass" @click="closeByMask"></div> <div :class="mainClass" :style="mainStyle" class="main"> <div class="drawer-head"> <span>{{ title }}</span> <span v-show="closable" class="close-btn" @click="closeByButton" >x</span> </div> <div class="drawer-body" :style="bodyStyle"> <slot /> </div> </div> </div> </template> <script> export default { name: 'drawer', props: { // 是否打开 display: { type: Boolean }, // 标题 title: { type: String, default: '标题' }, // 是否显示关闭按钮 closable: { type: Boolean, default: true }, // 是否显示遮罩 mask: { type: Boolean, default: true }, // 是否点击遮罩关闭 maskClosable: { type: Boolean, default: true }, // 宽度 { type: String, default: '400px' }, // 高度 height: { type: String, default: '75%' }, // 是否在父级元素中打开 inner: { type: Boolean, default: false } }, computed: { maskClass: function () { return { 'mask-show': this.mask && this.display, 'mask-hide': !(this.mask && this.display), inner: this.inner } }, mainClass: function () { return { 'main-show': this.display, 'main-hide': !this.display, inner: this.inner } }, mainStyle: function () { return { this.width, height: this.height, bottom: this.display ? '0' : `-${this.height}`, borderTop: this.mask ? 'none' : '1px solid #eee' } }, bodyStyle: function () { return { height: this.height } } }, mounted () { if (this.inner) { let box = this.$el.parentNode box.style.position = 'relative' } }, methods: { closeByMask () { this.maskClosable && this.$emit('update:display', false) }, closeByButton () { this.$emit('update:display', false) } } } </script> <style lang="less" scoped> .drawer { .mask-show { position: fixed; top: 0; left: 0; 100%; height: 100%; z-index: 10; background-color: rgba(0, 0, 0, 0.5); opacity: 1; transition: opacity 0.5s; } .mask-hide { opacity: 0; transition: opacity 0.5s; } .main { position: fixed; z-index: 10; bottom: 0; height: 100%; border-top-left-radius: 10px; border-top-right-radius: 10px; background: #f7f7f7; transition: all 0.5s; } .main-show { opacity: 1; } .main-hide { opacity: 0; } .inner { position: absolute; } .drawer-head { display: flex; justify-content: space-between; align-items: center; height: 50px; padding: 20px; box-sizing: border-box; border-top-left-radius: 10px; border-top-right-radius: 10px; font-size: 16px; font-weight: bold; background: #fff; position: relative; border-bottom: 1px solid #eee; .close-btn { font-size: 24px; position: absolute; right: 20px; top: 50%; transform: translateY(-50%); display: inline-block; cursor: pointer; } } .drawer-body { // padding: 20px; font-size: 14px; overflow: auto; } } </style>
import drawer from './drawer' components: { drawer }, display: true, drawerWidth: '100%', drawerHeight: '500px', <el-button type="primary" @click="display = !display">{{display?'close': 'open'}}</el-button> <drawer title="我是标题" :display.sync="display" :width="drawerWidth" :height="drawerHeight"> <div>123</div> </drawer>
cnpm install stylus-loader css-loader style-loader --save-dev
cnpm install less less-loader --save-dev
第二种方案:
<template> <div class="drawer"> <button @click="clickBtn">点击</button> <div class="background" v-if="open" @click.self="closeDrop"> <div class="drop" :class="{ active: isActive, close: isClose }">drop</div> </div> </div> </template> <script> export default { name: 'HelloWorld', props: {}, data () { return { open: false, isActive: false, isClose: false } }, methods: { clickBtn () { this.open = true this.isActive = true this.isClose = false }, closeDrop () { this.isClose = true setTimeout(() => { this.open = false }, 200) } } } </script> <style scoped lang="scss"> .background { position: fixed; top: 0; bottom: 0; left: 0; right: 0; background: rgba($color: #000000, $alpha: 0.5); .drop { 0px; position: absolute; top: 0; right: 0; bottom: 0; background: #fff; } // 开 .active { animation: opendoor 0.3s normal forwards; } @keyframes opendoor { from { 0; } to { 45%; } } // 关 .close { animation: close 0.3s normal forwards; } @keyframes close { 0% { 45%; } 100% { 0; opacity: 0; } } } </style>