我是靠谱客的博主 俊逸身影,这篇文章主要介绍button添加插槽之后绑定不来事件_如何给element添加一个抽屉组件,现在分享给大家,希望可以做个参考。

b225b3a716e974e1f8db15d4bc17f7e1.png

近来因为业务需要,对比iview和element库,发现element确实要比实习期间使用的iview强大点,尤其文档更为友好,但是iview的组件功能更多一点,比如分割线和抽屉组件

今天特意手写一个抽屉组件,方便自己使用element库,写好的组件我已经放在我的githup了,

mmdctjj/meow​github.com
f2f850859c20bf072494469f362b4e82.png

一、实践

1.分析

一个抽屉组件的z-index必定是在当前页面之上的,在抽屉主体之外的区域还会有一层半透明的遮罩层,知道这些就很容易了

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// drawer.vue <template> <div class="mask"></div> <div class="drawer"> <div class="drawer_body"></div> </div> </template> <style scoped> .drawer { position: absolute; height: 100vh; top: 0; bottom: 0; right: 0; left: 0; z-index: 1000000 !important; } .drawer .drawer_body { height: 100%; position: absolute; z-index: 1000001; background-color: #fff; } .mask { height: 100vh; width: 100vw; position: absolute; z-index: 1000000; top: 0; left: 0; background-color: #000; opacity: 0.5; } </style>

现在已经是我们想要的样子了,接下来是给drawer_body添加样式

作为一个灵活的组件库,我们希望样式是可以随时定制的,所以,接下要添加的样式都使用props动态绑定的

