Layout 布局通過(guò)基礎(chǔ)的 24 分欄,迅速簡(jiǎn)便地創(chuàng)建布局。只需引用row和col組件,就能快速的創(chuàng)建布局,基于24等分的原理,可以設(shè)置各個(gè)col所占的等分,使布局變得更簡(jiǎn)單。Layout 還參照了 Bootstrap 的 響應(yīng)式設(shè)計(jì),預(yù)設(shè)了五個(gè)響應(yīng)尺寸:xs、sm、md、lg 和 xl。通過(guò)源碼閱讀,來(lái)了解下element-ui源碼中是怎么實(shí)現(xiàn)分欄布局和響應(yīng)式布局的。
<el-row>
<el-col :span="12"><div class="grid-content bg-purple"></div></el-col>
<el-col :span="12"><div class="grid-content bg-purple-light"></div></el-col>
</el-row>
1. row組件
el-row組件的代碼相對(duì)比較簡(jiǎn)單,使用的是函數(shù)式組件,根據(jù)傳入的標(biāo)簽來(lái)創(chuàng)建一個(gè)容器,默認(rèn)為div容器,然后再根據(jù)傳入的布局類(lèi)型,排列方式,柵格間隔等參數(shù)來(lái)設(shè)置對(duì)應(yīng)的CSS。代碼如下所示:
export default {
name: 'ElRow',
componentName: 'ElRow',
props: {
tag: {
type: String,
default: 'div'
},
gutter: Number,
type: String,
justify: {
type: String,
default: 'start'
},
align: {
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) {
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' }
],
style: this.style
}, this.$slots.default);
}
};
2.col組件
2.1組件介紹
el-row可以理解成一個(gè)容器,在element-ui中將窗口劃分24等分,每一等分可以用一個(gè)el-col來(lái)添加內(nèi)容,也可以為每一個(gè)el-col設(shè)置占多少等份,或者偏移多少份。其js的源碼相對(duì)比較簡(jiǎn)單,就是簡(jiǎn)單的創(chuàng)建元素,為元素設(shè)置對(duì)應(yīng)的樣式。其核心主要是CSS代碼。
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],
md: [Number, Object],
lg: [Number, Object],
xl: [Number, Object]
},
computed: {
/**
* 獲取父組件'el-row'的柵格間格
*/
gutter() {
let parent = this.$parent;
while (parent && parent.$options.componentName !== 'ElRow') {
parent = parent.$parent;
}
return parent ? parent.gutter : 0;
}
},
render(h) {
let classList = [];
let style = {};
// 設(shè)置柵格間隔的樣式
if (this.gutter) {
style.paddingLeft = this.gutter / 2 + 'px';
style.paddingRight = style.paddingLeft;
}
//根據(jù)傳遞的,span,offset,pull,push等屬性值,生成相應(yīng)的樣式名稱(chēng)
['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]}`
);
}
});
//根據(jù)傳遞的響應(yīng)式屬性生成相應(yīng)的樣式名稱(chēng)
['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]}`
);
});
}
});
// 創(chuàng)建元素,并設(shè)置樣式
return h(this.tag, {
class: ['el-col', classList],
style
}, this.$slots.default);
}
};
2.2 樣式介紹
el-col組件的重點(diǎn)主要是樣式相關(guān)的,實(shí)現(xiàn)分欄和響應(yīng)式的核心都是由樣式來(lái)決定的,下面主要講下怎么進(jìn)行分欄和實(shí)現(xiàn)響應(yīng)式。
2.1 24等份
el-col的核心是將el-row分成 24 等份來(lái)迅速簡(jiǎn)便地創(chuàng)建布局。其平分原理主要是使用百分比來(lái)做為元素的寬度,使用sass中的for來(lái)循環(huán)的生成24等分,如下所示:
@for $i from 0 through 24 {
.el-col-#{$i} {
width: (1 / 24 * $i * 100) * 1%;
}
.el-col-offset-#{$i} {
margin-left: (1 / 24 * $i * 100) * 1%;
}
.el-col-pull-#{$i} {
position: relative;
right: (1 / 24 * $i * 100) * 1%;
}
.el-col-push-#{$i} {
position: relative;
left: (1 / 24 * $i * 100) * 1%;
}
}
for:該指令可以在限制的范圍內(nèi)重復(fù)輸出格式,每次按要求(變量的值)對(duì)輸出結(jié)果做出變動(dòng)。這個(gè)指令包含兩種格式:
@for $var from <start> through <end>,或者@for $var from <start> to <end>,區(qū)別在于through與to的含義:當(dāng)使用through時(shí),條件范圍包含<start>與<end>的值,而使用to時(shí)條件范圍只包含<start>的值不包含<end>的值。
2.2 響應(yīng)式布局
響應(yīng)式布局主要是使用media,在不同屏幕下設(shè)置對(duì)應(yīng)的樣式,el-col主要設(shè)置了768px、992px、1200px、1920px等4種寬度的屏幕:
$--sm: 768px !default;
$--md: 992px !default;
$--lg: 1200px !default;
$--xl: 1920px !default;
$--breakpoints: (
'xs' : (max-width: $--sm - 1),
'sm' : (min-width: $--sm),
'md' : (min-width: $--md),
'lg' : (min-width: $--lg),
'xl' : (min-width: $--xl)
);
$--breakpoints-spec: (
'xs-only' : (max-width: $--sm - 1),
'sm-and-up' : (min-width: $--sm),
'sm-only': "(min-width: #{$--sm}) and (max-width: #{$--md - 1})",
'sm-and-down': (max-width: $--md - 1),
'md-and-up' : (min-width: $--md),
'md-only': "(min-width: #{$--md}) and (max-width: #{$--lg - 1})",
'md-and-down': (max-width: $--lg - 1),
'lg-and-up' : (min-width: $--lg),
'lg-only': "(min-width: #{$--lg}) and (max-width: #{$--xl - 1})",
'lg-and-down': (max-width: $--xl - 1),
'xl-only' : (min-width: $--xl),
);
設(shè)置好對(duì)應(yīng)的屏幕尺寸后,再根據(jù)傳入的參數(shù)來(lái)生成對(duì)應(yīng)的css樣式代碼,源碼中使用的是一個(gè)res的混合器來(lái)生成的,如下所示:
@mixin res($key, $map: $--breakpoints) {
// 循環(huán)斷點(diǎn)Map,如果存在則返回
@if map-has-key($map, $key) {
@media only screen and #{inspect(map-get($map, $key))} {
@content;
}
} @else {
@warn "Undefeined points: `#{$map}`";
}
}
- map-has-key:用于判斷字典中是否包含了對(duì)應(yīng)的
key。- inspect:返回一個(gè)字符串的表示形式,
value是一個(gè)sass表達(dá)式。