0x00 简介

前文分析过组件的 布局栅格化(Grid Layout) ,通过基础的 24 分栏,迅速简便地创建布局。

本文将介绍用于布局的容器组件,使用 Flexbox 功能将其所控制区域设定为特定的布局,方便快速搭建页面的基本结构。本文将深入分析组件源码,剖析其实现原理,耐心读完,相信会对您有所帮助。 组件文档

更多组件剖析详见 Element 2 源码剖析组件总览

0x01 布局容器

布局容器提供5个组件,支持多层嵌套,方便快速搭建页面的基本结构:

  • <el-container>:布局容器,其下可嵌套 <el-header> <el-footer> <el-aside> <el-main> 或 <el-container> 本身,可以放在任何父容器中。当子元素中包含 <el-header> 或 <el-footer> 时,全部子元素会垂直上下排列,否则会水平左右排列。
  • <el-header>:顶部容器,其下可嵌套任何元素,只能放在 <el-container> 中。
  • <el-aside>:侧边栏容器,其下可嵌套任何元素,只能放在 <el-container> 中。
  • <el-main>:主要区域容器,其下可嵌套任何元素,只能放在 <el-container> 中。
  • <el-footer>:底部容器,其下可嵌套任何元素,只能放在 <el-container> 中。

以上组件采用了 flex 布局,使用前请确定目标浏览器是否兼容。此外,<el-container> 的子元素只能是后四者,后四者的父元素也只能是 <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>

0x02 代码实现

container 布局容器

组件 container 封装了 <section>元素,包含没有后备内容(默认值)的匿名插槽 。组件定义了direction的 prop 属性,用于子元素的排列方向。

// packages\container\src\main.vue
<template>
<section class="el-container" :class="{ 'is-vertical': isVertical }">
<slot></slot>
</section>
</template>
<script>
export default {
name: 'ElContainer',
componentName: 'ElContainer',
props: {
direction: String
},
computed: {
isVertical() {
// ...
}
}
};
</script>

若没有定义了direction属性值,组件通过tag判断子元素中包含 <el-header> 或 <el-footer> 时,全部子元素会垂直上下排列,否则会水平左右排列。 componentOptions类型定义

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;
}
}

header 顶部容器

组件 header 封装了 <header>元素,包含一个 slot 。组件定义了height的 prop 属性,设置顶部容器高度,默认值60px

// packages\header\src\main.vue
<template>
<header class="el-header" :style="{ height }">
<slot></slot>
</header>
</template>
<script>
export default {
name: 'ElHeader',
componentName: 'ElHeader',
props: {
height: {
type: String,
default: '60px'
}
}
};
</script>

aside 侧边栏容器

组件 aside 封装了 <aside>元素,包含一个 slot 。组件定义了width的 prop 属性,设置侧边栏宽度,默认值300px

// packages\aside\src\main.vue
<template>
<aside class="el-aside" :style="{ width }">
<slot></slot>
</aside>
</template>
<script>
export default {
name: 'ElAside',
componentName: 'ElAside',
props: {
width: {
type: String,
default: '300px'
}
}
};
</script>

main 主要区域(内容)容器

组件 main 封装了 <main>元素,包含一个 slot 。

// packages\main\src\main.vue
<template>
<main class="el-main">
<slot></slot>
</main>
</template>
<script>
export default {
name: 'ElMain',
componentName: 'ElMain'
};
</script>

footer 底部容器

组件 footer 封装了 <footer>元素,包含一个 slot。组件定义了height的 prop 属性,设置顶部容器高度,默认值60px

// packages\footer\src\main.vue
<template>
<footer class="el-footer" :style="{ height }">
<slot></slot>
</footer>
</template>
<script>
export default {
name: 'ElFooter',
componentName: 'ElFooter',
props: {
height: {
type: String,
default: '60px'
}
}
};
</script>

0x03 组件样式

组件样式源码使用 scss 的混合指令 b、 when 嵌套生成组件样式。

// packages\theme-chalk\src\common\var.scss
$--header-padding: 0 20px !default;
$--footer-padding: 0 20px !default;
$--main-padding: 20px !default; // packages\theme-chalk\src\container.scss
@include b(container) {
display: flex;
flex-direction: row;
flex: 1;
flex-basis: auto;
box-sizing: border-box;
min-width: 0; @include when(vertical) {
flex-direction: column;
}
} // packages\theme-chalk\src\header.scss
@include b(header) {
padding: $--header-padding;
box-sizing: border-box;
flex-shrink: 0;
} // packages\theme-chalk\src\footer.scss
@include b(footer) {
padding: $--footer-padding;
box-sizing: border-box;
flex-shrink: 0;
} // packages\theme-chalk\src\main.scss
@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;
} // packages\theme-chalk\src\aside.scss
@include b(aside) {
overflow: auto;
box-sizing: border-box;
flex-shrink: 0;
}

使用 gulpfile.js编译 scss 文件转换为CSS,经过浏览器兼容、格式压缩,最后生成样式内容如下。

/* packages\theme-chalk\lib\container.css */
.el-container {
display: flex;
flex-direction: row;
flex: 1;
flex-basis: auto;
box-sizing: border-box;
min-width: 0;
} .el-container.is-vertical {
flex-direction: column;
} /* packages\theme-chalk\lib\main.css */
.el-main {
display: block;
flex: 1;
flex-basis: auto;
overflow: auto;
box-sizing: border-box;
padding: 20px;
} /* packages\theme-chalk\lib\aside.css */
.el-aside {
overflow: auto;
box-sizing: border-box;
flex-shrink: 0;
} /* packages\theme-chalk\lib\header.css */
.el-header {
padding: 0 20px;
box-sizing: border-box;
flex-shrink: 0;
} /* packages\theme-chalk\lib\footer.css */
.el-footer {
padding: 0 20px;
box-sizing: border-box;
flex-shrink: 0;
}

