封装一个折叠组件

727 阅读1分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动

TIP 👉 假作真时真亦假,无为有处有还无。曹雪芹《红楼梦》

前言

在我们日常项目开发中,我们经常会做一些折叠功能,所以封装了这款折叠组件。

折叠组件

属性

1. value
  • 是否折叠
  • 值为布尔类型
  • 默认值:false
2. duration
  • 动画持续时间
  • 值为数值类型,单位:毫秒
  • 默认值:300
3. noEnter
  • 无展开动画
  • 值为布尔类型
  • 默认值:false
4. noLeave
  • 无折叠动画
  • 值为布尔类型
  • 默认值:false

示例

<template>
  <div class="collapse">
    <div class="switch-bar" @click="clickHandle">{{isCollapse?'展开':'收起'}}</div>
    <BaseCollapse :value="isCollapse" :duration="500" :noEnter="false" :noLeave="false">
      <div class="content">
        <h1>1111111</h1>
        <h1>2222222</h1>
        <h1>3333333</h1>
      </div>
    </BaseCollapse>
  </div>
</template>
<script>
import BaseCollapse from '@/components/base/collapse/index.vue'
export default {
  name: 'CollapseDemo',
  components: {
    BaseCollapse
  },
  data () {
    return {
      isCollapse: false
    }
  },
  methods: {
    clickHandle () {
      this.isCollapse = !this.isCollapse
    }
  }
}
</script>
<style lang="scss" scoped>
.collapse{
  width: 400px;
  margin: 0 auto;
  padding: 50px;
  .switch-bar{
    text-align: center;
    font-size: 38px;
    line-height: 64px;
    border-radius: 16px;
    border: solid 1px #999999;
  }
  .content{
    margin-top: 20px;
    background-color: #d8f2ff;
    padding: 20px;
    text-align: center;
  }
}
</style>

实现collapse.vue

<!-- 折叠组件 -->
<template>
  <transition v-on:before-enter="beforeEnter"
              v-on:enter="enter"
              v-on:after-enter="afterEnter"
              v-on:before-leave="beforeLeave"
              v-on:leave="leave"
              v-on:after-leave="afterLeave">
    <div class="collapse-wrap" v-show="!collapseFlag">
      <slot></slot>
    </div>
  </transition>
</template>
<script>
export default {
  name: 'collapse',
  props: {
    // 是否折叠
    value: {
      type: Boolean,
      dafault: false
    },
    // 持续时间(单位:毫秒)
    duration: {
      type: Number,
      default: 300
    },
    // 无进入动画
    noEnter: {
      type: Boolean,
      default: false
    },
    // 无退出动画
    noLeave: {
      type: Boolean,
      default: false
    }
  },
  data () {
    return {
      collapseFlag: this.value
    }
  },
  computed: {
    elTransition () {
      let duration = this.duration
      return `${duration}ms height ease-in-out, ${duration}ms padding-top ease-in-out, ${duration}ms padding-bottom ease-in-out`
    }
  },
  watch: {
    value (val) {
      this.collapseFlag = val
    }
  },
  methods: {
    beforeEnter (el) {
      if (this.noEnter) return
      el.style.transition = this.elTransition
      if (!el.dataset) el.dataset = {}

      el.dataset.oldPaddingTop = el.style.paddingTop
      el.dataset.oldPaddingBottom = el.style.paddingBottom

      el.style.height = 0
      el.style.paddingTop = 0
      el.style.paddingBottom = 0
    },

    enter (el) {
      el.dataset.oldOverflow = el.style.overflow
      if (el.scrollHeight !== 0) {
        el.style.height = el.scrollHeight + 'px'
        el.style.paddingTop = el.dataset.oldPaddingTop
        el.style.paddingBottom = el.dataset.oldPaddingBottom
      } else {
        el.style.height = ''
        el.style.paddingTop = el.dataset.oldPaddingTop
        el.style.paddingBottom = el.dataset.oldPaddingBottom
      }

      el.style.overflow = 'hidden'
    },

    afterEnter (el) {
      el.style.transition = ''
      el.style.height = ''
      el.style.overflow = el.dataset.oldOverflow
    },

    beforeLeave (el) {
      if (!el.dataset) el.dataset = {}
      el.dataset.oldPaddingTop = el.style.paddingTop
      el.dataset.oldPaddingBottom = el.style.paddingBottom
      el.dataset.oldOverflow = el.style.overflow

      el.style.height = el.scrollHeight + 'px'
      el.style.overflow = 'hidden'
    },

    leave (el) {
      if (el.scrollHeight !== 0 && !this.noLeave) {
        el.style.transition = this.elTransition
        el.style.height = 0
        el.style.paddingTop = 0
        el.style.paddingBottom = 0
      }
    },

    afterLeave (el) {
      el.style.transition = ''
      el.style.height = ''
      el.style.overflow = el.dataset.oldOverflow
      el.style.paddingTop = el.dataset.oldPaddingTop
      el.style.paddingBottom = el.dataset.oldPaddingBottom
    }
  }
}
</script>

希望看完的朋友可以给个赞,鼓励一下