超详细 ElementUI 源码分析 —— Layout

2,393 阅读2分钟

Layout 是用来快速布局的组件,本质上是和 Bootstrap 的栅格系统(真的很牛批,建议看一下它的源码)一样,将每一行分成 24 个小块,每一个小块就是一列,通过指定合并的列数来创建布局,本文就 ElementUI 的 Layout 布局进行了分析。

Layout 布局

首先我们来分析一下问什么要使用 Layout?

  • 我们在写原生 HTML 甚至是在使用 Vue 模板时,会使用div对每个模块进行分割,但是通篇的div会使我们的代码语义不清,H5 就要求我们使用标签语义化,但即便是使用了标签语义化,有一些地方还是会显得模糊不清,而且在样式上也难以维护。
  • 对于简单的布局我们不希望每次都需要自己来写,如果有一个模板快速帮我们实现布局就好了。

基于以上理由,Layout 就出现了,它能做什么?

  • 快速布局
  • 响应式布局

这里就不说使用了,具体使用请参考官方文档

Layout 布局分为两个组件:row 和 col

参数

关于 row 的参数请参考

col 参数请参考

间隔

关于 row 组件最重要的部分就是栅格间隔gutter,也就是每一个分栏之间的距离,看源码:

computed: {
  style () {
    const ret = {}

    // 如果传入了 gutter
    if (this.gutter) {
      // 向左移动间隔的一半
      ret.marginLeft = `-${this.gutter / 2}px`
      // 向右移动间隔的一半
      ret.marginRight = ret.marginLeft
      // 
    }

    return ret
  }
}

首先gutter是由每一列自身的padding产生的,在col.js中可以看出来,paddinggutter的一半。假如间隔为 20px,列的padding:0 10px,所以两列之间就产生了 20px 的间隔,这个很好理解。

那么row.js中为什么要给 row 组件添加一个margin呢,熟悉 Bootstrap 的小伙伴应该知道,这是考虑了在「列中嵌套行」的情况,如果在行中不加margin就会导致有某些列的间隔大于预期,比如说下面的代码结构

<el-row :gutter="20" type="flex" justify="end">
  <el-col :span="6">
    <el-row :gutter="10">
      <el-col :span="12"><div class="grid-content bg-purple"></div></el-col>
      <el-col :span="12"><div class="grid-content bg-purple"></div></el-col>
    </el-row>
  </el-col>
  <el-col :span="6"><div class="grid-content bg-purple"></div></el-col>
  <el-col :span="6"><div class="grid-content bg-purple"></div></el-col>
  <el-col :span="6"><div class="grid-content bg-purple"></div></el-col>
</el-row>

在第一列中嵌套了一行,这一行里又有两列,看渲染出来的效果图:

可以看出来,外面的大间隔为 20px,第一列的小间隔为 10px,现在把margin去了看一下对比:

可以明显发现第一大列的左右都增加了 5px,这样就破坏了原有的gutter值,使得布局不符合预期,这就是margin的精妙之处。

渲染函数

然后我们看一下渲染函数。

移步官网查看渲染函数的详细介绍

// 渲染函数
render (h) {
  return h(
    // 默认渲染的是一个 div
    this.tag,
    {
      // 相当于模板中的 :class
      class: [
        'el-row',
        // 如果 flex 布局不是默认的值,就会加上 .is-justify-
        // 就是加上了 justify-content: flex-end
        this.justify !== 'start' ? `is-justify-${this.justify}` : '',
        this.align !== 'top' ? `is-align-${this.align}` : '',
        // 如果开启了 flex 布局模式,则会加上 .el-row--flex
        // 就是加上了 display: flex
        { 'el-row--flex': this.type === 'flex' }
      ],
      style: this.style
    },
    // 子集虚拟节点
    this.$slots.default
  )
}

我们注意到 row 组件 和 col 组件中没有提供模板,而是使用渲染函数来创建的 HTML 结构,这样做能让我们更好的处理细节。

关于col.js里面的东西主要是为了添加组件的样式,通过父组件传递的属性动态添加 class,Layout 布局主要部分也就是 CSS 了,所以本文先不详述了,后期会单独分析样式文件,感兴趣的可以先关注一波。源码所有的解释在我的Github里,欢迎进来点个 star。

传送门

【2020.3.15】超详细 ElementUI 源码分析 —— Layout