给 el-card 添加折叠功能

注意
本文最后更新于 2024-01-10,文中内容可能已过时。
出发点
虽然 Element 也有 el-collapse 组件,但是当我只想写一个折叠面板时,它的写法就略显繁琐了,el-card 组件的样式也更符合我的需求,所以我就想着给 el-card 添加折叠功能。

1 效果

在线演示:https://lruihao.github.io/vue-el-demo/#/card-collapse

2 实现过程

一开始想着使用 Vue 的自定义指令功能来实现,但是动手之前还是习惯性地先看 el-card 的源码,如下所示:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<template>
  <div class="el-card" :class="shadow ? 'is-' + shadow + '-shadow' : 'is-always-shadow'">
    <div class="el-card__header" v-if="$slots.header || header">
      <slot name="header">{{ header }}</slot>
    </div>
    <div class="el-card__body" :style="bodyStyle">
      <slot></slot>
    </div>
  </div>
</template>

<script>
  export default {
    name: 'ElCard',
    props: {
      header: {},
      bodyStyle: {},
      shadow: {
        type: String
      }
    }
  };
</script>

这一看源码这么简单,直接改得了,还用啥自定义指令,开干!

3 实现方式

  1. 通过继承 el-card 组件来实现,这样就不用改 el-card 的源码了,也不用担心升级 Element 时会被覆盖掉。
  2. 然后在继承的组件中添加一个 isCollapse 属性来控制折叠状态。

继承也很简单,这样简单几行就完整继承了原来 el-card 的所有功能了:

1
2
3
4
5
6
7
<script>
import { Card } from 'element-ui'
export default {
  name: 'ElCardCollapse',
  extends: Card,
}
</script>

然后,把 el-card template 中的代码先原封不动地复制过来,再在需要的地方添加折叠按钮和相关逻辑就行了:

 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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
<template>
  <div class="el-card" :class="shadow ? 'is-' + shadow + '-shadow' : 'is-always-shadow'">
    <div
      v-if="$slots.header || header"
      class="el-card__header"
      :class="isCollapseSelf ? 'collapse-icon-right' : 'collapse-icon-down'"
      @click="isCollapseSelf = !isCollapseSelf"
    >
      <slot name="header">{{ header }}</slot>
    </div>
    <div
      class="el-card__body"
      :style="bodyStyle"
      :class="{'is-collapse': isCollapseSelf}"
    >
      <slot />
    </div>
  </div>
</template>

<script>
import { Card } from 'element-ui'
export default {
  name: 'ElCardCollapse',
  extends: Card,
  props: {
    isCollapse: {
      type: Boolean,
      default: false,
    },
  },
  data() {
    return {
      isCollapseSelf: this.isCollapse,
    }
  },
}
</script>
<style lang="scss" scoped>
.el-card__header {
  cursor: pointer;
  position: relative;

  &::after {
    font-family: element-icons !important;
    speak: none;
    font-style: normal;
    font-weight: 400;
    font-variant: normal;
    text-transform: none;
    line-height: 1;
    vertical-align: baseline;
    display: inline-block;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    position: absolute;
    right: 10px;
    top: 50%;
    transform: translateY(-50%);
  }

  &.collapse-icon-right::after {
    content: '\e6e0';
  }
  &.collapse-icon-down::after {
    content: '\e6df';
  }
}
.is-collapse {
  display: none;
}
</style>

4 使用方法

main.js 中引入:

1
2
import ElCardCollapse from '@/components/ElCardCollapse.vue'
Vue.component('ElCardCollapse', ElCardCollapse)

写法和 el-card 一样,只是多了一个 is-collapse 属性,使用 el-card-collapse 代替 el-card 即可:

 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
42
43
44
<template>
  <div>
    <el-card-collapse class="box-card" :is-collapse="isCollapse">
      <div slot="header" class="flex-between">
        <span>卡片名称</span>
        <el-button style="padding: 3px 0; margin-right: 10px;" type="text">操作按钮</el-button>
      </div>
      <div v-for="o in 4" :key="o" class="text item">
        {{ '列表内容 ' + o }}
      </div>
    </el-card-collapse>
  </div>
</template>

<script>
export default {
  name: 'CardCollapse',
  data() {
    return {
      isCollapse: true,
    }
  },
}
</script>

<style lang="scss" scoped>
.text {
  font-size: 14px;
}

.item {
  margin-bottom: 18px;
}

.flex-between {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.box-card {
  width: 480px;
}
</style>

相关内容

Buy me a coffee~
Lruihao 支付宝支付宝
Lruihao 微信微信
0%