参考iview的样式,除了抽屉的宽度,还需要设置抽屉的方向,当我们需要抽屉时让它显示出来,不需要时隐藏它,或者为了更加显眼,甚至给抽屉更换背景色......,这些都是可以实现的,看下面的代码

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<script> export default { props: { // 是否显示drawer drawerVisible: Boolean, // drawer方向 direction: { type: String, validator(val) { return ["right", "left"].indexOf(val) !== -1; } }, // drawer宽度 width: { type: Number, default: 400 }, // drawer背景色 background: { type: String, default: "#ffffff" }, // 是否显示遮罩层 mask: { type: Boolean, default: true } } }; </script>

对于宽度和背景色,你还需要额外的处理下

复制代码
1
2
3
4
5
6
<div class="drawer_body" :style="{'right':direction=='right'?'0':'auto', 'left':direction=='left'?'0':'auto', 'width':width+'px','background':background}" >drawer</div>

你只需在使用的地方引入组件,然后提供你想修改的props值

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//index.vue <template> <div> ... <el-button size="mini" @click="visible">显示抽屉</el-button> <Drawer :drawerVisible="drawerVisible" direction="right" :mask="true" background="aquamarine" ></Drawer> </div> </template> <script> export default { data() { return { drawerVisible: false }; }, methods:{ // 打开抽屉 visible() { this.drawerVisible = true; } } } </script>

2.关闭抽屉

在点击遮罩层的时候,我们希望可以关闭已经打开的抽屉组件,这里如果你直接修改父组件传过来的drawerVisible值,会报错如下

复制代码
1
2
3
vue.esm.js:629 [Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "drawerVisible"

这是因为vue是单向数据流的,如果想改变父元素的值,必须使用监听事件的方式,但是2.3.0之后添加了.sync修饰符,所以,正确的做法是使用.sync修饰符

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
... <div v-if="drawerVisible" class="mask"></div> <transition :name="this.direction=='left'?'slide-right':'slide-left'"> <div v-if="drawerVisible" @click.stop="closeBtn?'':close" class="drawer"> <div class="drawer_body" :style="{ 'right':direction=='right'?'0':'auto', 'left':direction=='left'?'0':'auto', 'width':width+'px', 'background': background}" > </div> </div> </transition> ... methods: { close() { this.$emit("update:drawerVisible", false); } }

另外,我们还希望在关闭抽屉组件时,我们可以监听到这个事件然后做出反应

复制代码
1
2
3
4
5
6
methods: { close() { this.$emit("update:drawerVisible", false); this.$emit("close"); } }

此时需要在抽屉组件上添加

复制代码
1
2
3
4
5
6
7
8
9
10
11
<Drawer :drawerVisible.sync="drawerVisible" @close="close" > </Drawer> methods:{ close(){ // 关闭抽屉组件时你要做的事 } }

2.动画

动画是UI的灵魂,所以接下来给抽屉组件的显示和隐藏添加动画,我们使用transition的css动画做动画过度效果

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
//drawer.vue <div class="drawer"> <div class="mask"></div> <!-- 不同方向使用不用的动画名称,如果抽屉在左边,则进入方向是朝 → --> <transition :name="this.direction=='left'?'slide-right':'slide-left'"> <div class="drawer_body" v-if="drawerVisible" :style="{'right':direction=='right'?'0':'auto', 'left':direction=='left'?'0':'auto', 'width':width+'px', 'background':background}" >drawer</div> </transition> </div> </template> <style scoped> /* * ... *这里省略了写过的样式 */ .slide-right-enter-active, .slide-right-leave-active, .slide-left-enter-active, .slide-left-leave-active { will-change: transform; transition: transform 300ms; position: absolute; width: 100vw; height: 100vh; overflow: hidden; } .slide-right-enter, .slide-right-leave-active { transform: translate(-100%, 0); } .slide-left-leave-active, .slide-left-enter { transform: translate(100%, 0); } </style>

虽然现在已经完全实现了抽屉的功能,但是本着更加精美的原则,我还打算使用slot给它添加辩题和页脚

3.添加标题

标题solt的name值是header

添加标题的目的是为了让抽屉组件看起来更加清楚,此外,除了添加标题,我还想添加个关闭按钮

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 需要添加几个props属性 <script> export default { props: { // drawer标题 title: String, // 是否显示关闭按钮 closeBtn: { type: Boolean, default: false }, } }; </script>

你可以选择是否添加标题,是否添加关闭按钮,值的注意的是如果添加了关闭按钮,点击遮罩层就不会自动关闭抽屉组件了

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!--这里要啰嗦下布局,如果你只选择开启关闭按钮,那justify-content布局是flex-end 如果两者都开启,那justify-content布局是space-between--> <slot name="header"> <div v-if="title||closeBtn" :style="{'justify-content':title?'space-between':'flex-end'}" class="title" > <div v-if="title">{{title}}</div> <el-button v-if="closeBtn" circle size="mini" icon="el-icon-close" @click="close" ></el-button> </div> </slot>

我是这么做到禁用遮罩层点击事件的

复制代码
1
<div v-if="drawerVisible" @click.stop="closeBtn?'':close" class="mask"></div>

当然这些你可以使用具名插槽自定义的

复制代码
1
2
3
4
5
6
7
8
9
<Drawer :width="400" direction="right" :mask="true" title="抽屉组件" > <div v-slot:header>这里是自定义标题</div> <div style="height:100px"></div> </Drawer>

4.添加页脚

页脚solt的name值是footer

复制代码
1
2
3
4
为了使得页脚和标题有一定的距离,我给主体内容添加了最小高度 <div style="min-height:82vh;padding: 5px 0"> <slot></slot> </div>

方法是很类似的,只是我多添加了两个监听事件,确定和取消

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//drawer.vue <slot name="footer"> <div class="footer"> <el-button size="mini" type="primary" @click="footerOk">确认</el-button> <el-button size="mini" @click="footerCal">取消</el-button> </div> </slot> //引入的页面 <Drawer :width="400" direction="right" :mask="true" title="抽屉组件" :footer-ok="footerOk" :footer-cal="footerCal" > </Drawer>

还需要在props中添加对应的值

复制代码
1
2
3
4
props: { footerOk: Function, footerCal: Function },

关于页脚的布局是这样的

复制代码
1
2
3
4
5
6
.footer { border-top: 0.1px solid #ddd; display: flex; justify-content: flex-end; padding-top: 10px; }

当然这些你也是可以使用具名插槽自定义的

复制代码
1
2
3
4
5
6
7
8
9
10
<Drawer :width="400" direction="right" :mask="true" title="抽屉组件" > <div v-slot:header>这里是自定义标题</div> <div style="height:100px"></div> <div v-slot:footer>这里是自定义页脚</div> </Drawer>

5.主体是否可以滚动

前面说过给主体添加了最小高度,但是超过最小高度,可能会被撑开布局,所以我给它添加了滚动功能

复制代码
1
2
3
4
5
6
// props添加 // 是否开启滚动 scroll: { type: Boolean, default: false }

在drawer_body的样式末尾追加overflow-y样式

复制代码
1
2
3
4
5
6
7
8
9
10
11
<div class="drawer_body" :style="{ 'right':direction=='right'?'0':'auto', 'left':direction=='left'?'0':'auto', 'width':width+'px', 'background': background, 'overflow-y':scroll?'scroll':'hidden'}" > </div> scroll默认是不开启的,如果你的抽屉要放的内容少,就不用理这个属性,但是当内容撑开抽屉时记得手动开启这个功能

6.细节的优化

这里说下自己的不足之处,并且如何改进它

a.滚动条bug

当选择抽屉在右边时,动画过程中会出现滚动条,看起来让我的UI组件大打折扣,针对这个问题我打算在组件中监听drawerVisible,当它需要被展示时禁用body的滚动效果,当它不需要被展示时,还原body的展示效果

复制代码
1
2
3
4
5
6
7
8
watch: { drawerVisible(n, o) { if (n == true) { document.documentElement.style.overflowY = "hidden"; document.documentElement.style.overflowX = "hidden"; } } },

b.向下冒泡bug

在点击抽屉以外的区域可以正常关闭抽屉,但是我发现当我点击抽屉非按钮区域时,也会关闭抽屉,这是向下冒泡的bug,这个bug我的解决方案是在drawer_body上添加个无意义的事件,并阻止向上冒泡

复制代码
1
2
3
4
5
6
7
8
9
10
11
<div @click.stop="clickBg_" // 注意这里 class="drawer_body" :style="{ 'right':direction=='right'?'0':'auto', 'left':direction=='left'?'0':'auto', 'width':width+'px', 'background': background, 'overflow-y':scroll?'scroll':'hidden'}" > </div>

二、API文档

1.属性

008f388c432cb75a156a3874be8733f7.png

2.事件

7dd22366f26ff1d377113c00a3a4acf7.png

3.slot

52622faee76202231397b5fa84039fe9.png
复制代码
1
2
注意:插槽里的按钮都是使用element内置的组件,如果你的项目里没有引入element库 那最好请使用具名插槽重写页头和页脚部分

有兴趣的同学可以看看我之前的文章

萌萌哒草头将军:徒手撸个vue项目框架(上)​zhuanlan.zhihu.com
3c92b5e36ca8c4ad27989ce32b847fbc.png
萌萌哒草头将军:徒手撸个vue项目框架(下)​zhuanlan.zhihu.com
3c92b5e36ca8c4ad27989ce32b847fbc.png
萌萌哒草头将军:天天喵:定制一款简洁的首页​zhuanlan.zhihu.com
cf3e074b18e2b04ee36e398a13a2d187.png

欢迎一起讨论学习

最后

以上就是俊逸身影最近收集整理的关于button添加插槽之后绑定不来事件_如何给element添加一个抽屉组件的全部内容,更多相关button添加插槽之后绑定不来事件_如何给element添加一个抽屉组件内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(45)

评论列表共有 0 条评论

立即
投稿
返回
顶部