折叠展开面板

83 阅读1分钟
//引用
 <Panel  v-model="expanded2" />
<template>
  <div class="expand-transition-panel" :class="{ expanded: value }">
    <div class="panel-header">
      <span class="panel-title">
        <slot name="title">{{ title }}</slot>
      </span>
      <slot name="icon">
        <i class="el-icon-arrow-right arrow" @click="$emit('input', !value)"></i>
      </slot>
    </div>
    <template v-if="!useFlex && supportsGrid">
      <div class="panel-body__grid">
        <div class="panel-content__grid">
          <slot>
            <!-- 模拟一下未知高度 -->
            <div v-for="num in 10" :key="num" class="test-item">{{ num }}</div>
          </slot>
        </div>
      </div>
    </template>
    <template v-else>
      <div class="panel-body__flex">
        <!-- 额外必须的div -->
        <div style="flex: 1">
          <div class="panel-content__flex">
            <slot>
              <!-- 模拟一下未知高度 -->
              <div v-for="num in 10" :key="num" class="test-item">{{ num }}</div>
            </slot>
          </div>
        </div>
      </div>
    </template>
  </div>
</template>

<script>
export default {
  props: {
    value: {
      type: Boolean,
      default: false,
    },
    title: {
      type: String,
      default: '面板标题',
    },
    /**  强制使用flex,演示用 */
    useFlex: {
      type: Boolean,
      default: false,
    },
  },
  data() {
    return {
      supportsGrid: true,
    }
  },
  methods: {
    checkGridSupport() {
      const div = document.createElement('div')
      const style = div.style
      // 检查标准属性
      if ('grid' in style) {
        this.supportsGrid = true
        return
      }
      // 检查前缀属性
      const prefixes = ['Moz', 'Webkit', 'O', 'ms']
      for (let i = 0; i < prefixes.length; i++) {
        if (prefixes[i] + 'Grid' in style) {
          this.supportsGrid = true
          return
        }
      }
      // 如果都没有找到,说明不支持
      this.supportsGrid = false
    },
  },
  mounted() {
    this.checkGridSupport()
  },
}
</script>

<style lang="scss" scoped>
.expand-transition-panel {
  .panel-header {
    height: 48px;
    border-bottom: 1px solid #eaeaea;
    display: flex;
    align-items: center;
    padding: 0 16px;
    .panel-title {
      flex: 1;
      height: 100%;
      display: flex;
      align-items: center;
    }
  }
  .panel-body__flex {
    display: flex;
  }
  .panel-body__grid {
    display: grid;
    /** 使用grid过渡 */
    grid-template-rows: 0fr;
    /** 收起时上下padding需为0 */
    padding: 0 16px;
    transition: all 0.3s;
  }
  .arrow {
    font-size: 16px;
    cursor: pointer;
    flex-shrink: 0;
    transition: all 0.3s;
  }
  .panel-content__flex {
    overflow: hidden;
    /** 收起时上下padding需为0 */
    padding: 0 16px;
    /* 通过max-height来过渡 */
    max-height: 0;
    transition: all 0.3s;
  }
  .panel-content__grid {
    overflow: hidden;
  }
  &.expanded {
    .panel-content__flex {
      max-height: 100%;
    }
    .panel-body__grid {
      grid-template-rows: 1fr;
    }
    .arrow {
      transform: rotate(90deg);
    }
  }
  .test-item {
    background-color: #e3e3eb;
    color: #333;
  }
}
</style>