Element 2 组件源码剖析之布局容器

虚幻大学 xuhss 158℃ 0评论

? 优质资源分享 ?

学习路线指引(点击解锁) 知识定位 人群定位
? Python实战微信订餐小程序 ? 进阶级 本课程是python flask+微信小程序的完美结合,从项目搭建到腾讯云部署上线,打造一个全栈订餐系统。
?Python量化交易实战? 入门级 手把手带你打造一个易扩展、更安全、效率更高的量化交易系统

0x00 简介

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

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

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

0x01 布局容器

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

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

以上组件采用了 flex 布局,使用前请确定目标浏览器是否兼容。此外, 的子元素只能是后四者,后四者的父元素也只能是

以下代码通过多层嵌套可以实现常用的页面布局, 更多常用布局实现详见 官方文档

<el-container>
  <el-header>Headerel-header>
  <el-container>
    <el-aside width="200px">Asideel-aside>
    <el-container>
      <el-main>Mainel-main>
      <el-footer>Footerel-footer>
    el-container>
  el-container>
el-container>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PI4JlC23-1658941722013)(https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/264f2db7f0b240a29831661a73b467df~tplv-k3u1fbpfcp-watermark.image?)]

0x02 代码实现

container 布局容器

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

// packages\container\src\main.vue

 <section class="el-container" :class="{ 'is-vertical': isVertical }">
 <slot>slot>
 section>

<script>
 export default {
 name: 'ElContainer',
 componentName: 'ElContainer',
 props: {
 direction: String
 },
 computed: {
 isVertical() {
 // ...
 }
 }
 };
script>

若没有定义了direction属性值,组件通过tag判断子元素中包含 或 时,全部子元素会垂直上下排列,否则会水平左右排列。 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 封装了 元素,包含一个 slot 。组件定义了height的 prop 属性,设置顶部容器高度,默认值60px

// packages\header\src\main.vue

 <header class="el-header" :style="{ height }">
 <slot>slot>
 header>

<script>
 export default {
 name: 'ElHeader',
 componentName: 'ElHeader',
 props: {
 height: {
 type: String,
 default: '60px'
 }
 }
 };
script>

aside 侧边栏容器

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

// packages\aside\src\main.vue

 <aside class="el-aside" :style="{ width }">
 <slot>slot>
 aside>

<script>
 export default {
 name: 'ElAside',
 componentName: 'ElAside',
 props: {
 width: {
 type: String,
 default: '300px'
 }
 }
 };
script>

main 主要区域(内容)容器

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

// packages\main\src\main.vue

 <main class="el-main">
 <slot>slot>
 main>

<script>
 export default {
 name: 'ElMain',
 componentName: 'ElMain'
 };
script>

footer 底部容器

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

// packages\footer\src\main.vue

 <footer class="el-footer" :style="{ height }">
 <slot>slot>
 footer>

<script>
 export default {
 name: 'ElFooter',
 componentName: 'ElFooter',
 props: {
 height: {
 type: String,
 default: '60px'
 }
 }
 };
script>

0x03 组件样式

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

// 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  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 布局教程:语法篇 阮一峰

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

0x04 关注专栏

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

转载请注明:xuhss » Element 2 组件源码剖析之布局容器

喜欢 (0)

您必须 登录 才能发表评论!