一天一个 Element 组件 - Row & Col
source link: https://shiningdan.github.io/2020/01/12/%E4%B8%80%E5%A4%A9%E4%B8%80%E4%B8%AA-Element-%E7%BB%84%E4%BB%B6-Row-Col/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
本文是 Element 的组件源码学习系列。
项目源码:ElemeFE/element | GitHub,Tag:v2.13.0
Row & Col 组件使用文档:Layout 布局
.vue 文件:/packages/col
.vue 文件:/packages/row
.scss 文件:/packages/theme-chalk/col.scss
.scss 文件:/packages/theme-chalk/row.scss
.d.ts 文件:/types/col.d.ts
.d.ts 文件:/types/row.d.ts
Props
首先我们来看一下 el-row
的 Props,了解使用这个组件的入参:
{ |
首先,看这个组件使用的是 render
方法,还是之前比较流行的写法,现在的模板大部分都使用 template
标签了。
tag
是用来自定义元素标签的,默认情况下使用的是 <div>
元素。
el-row
和 el-col
本质上是 CSS flexbox
的属性封装,所以能使用 flexbox
的标签,都可以作为 tag
属性传入,来替换 <div>
元素。常见的场景,是 C 端 SEO,要提供语义化的 HTML 标签,这个使用就可以使用 tag
gutter
gutter
用来指定每一栏之间的间隔,默认是 0。
在 el-row
上设置了 gutter
属性后,会影响该 row
下面所有 el-col
元素,我们来看一下怎么实现的:
首先,我们来看一下 el-col
的相关代码:
computed: { |
一个 el-row
组件的 gutter
属性,是通过它的父元素,或者祖先元素中最近的一个 el-row
组件决定的。首先,拿到最近的 el-row
组件,然后获得该组件的 gutter
配置。
在渲染的时候,由于 gutter
指的是两个 col
组件之间的总距离,所以映射到每一个 el-col
上,设置为 padding-left
和 padding-right
分为为二分之一。
注意!!如果第一个 el-col 的左侧也有二分之一 gutter 的长度,是不符合我们的预期的。因为第一个 el-col
应该是最左边没有边距的。
所以我们需要在 el-row
上面做文章,将第一个 el-col
的 paddingLeft
抵消掉。由于 padding
的值,不能设置为负数,参考 padding | MDN,所以我们只能将 el-row
的外边距设置为负数,来抵消第一个 el-col
的 paddingLeft
:
computed: { |
我本人对于 gutter
在 el-col
上的实现方案,有一些疑问。我觉得 gutter
的实现方案,在 el-col
上,应该使用 marginLeft
和 marginRight
。因为如果对 el-col
设置了背景颜色的话,使用 padding
的实现方法,间隔栏也会被染色,这个是不符合预期的。
当然这个问题也很好解决。需要我们对 el-col
的定位,是负责布局控制。而业务相关的设置,比如背景颜色,不应该直接设置在 el-col
上,而是在 el-col
中再包裹 div
元素,设置在 div
元素上,则间隔栏就不会被染色了。
span & offset & pull & push
span
属性是用来控制一个 el-col
栅格的宽度的。我们来看一下实现方案:
['span', 'offset', 'pull', 'push'].forEach(prop => { |
这里把 span & offset & pull & push
放在一起写,是因为这几个属性,背后的原理都是一样的,控制 HTML 元素的 CSS 属性。下面我们来一起看一下相关的 SCSS 实现:
[class*="el-col-"] { |
我们来依次看下:
- 所有的
el-col
都设置了float: left
,来实现在一个el-row
中从左到右的顺序排列。并且设置了box-sizing: border-box
,这样方便对于宽度进行较为精确的控制,不会受到padding
和border
的宽度影响。 span
值的实现,当等于0
的时候,实现方案是display: none
。当不等于 0 的时候,通过width
设置的百分比。offset
是通过 margin 来实现的偏移量。
type=flex
通过在 el-row
上设置 type=flex
,可以使用 flexbox 的布局能力。我们来看一下具体的实现方案:
render(h) { |
即,通过设置 type=flex
来开启 flexbox
布局,然后设置 justify
来配置 CSS justify-content
属性,以及 设置 align
来配置 align-items
属性。
@include m(flex) { |
响应式布局
参照了 Bootstrap 的 响应式设计,预设了五个响应尺寸:xs
、sm
、md
、lg
和 xl
。
我们来看一下怎么实现的:
['xs', 'sm', 'md', 'lg', 'xl'].forEach(size => { |
我们用 xs
属性来举例。
xs:<768px
响应式栅格数或者栅格属性对象
首先,当 el-col
设置了 xs
属性后,通过上面的 JS 代码,给 el-col
添加了相关的 CSS 类。我们来看一下这个类是怎么实现的呢。
@include res(xs) { |
在这个 @include
里面,好像和 span
的设置没有什么不同,都是对于 el-col
的宽度进行修改。那 xs
的设置,如何触发祥响应式相关的设置呢?关键在 res(xs)
的 res
这个函数上。
在 col.scss
中,一开始引入了两个文件:
@import "./common/var.scss"; |
res
函数的定义就可以在这两个文件中找到:
// ./mixins/mixins.scss |
当调用 res(xs)
的时候,$key
就是 xs
,$map
使用的是默认值 $--breakpoints
,也就是 ./common/var.scss
中预先定义的响应式布局中常用的几种宽度。然后 res
函数会通过设置 @media only screen
的 CSS 属性,来实现响应式的能力。所以,el-col
的实现,本质上也是通过设置 @media
属性来实现的。
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK