[Element Plus 源码解析] Container 布局容器

2,281 阅读1分钟

一、组件介绍

[官网链接](组件 | Element (gitee.io))

el-container组件是用于布局的容器组件,用于搭建页面的基本结构;

其通常与el-headerel-asideel-mainel-footer搭配使用。

二、源码分析

2.1 container组件代码

container.vue

<template>
  // 外层使用原生section标签
  <section class="el-container" :class="{'is-vertical': isVertical}">
    // 提供默认插槽
    <slot></slot>
  </section>
</template>
<script lang="ts">
import { defineComponent, computed, VNode, Component } from 'vue'

export default defineComponent({
  name: 'ElContainer',
  props: {
    direction: {
      type: String,
      default: '',
    },
  },
  setup(props, { slots }) {
    // 判断是否采用垂直布局,若采用垂直布局,则将flex-direction设置为column
    const isVertical = computed(() => {
      // 显式传入布局方向
      if (props.direction === 'vertical') {
        return true
      } else if (props.direction === 'horizontal') {
        return false
      }
      if (slots && slots.default) {
        const vNodes: VNode[] = slots.default()
        return vNodes.some(vNode => {
          const tag = (vNode.type as Component).name
          // 当子元素中包含 `<el-header>` 或 `<el-footer>` 时,全部子元素会垂直上下排列,否则会水平左右排列。
          return tag === 'ElHeader' || tag === 'ElFooter'
        })
      } else {
        return false
      }
    })
    return {
      isVertical,
    }
  },
})
</script>
@import 'mixins/mixins';
// BEM命名
@include b(container) {
  // flex布局
  display: flex; 
  flex-direction: row;
  flex: 1;
  flex-basis: auto;
  box-sizing: border-box;
  min-width: 0;
  
  // 垂直
  @include when(vertical) {
    flex-direction: column;
  }
}

2.2 header组件代码

header.vue

<template>
  // 原生header标签               
  <header class="el-header" 
    // 设置css局部变量覆盖全局变量动态设置header高度
    :style="{ '--el-header-height': height }">
    // 默认插槽
    <slot></slot>
  </header>
</template>
<script lang="ts">
import { defineComponent } from 'vue'

export default defineComponent({
  name: 'ElHeader',
  props: {
    height: {
      type: String,
      default: null,
    },
  },
})
</script>

header.scss

@import 'mixins/mixins';
@import 'common/var';

:root {
  --el-header-padding: 0 20px;
  // 全局css变量,指定header的默认高度
  --el-header-height: 60px;
}

@include b(header) {
  padding: var(--el-header-padding);
  box-sizing: border-box;
  flex-shrink: 0;
  // 通过css变量调整高度
  height: var(--el-header-height);
}

注: footer/aside的代码实现与header完全一致,不再单独细述

2.3 main组件代码

main.vue

<template>
  // 原生main标签
  <main class="el-main">
    // 默认插槽
    <slot></slot>
  </main>
</template>
<script lang="ts">
import { defineComponent } from 'vue'

export default defineComponent({
  name: 'ElMain',
})
</script>

main.scss

@import 'mixins/mixins';
@import 'common/var';

:root {
  --el-main-padding: 20px;
}

@include b(main) {
  // IE11 supports the <main> element partially https://caniuse.com/#search=main
  display: block;
  // 占满剩余空间
  flex: 1;
  flex-basis: auto;
  overflow: auto;
  box-sizing: border-box;
  padding: var(--el-main-padding);
}

2.4 总结:

  1. container/header/footer/aside/main 内部都使用了对应的html5原生标签,具有语义化;
  2. container采用flex布局;
  3. 通过style属性动态设置css局部变量值,覆盖css全局变量,起到动态调整样式的效果。