系列文章目录
第一章 element源码(一)简要介绍
第二章 element源码(二)Layout 布局组件
文章目录
- 系列文章目录
- 一、layout布局组件介绍
- 二、组件组成
- 三、组件按需导入
- 四、col组件
- 五、row组件
- 六、组件的属性 feature
- 1.span
- 2.gutter
- 3.对齐方式
- 总结
一、layout布局组件介绍
是响应式布局的常见方式。官方介绍是 ”通过基础的 24 分栏,迅速简便地创建布局“,也很好理解。
二、组件组成
el-row,el-col两个组件,然后简单介绍一下element源码的组件结构。所有组件放在packages文件夹下,下属每一个文件夹对应element中的组件。然后组件文件夹结构分src和index,src下是组件代码,index引入并定义函数注册组件,主要是为了实现element的按需导入。
三、组件按需导入
先看一下index.js
源码
import ElCol from './src/col';
/* istanbul ignore next */
ElCol.install = function(Vue) {
Vue.component(ElCol.name, ElCol);
};
export default ElCol;
从src中引入col组件代码,然后定义install
方法(vue的知识不了解的看一下源码),该方法中注册了全局的组件el-col。在vue的main.js中使用Vue.use(Component)
会调用install方法注册全局的组件,就实现了组件的按需导入
四、col组件
先看一下/src/col.js
源码
render (h) {
//这里删除了一些属性上的处理,先理解基础的结构
return h(this.tag, {
class: ['el-col', classList],
style
}, this.$slots.default);
}
简单介绍一下vue的render函数参数h方法,h(标签名,属性,内容)。这里内容this.$slots.default
,涉及到slot插值的知识,<slot></slot>
也是具名插槽知识默认为default,等同于<slot name="default"></slot>
在render函数中定义,与在template中定义差不多,使用template最后也会转换成render,所以vue也支持直接用render定义组件。这里element用render主要是为了this.tag可以自定义
<template>
<div class="el-col">
<slot></slot>
</div>
</template>
如果template定义,tag只能是div,用父组件用props传tag就可以自定义tag,默认为div
props: {
tag: {
type: String,
default: 'div'
},
},
五、row组件
与el-col组件相同,不做详细介绍
六、组件的属性 feature
element在组件上定义了很多属性,实现组件的个性化也扩展了组件的使用。有文章称之为feature特征,下面我挑一些常用的feature解析,达到学习element编程思路的目的即可,有时间我会把所有feature的解析做全
1.span
官方介绍”栅格占据的列数“。挺好理解的,总共24份:span="1"就是占1/24
老规矩,先看一下src/col
源码
props: {
span: {
type: Number,
default: 24
},
...//文中省略号,均是与当前解析不相关的;以后不再赘述
},
render(h) {
let classList = [];
let style = {};
...
['span', 'offset', 'pull', 'push'].forEach(prop => {
if (this[prop] || this[prop] === 0) {
classList.push(
prop !== 'span'
? `el-col-${prop}-${this[prop]}`
: `el-col-${this[prop]}`
);
}
});
...
return h(this.tag, {
class: ['el-col', classList],
style
}, this.$slots.default);
}
这片代码就干一件事,父组件传过来的:span="1"
转化为类名el-col-1
,代码的实现过程,大家自己理解吸收一下。那现在el-col有了类型el-col-1还不够,还要定义类名样式.el-col-1{width:4%}
。
下面给大家介绍一下element对样式的处理,样式源码都在/package/theme-chalk/src
下面基本上可以找到组件对应的文件,例如col.scss
先看一下col.scss
源码
[class*="el-col-"] {
float: left;
box-sizing: border-box;
}
.el-col-0 {
display: none;
}
@for $i from 0 through 24 {
.el-col-#{$i} {
width: (math.div(1 , 24) * $i * 100) * 1%;
}
...
}
涉及到scss中@for循环,我以后开个栏目专门介绍scss,我也是在读源码的同时理解了很多scss的使用,
这里就是0-24循环,$i是索引号,#{}实在类名中插值类似vue中{{}}将变量插入,这段代码编译出来就是.el-col-1到.el-col-24的样式。与col.js的处理对应上,到处就属性span就实现了。push,pull,offset都是类似的处理只是样式上是对margin的设置。
2.gutter
官方介绍"栅格间隔",el-col的间隔。
其实与上面的span很类似,就是:gutter="2"在el-col左右margin为1就可以,然后el-row再向外margin拉开1px(这个自己理解一下)。但是这里有个特殊的地方是:gutter设置在el-row上,我们看一下element是怎么处理的这种情况。
computed: {
gutter () {
let parent = this.$parent;
while (parent && parent.$options.componentName !== 'ElRow') {
parent = parent.$parent;
}
return parent ? parent.gutter : 0;
}
},
在computed中循环去找父节点一直找到根节点。拿到el-row中的gutter,没有就默认为0。
这里有看见过文章介绍可以用provide/inject
替代,el-row中provide传参,el-col中inject接收,这种方法可能更优
3.对齐方式
官方介绍:”通过 flex 布局来对分栏进行灵活的对齐“
将 type 属性赋值为 ‘flex’,可以启用 flex 布局,并可通过 justify 属性来指定 start, center, end, space-between, space-around 其中的值来定义子元素的排版方式。
这里的处理很简单根据属性传参,确定display:flex以及对齐方式。但是在scss中的处理,我感觉值得借鉴,这里element的应用了bem规范 即block__element–modifier 块__元素–修饰,然后也涉及到scss中的@mixin。
看一下三段源码
// /pages/theme-chalk/src/mixins/config.scss
$namespace: 'el';
$element-separator: '__';
$modifier-separator: '--';
$state-prefix: 'is-';
// /pages/theme-chalk/src/mixins/mixins.scss
/* BEM
-------------------------- */
@mixin b($block) {
$B: $namespace+'-'+$block !global;
.#{$B} {
@content;
}
}
@mixin e($element) {
$E: $element !global;
$selector: &;
$currentSelector: "";
@each $unit in $element {
$currentSelector: #{$currentSelector + "." + $B + $element-separator + $unit + ","};
}
@if hitAllSpecialNestRule($selector) {
@at-root {
#{$selector} {
#{$currentSelector} {
@content;
}
}
}
} @else {
@at-root {
#{$currentSelector} {
@content;
}
}
}
}
@mixin m($modifier) {
$selector: &;
$currentSelector: "";
@each $unit in $modifier {
$currentSelector: #{$currentSelector + & + $modifier-separator + $unit + ","};
}
@at-root {
#{$currentSelector} {
@content;
}
}
}
@mixin when($state) {
@at-root {
&.#{$state-prefix + $state} {
@content;
}
}
}
// /pages/theme-chalk/src/row.scss
@include b(row) {
position: relative;
box-sizing: border-box;
@include utils-clearfix;
@include m(flex) {
display: flex;
&:before,
&:after {
display: none;
}
@include when(justify-center) {
justify-content: center;
}
}
}
这里的三段代码很长,涉及到scss的东西有点多,不是很好懂。我会分析带大家一起读懂。
1,首先是/pages/theme-chalk/src/mixins/config.scss
,这就是一个config文件,用来定义4个常量,英语不好的用词典翻译一下也知道是什么意思。$namespace
名字空间el,很多element中的类名都是el-xxx就是用这个常量定义;$element-separator
和$modifier-separator
分别是bem规范中__元素分割和–修饰分割;$state-prefix
是用来确定属性的,例如el-row中的属性justify="center"会转变成类名is-center,后面详细介绍。
2,/pages/theme-chalk/src/mixins/mixins.scss
,只是@mixin处理的文件,要想弄明白element中scss的运用,就必须看懂这个文件。有四个@minx
,分别是@mixin b()
;@mixin e()
;@mixin m()
;@minxin when()
@mixin b($block) {
$B: $namespace+'-'+$block !global;
.#{$B} {
@content;
}
}
@mixin b($block){ }
block是参数@include b(row) { }
引入时block就是row。$B: $namespace+'-'+$block !global;
定义变量B:el-row。namespace就是上分文件中的el; !global就是提升变量B为全局的不仅@mixin b(){}中能使用
.#{$B} {@content;}
#{}前面解释过,@content
类似与插槽,@include b(row) {position: relative; box-sizing: border-box;
}中间的内容插入替换@content
@include b(row) {
position: relative; box-sizing: border-box;
}
// => 编译为以下
.el-row{
position: relative; box-sizing: border-box;
}
另外三个@mixin
不带大家解析,其中有一个scss@root
语法查一下文档就行,其他都能看懂
3,/pages/theme-chalk/src/row.scss
中el-row的class定义直接@include
引用mixin,
@mixin b(row) {
@include m(flex) {
@include when(justify-center) {
justify-content: center;
}
}
}
// => 编译为以下
.el-row--flex.is-justify-center {
justify-content: center;
}
父组件中传参type和justify,el-col组件设置对应的class。到此el-row中对齐方式就实现了。
总结
以上就是有关layout布局组件的解析。有一些属性没有展开细讲,大家看源码理解吸收,有不懂的欢迎交流讨论