preface

In the last article we looked at the design and implementation of the Layout component, which is usually used in a local Layout. For the layout of the entire page, Element-UI provides the Container layout Container component, which is used to manage the overall layout of background pages on PCS.

Demand analysis

Let’s take a look at a common layout of a page with a few diagrams.

The layout of these two diagrams is common in background systems and can be implemented with simple CSS. However, we prefer to use component-based development, encapsulating these CSS details in components, as follows:

<el-container>
  <el-header>Header</el-header>
  <el-main>Main</el-main>
  <el-footer>Footer</el-footer>
</el-container>

<el-container>
  <el-header>Header</el-header>
  <el-container>
    <el-aside width="200px">Aside</el-aside>
    <el-container>
      <el-main>Main</el-main>
      <el-footer>Footer</el-footer>
    </el-container>
  </el-container>
</el-container>
Copy the code

We used

,

,

,

, and

.





  • : indicates the outer container. When a child element contains

    or

    , all child elements are arranged vertically up and down, otherwise horizontally left and right.



  • : top column container.


  • : side bar container.


  • : Primary region container.


  • : bottom container.

These components must comply with the following constraints:

The child element of

can only be the last four, and the parent element of the last four can only be < el-Container >.

With an understanding of the requirements for the element-UI Container layout Container components, let’s examine its design and implementation.

Design and implementation

The graphical layout can be easily implemented using Flex layout, and the Element-UI is also based on Flex layout. Let’s look at the implementation of each component.

ElContainer components

Let’s start with the template section:

<template>
  <section class="el-container">
    <slot></slot>
  </section>
</template>
Copy the code

The

component renders as a

tag and distributes content by slot.

Take a look at the CSS section again:

@include b(container) {
  display: flex;
  flex-direction: row;
  flex: 1;
  flex-basis: auto;
  box-sizing: border-box;
  min-width: 0;
}
Copy the code

Focusing on the CSS section, display:flex creates a Flex container with flex-direction:row specifying that the internal elements are arranged horizontally. The reason for flex:1 is that

supports nesting, and we know that flex:1 equals flex-grow:1; flex-shrink:1; Flex-basis :0, that is, when

is nested, it fills up the remaining space. Flex-basis :auto indicates that the parent container will reserve its own content size before allocating space, and then the remaining space will be added to the remaining space.


The container is horizontal by default, but also needs to support vertical alignment. We can provide a prop in the direction of the component. If the direction passed in is vertical, add the corresponding CSS.

<template>
  <section class="el-container" :class="{ 'is-vertical': isVertical }">
    <slot></slot>
  </section>
</template>
Copy the code
export default {
  name: 'ElContainer'.componentName: 'ElContainer'.props: {
    direction: String
  },

  computed: {
    isVertical() {
      if (this.direction === 'vertical') {
        return true;
      } else if (this.direction === 'horizontal') {
        return false; }}}};Copy the code
@include when(vertical) {
  flex-direction: column;
}
Copy the code

If the direction passed in is vertical, add is-vertical CSS, and finally change flex-direction:column to make the internal elements aligned vertically.

Recall a previous requirement: When

or

is a child element of the < el-Container >, all child elements are vertically up and down, otherwise horizontally left to right.

It is also easy to implement by extending the evaluation criteria for the attribute isVertical:

computed: {
  isVertical() {
    if (this.direction === 'vertical') {
      return true;
    } else if (this.direction === 'horizontal') {
      return false;
    }
    return this.$slots && this.$slots.default
     ? this.$slots.default.some(vnode= > {
       const tag = vnode.componentOptions && vnode.componentOptions.tag;
       return tag === 'el-header' || tag === 'el-footer';
     })
     : false; }}Copy the code

This.$slots.default fetches all the vNodes in the default slot and iterates over them. Via vnode.com ponentOptions. The tag is to judge the vnode < el – the header > or < el – footer >. Vnode.componentoptions is not in the official website API, but for those who read Vue source code is not unfamiliar.

ElHeader components

Let’s take a look at the template section:

<template>
  <header class="el-header">
    <slot></slot>
  </header>
</template>
Copy the code

The

component renders as a

label and distributes content by slot.

Take a look at the CSS section again:

@include b(header) {
  padding: $--header-padding;
  box-sizing: border-box;
  flex-shrink: 0;
}
Copy the code

Where $- the header – padding is a variable, in the packages/theme – chalk/SRC/common/var. SCSS defined in the file. Flex-shrink: 0 indicates that the space occupied by

does not shrink even if there is insufficient space.

Generally, headers have a fixed height, so

allows you to pass in a height props to specify the height, or provide a default height if not specified.

<template>
  <header class="el-header" :style="{ height }">
    <slot></slot>
  </header>
</template>
Copy the code
export default {
  name: 'ElHeader'.componentName: 'ElHeader'.props: {
    height: {
      type: String.default: '60px'}}};Copy the code

Since the style is passed directly through the :style setting, the height must be passed in units.

ElMain components

Let’s take a look at the template section:

<template>
  <main class="el-main">
    <slot></slot>
  </main>
</template>
Copy the code

The

component is rendered as a


tag and content is distributed by slot.

Take a look at the CSS section again:

@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: $--main-padding;
}
Copy the code

Note that the


tag is partially supported in IE11. Usually the content wrapped in

is entirely determined by its children, so the height and width are not set, but the remaining space of the < el-Container > container is allocated via Flex :1.

ElFooter components

Let’s take a look at the template section:

<template>
  <footer class="el-footer">
    <slot></slot>
  </footer>
</template>
Copy the code

The

component renders as a

tag and distributes content through slot.

Take a look at the CSS section again:

@include b(footer) {
  padding: $--footer-padding;
  box-sizing: border-box;
  flex-shrink: 0;
}
Copy the code

As with the header, there is usually a fixed height at the bottom, so

allows you to pass in a height props to specify the height, or provide a default height if not specified.

<template>
  <footer class="el-footer" :style="{ height }">
    <slot></slot>
  </footer>
</template>
Copy the code
export default {
  name: 'ElFooter'.componentName: 'ElFooter'.props: {
    height: {
      type: String.default: '60px'}}};Copy the code

ElAside components

Let’s take a look at the template section:

<template>
  <aside class="el-aside">
    <slot></slot>
  </aside>
</template>
Copy the code

The

component is rendered as an

Take a look at the CSS section again:

@include b(aside) {
  overflow: auto;
  box-sizing: border-box;
  flex-shrink: 0;
}
Copy the code

The

component is used to render the sidebar, and the sidebar usually has a width, so

allows you to pass in a width props to specify the width, or a default width if not specified.

<template>
  <aside class="el-aside" :style="{ width }">
    <slot></slot>
  </aside>
</template>
Copy the code
export default {
  name: 'ElAside'.componentName: 'ElAside'.props: {
    width: {
      type: String.default: '300px'}}};Copy the code

conclusion

The implementation of element-UI’s Container layout is simple: create semantic labels, use slots for content distribution, and use Flex for layout.

By the end of this article, you can review flex layout, HTML5 semantic tags, deepen your understanding, and learn some tips from Vue source code.

If you can’t learn something, you will make progress. If you think this kind of article is helpful, you are welcome to recommend it to your friends.

Next up: Element-UI Technology Revealed (5) Colors, fonts, borders, and ICONS.

In addition, I just opened a public account “Lao Huang’s front-end private dishes”, “Element-UI Technology Secrets” series articles will be updated and released on the public account for the first time, in addition, I will often share some front-end advanced knowledge, dry goods, and occasionally share some soft quality skills, welcome everyone to pay attention to oh ~