概述
ElementUI
源码学习 - Layout布局(row 、col)
row.js
该组件不同于button
组件,是一个js
文件,使用的是render
方法
export default {
name: 'ElRow', //组件名字,作用在 button 组件中,已经说明了
componentName: 'ElRow', //这个在 col 组件中判断 是否为 col 的父组件,从而给 gutter 间隔
props: {
tag: { //自定义元素标签, tag 在 render 函数中定义元素标签,
//题外话 在vue中使用 is 也是可以改变元素标签的 ps: <p is="span"></p> 在控制台是span标签
//场景:C端 SEO,要提供语义化的 HTML 标签,这个时候可以使用 tag
type: String,
default: 'div'
},
gutter: Number, //间隔大小
type: String, // 布局模式,可选 flex,
justify: { // flex 布局下的水平排列方式
type: String,
default: 'start'
},
align: { //flex 布局下的垂直排列方式
type: String,
default: 'top'
}
},
computed: {
style() {
const ret = {};
if (this.gutter) {
ret.marginLeft = `-${this.gutter / 2}px`;
ret.marginRight = ret.marginLeft;
}
return ret;
}
},
render(h) { //render 函数
return h(this.tag, {
class: [
'el-row',
this.justify !== 'start' ? `is-justify-${this.justify}` : '',
this.align !== 'top' ? `is-align-${this.align}` : '',
{ 'el-row--flex': this.type === 'flex' } //是否为 flex 布局
],
style: this.style //object 样式 由计算属性得出
}, this.$slots.default); //插入默认插槽
}
};
[注]
1、计算属性中的
style
==》ret.marginLeft
=-${this.gutter / 2}px
;是为负值的margin
,这样处理是为了 处理 第一个和最后一个col
的padding
值,因为padding
是不可以为负值的,所以采用row
的外边距为负值来抵消 第一和最后一个col
的padding
2、可能
element
对于col
的定位是作为布局,不然要是在col
设置背景色,padding
也是会显示其背景色的,解决方案就是在col
之下增加元素,将其背景色设置在子元素上面,比如element
官方例子3、render函数传送门
4、布局实现
flexbox
,样式如下
@include m(flex) {
display: flex;
&:before,
&:after {
display: none;
}
@include when(justify-center) {
justify-content: center;
}
@include when(justify-end) {
justify-content: flex-end;
}
@include when(justify-space-between) {
justify-content: space-between;
}
@include when(justify-space-around) {
justify-content: space-around;
}
@include when(align-middle) {
align-items: center;
}
@include when(align-bottom) {
align-items: flex-end;
}
}
col.js
export default {
name: 'ElCol',
props: {
span: {
type: Number,
default: 24
},
tag: {
type: String,
default: 'div'
},
offset: Number,
pull: Number,
push: Number,
xs: [Number, Object], // 响应式栅格数或者栅格属性对象
sm: [Number, Object], // (例如: {span: 4, offset: 4}) 同下
md: [Number, Object],
lg: [Number, Object],
xl: [Number, Object]
},
computed: {
gutter() {
let parent = this.$parent;
while (parent && parent.$options.componentName !== 'ElRow') {
/*parent.$options.componentName 也就是 row 中的 componentName
迭代:直到找到父元素是 Row 并且获取 Row 的 gutter 属性
*/
parent = parent.$parent;
}
return parent ? parent.gutter : 0;
}
},
render(h) {
let classList = [];
let style = {};
if (this.gutter) { //由计算属性而来,也是通过 row 的 gutter 的值而来
style.paddingLeft = this.gutter / 2 + 'px';
style.paddingRight = style.paddingLeft;
/*采用padding达到间隔效果*/
}
['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]}`
);
}
});
['xs', 'sm', 'md', 'lg', 'xl'].forEach(size => {
if (typeof this[size] === 'number') {
classList.push(`el-col-${size}-${this[size]}`);
} else if (typeof this[size] === 'object') {
let props = this[size];
Object.keys(props).forEach(prop => {
classList.push(
prop !== 'span'
? `el-col-${size}-${prop}-${props[prop]}`
: `el-col-${size}-${props[prop]}`
);
});
}
});
return h(this.tag, {
class: ['el-col', classList],
style
}, this.$slots.default);
}
};
【注】
1、
['span', 'offset', 'pull', 'push']
放在一起都是为了控制其css
,如下为其css
实现
/*所有的 col 都设置 float: left;来实现了 el-row 从左到右的顺序排列,并且设置了 `box-sizing: border-box` ,这样方便对于宽度进行较为精确的控制,不会受到 padding 和 border 的宽度影响。
*/
[class*="el-col-"] {
float: left;
box-sizing: border-box;
}
/*
span 值的实现,当等于 0 的时候,实现方案是 display: none。当不等于 0 的时候,通过 width 设置的百分比。
*/
.el-col-0 {
display: none;
}
/*在 Sass 中,可以使用 @for 循环来完成
@for $i from <start> through <end>
@for $i from <start> to <end>
$i 表示变量
start 表示起始值
end 表示结束值
这两个的区别是关键字 through 表示包括 end 这个数,而 to 则不包括 end 这个数。
*/
@for $i from 0 through 24 {
.el-col-#{$i} {
width: (1 / 24 * $i * 100) * 1%;
}
/*offset 是通过 margin 来实现的偏移量。*/
.el-col-offset-#{$i} {
margin-left: (1 / 24 * $i * 100) * 1%;
}
/* pull 、push 都是设置的相对定位 设置 right 、left 达到移动的目的*/
.el-col-pull-#{$i} {
position: relative;
right: (1 / 24 * $i * 100) * 1%;
}
.el-col-push-#{$i} {
position: relative;
left: (1 / 24 * $i * 100) * 1%;
}
}
响应式布局
参照了
Bootstrap
的 响应式设计,预设了五个响应尺寸:xs
、sm
、md
、lg
和xl
。以及分成了 24 小块,Bootstrap
原先是12块,element
增加至24,因为 24 可以组合多种不同布局组合,比如 1 2 3 4 6 8 12 这些组合,能最大限度的满足布局需求
PS:
=>>>>>xs
:<768px
响应式栅格数或者栅格属性对象
@include res(xs) {
.el-col-xs-0 {
display: none;
}
@for $i from 0 through 24 {
.el-col-xs-#{$i} {
width: (1 / 24 * $i * 100) * 1%;
}
.el-col-xs-offset-#{$i} {
margin-left: (1 / 24 * $i * 100) * 1%;
}
.el-col-xs-pull-#{$i} {
position: relative;
right: (1 / 24 * $i * 100) * 1%;
}
.el-col-xs-push-#{$i} {
position: relative;
left: (1 / 24 * $i * 100) * 1%;
}
}
}
[注]
在
col.scss
中,引入俩个文件@import "./common/var.scss"; // 各种变量的定义,便于以后样式的修改以及维护 @import "./mixins/mixins.scss"; //混入
res
函数的定义就可以在这俩个文件中找到
/* ./mixins/mixins.scss*/
@mixin res($key, $map: $--breakpoints) {
// 循环断点Map,如果存在则返回
@if map-has-key($map, $key) {
@media only screen and #{inspect(map-get($map, $key))} {
@content;
}
} @else {
@warn "Undefeined points: `#{$map}`";
}
}
/*./common/var.scss*/
$--breakpoints: (
'xs' : (max-width: $--sm - 1), /*只有 xs 是 max-width */
'sm' : (min-width: $--sm),
'md' : (min-width: $--md),
'lg' : (min-width: $--lg),
'xl' : (min-width: $--xl)
);
$--sm: 768px !default;
$--md: 992px !default;
$--lg: 1200px !default;
$--xl: 1920px !default;
/*
!default表示默认值。给一个未通过!default声明赋值的变量赋值,此时,如果变量已经被赋值,不会再被重新赋值;但是如果变量还没有被赋值,则会被赋予新的值。
*/
当调用 res(xs)
的时候,$key
就是 xs
,$map
使用的是默认值 $--breakpoints
,也就是 ./common/var.scss
中预先定义的响应式布局中常用的几种宽度。然后 res
函数会通过设置 @media only screen
的 CSS 属性,来实现响应式的能力。所以,el-col
的实现,本质上也是通过设置 @media
属性来实现的。
最后
以上就是含蓄钢笔为你收集整理的ElementUI源码学习 - Layout布局(row 、col)的全部内容,希望文章能够帮你解决ElementUI源码学习 - Layout布局(row 、col)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复