容器布局实现使用 CSS Flexbox,flex-basisflex-shrinkflex 等属性的语法内容请阅读 Flex 布局教程:语法篇 阮一峰

前文曾提到<el-container> 的子元素只能是后四者,后四者的父元素也只能是 <el-container>。因为 只有container 组件指定为 Flex 布局,其余组件若是想要Flex 布局生效,只能将组件作为 container 的子组件,当然 container 可以自包含。

0x04 关注专栏

此文章已收录到专栏中 ,可以直接关注。

Element 2 组件源码剖析之布局容器的更多相关文章

  1. Rest_Framework之认证、权限、频率组件源码剖析

    一:使用RestFramwork,定义一个视图 from rest_framework.viewsets import ModelViewSet class BookView(ModelViewSet ...

  2. 转 Spring源码剖析——核心IOC容器原理

    Spring源码剖析——核心IOC容器原理 2016年08月05日 15:06:16 阅读数:8312 标签: spring源码ioc编程bean 更多 个人分类: Java https://blog ...

  3. STL源码剖析——序列式容器#4 Stack & Queue

    Stack stack是一种先进后出(First In Last Out,FILO)的数据结构,它只有一个出口,元素的新增.删除.最顶端访问都在该出口进行,没有其他位置和方法可以存取stack的元素. ...

  4. STL源码剖析——序列式容器#2 List

    list就是链表的实现,链表是什么,我就不再解释了.list的好处就是每次插入或删除一个元素,都是常数的时空复杂度.但遍历或访问就需要O(n)的时间. List本身其实不难理解,难点在于某些功能函数的 ...

  5. STL源码剖析——序列式容器#1 Vector

    在学完了Allocator.Iterator和Traits编程之后,我们终于可以进入STL的容器内部一探究竟了.STL的容器分为序列式容器和关联式容器,何为序列式容器呢?就是容器内的元素是可序的,但未 ...

  6. STL源码剖析——序列式容器#3 Deque

    Deque是一种双向开口的连续线性空间.所谓的双向开口,就是能在头尾两端分别做元素的插入和删除,而且是在常数的时间内完成.虽然Vector也可以在首端进行元素的插入和删除(利用insert和erase ...

  7. STL源码剖析——序列式容器#5 heap

    准确来讲,heap并不属于STL容器,但它是其中一个容器priority queue必不可少的一部分.顾名思义,priority queue就是优先级队列,允许用户以任何次序将任何元素加入容器内,但取 ...

  8. Spring源码剖析依赖注入实现

    Spring源码剖析——依赖注入实现原理 2016年08月06日 09:35:00 阅读数:31760 标签: spring源码bean依赖注入 更多 个人分类: Java   版权声明:本文为博主原 ...

  9. Node 进阶:express 默认日志组件 morgan 从入门使用到源码剖析

    本文摘录自个人总结<Nodejs学习笔记>,更多章节及更新,请访问 github主页地址.欢迎加群交流,群号 197339705. 章节概览 morgan是express默认的日志中间件, ...

随机推荐

  1. NMS技术总结(NMS原理、多类别NMS、NMS的缺陷、NMS的改进思路、各种NMS方法)

    ​  前言  本文介绍了NMS的应用场合.基本原理.多类别NMS方法和实践代码.NMS的缺陷和改进思路.介绍了改进NMS的几种常用方法.提供了其它不常用的方法的链接. 本文很早以前发过,有个读者评论说 ...

  2. 【FAQ】申请华为运动健康服务授权的4个常见问题及解决方法

    华为运动健康服务(HUAWEI Health Kit)提供原子化数据开放,在获取用户对数据的授权后,应用可通过接口访问运动健康数据,对用户数据进行增.删.改.查等操作,为用户提供运动健康类数据服务.这 ...

  3. 分布式下Session一致性问题

    一.Session一致性问题 1.1 什么是Session 用户使用网站的服务,基本上需要浏览器和web服务器进行多次交互,web服务器如何知道哪些请求是来自哪个会话的? 具体方式为:在会话开始时,分 ...

  4. 482. License Key Formatting - LeetCode

    Question 482. License Key Formatting Solution 思路:字符串转化为char数组,从后遍历,如果是大写字母就转化为小写字母,如果是-就忽略,如果遍历了k个字符 ...

  5. 理解RESTful Api设计

    REST REST(REpresentational State Transfer)是 Roy Fielding 博士于 2000 年在他的博士论文中提出来的一种软件架构风格(一组架构约束条件和原则) ...

  6. ES6 Promise 的链式调用

    1.什么是Promise Promise 对象代表了未来将要发生的事件,用来传递异步操作的消息. 2.对象的状态不受外界影响.Promise 对象代表一个异步操作,有三种状态: pending: 初始 ...

  7. [USACO16JAN]Angry Cows G 解题报告

    一图流 参考代码: #include<bits/stdc++.h> #define ll long long #define db double #define filein(a) fre ...

  8. 两个月吃透阿里P9推荐260页SpringBoot2企业应用实战pdf入职定P6+

    前言 Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程.该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置 ...

  9. 人脸识别库 face_recognition

    face_recognition Windows系统环境下安装 默认环境:anaconda的python3.7版本,win10环境 第一步:安装dlib 从网络上下载: http://dlib.net ...

  10. 最短路之 Dijkstra 算法

    普通的 Dijkstra 这是一种运用贪心的单源最短路算法,就是求从一个节点出发,到任意一个点的最短距离 首先我们要一个图 假设要求从 1 开始的单源最短路 dis[] 表示最短路数组, vis[] ...