layout 布局是由 row 和 col 组件组合,通过基础的 24 分栏,简单的实现布局。element-plus layout 组件
layout 布局默认使用 flex 布局,
最终编译结果
<div class="el-row">
<div class="el-col">div>
<div class="el-col">div>
div>
我们从 props
入手,一共有4个
component
实现。<template>
<component :is="tag" :class="rowKls" :style="style">
<slot />
component>
template>
实现分2步:
marginRight
和 marginLeft
:styles.marginRight = styles.marginLeft = `-${props.gutter / 2}px`
paddingLeft
和 paddingRight
:styles.paddingLeft = styles.paddingRight = `${gutter.value / 2}px`
这样 row 组件左边的 marginLeft 会被第一个col 组件的 paddingLeft 抵消。右边同理。
这样就实现了 col 组件的间隔。
这2个是 flex 布局下,水平和垂直方向的对齐方式,不多介绍。
我们还是从 props
入手,主要的一共有6个
display:none
margin-left
实现。position:relative; left: x%
实现。position:relative; right: x%
实现。注意,push 和 pull 的实现中,移动的距离并不会影响相邻其他 col 组件的位置。这是有相对定位决定的。
元素相对定位,并不会脱离文档流。
也就是说,设置的 right 或 left 会使相对定位元素的位置发生变化。但其他的元素依然会按照相对定位元素的初始位置正常布局。
关键 scss 实现
math.div(1, 24)
表示 1/24
@for $i from 0 through 24 {
.el-col-#{$i} {
max-width: (math.div(1, 24) * $i * 100) * 1%;
flex: 0 0 (math.div(1, 24) * $i * 100) * 1%;
}
.el-col-offset-#{$i} {
margin-left: (math.div(1, 24) * $i * 100) * 1%;
}
.el-col-pull-#{$i} {
position: relative;
right: (math.div(1, 24) * $i * 100) * 1%;
}
.el-col-push-#{$i} {
position: relative;
left: (math.div(1, 24) * $i * 100) * 1%;
}
}
重点:
1,设置占据栅格数的 css:el-col-xxx
时,使用了max-width
和 flex: 0 0 x%
max-width
用于指定最大宽度。flex: 0 0 x%
设置 flex 元素 col 不能增大也不能缩小,宽度只能是 x%,也就是每个栅格的宽度都是定死的。flex 元素的
width
优先级:max-width
>flex-basic
>width
2,百分比
max-width
百分比,相对于其父级容器宽度
flex-basic
百分比,相对于其父弹性容器主轴尺寸
margin-left
百分比,相对于最近的块容器宽度
left
百分比,相对于元素包含块的宽度。(el-row
有设置相对定位哦)
所以可用百分比来表示,1 栅格的宽度 = el-row
宽度的1/24 = (math.div(1, 24) * 100) * 1%;
col 组件还有 xs
sm
md
lg
xl
这几个关于响应式的 props
<template>
<el-row :gutter="10">
<el-col :xs="8" :sm="6" :md="4" :lg="3" :xl="1">
<div class="grid-content ep-bg-purple"/>
el-col>
<el-col :xs="4" :sm="6" :md="8" :lg="9" :xl="11">
<div class="grid-content ep-bg-purple-light"/>
el-col>
el-row>
template>
这几个可以传 number 或 object。关键处理逻辑:
const sizes = ['xs', 'sm', 'md', 'lg', 'xl']
sizes.forEach((size) => {
if (isNumber(props[size])) {
classes.push(`el-col-${size}-${props[size]}`) // el-col-xs-2
} else if (isObject(props[size])) {
// props[xs] = { span?: number, offset?: number, pull?: number, push?: number }
Object.entries(props[size]).forEach(([prop, sizeProp]) => {
classes.push(
prop !== 'span'
? `el-col-${size}-${prop}-${sizeProp}` // el-col-xs-offset-2
: `el-col-${size}-${sizeProp}` // el-col-xs-2
)
})
}
})
样式实现
$sm: 768px;
$md: 992px;
$lg: 1200px;
$xl: 1920px;
$breakpoints: (
'xs': '(max-width: #{$sm})',
'sm': '(min-width: #{$sm})',
'md': '(min-width: #{$md})',
'lg': '(min-width: #{$lg})',
'xl': '(min-width: #{$xl})',
);
@mixin res($key, $map: $breakpoints) {
@if map-has-key($map, $key) {
@media only screen and #{unquote(map-get($map, $key))} {
@content;
}
} @else {
@warn "Undefined points: `#{$map}`";
}
}
@mixin col-size($size) {
@include res($size) {
.el-col-#{$size}-0 {
display: none;
}
@for $i from 0 through 24 {
.el-col-#{$size}-#{$i} {
@if $i != 0 {
display: block;
}
max-width: (math.div(1, 24) * $i * 100) * 1%;
flex: 0 0 (math.div(1, 24) * $i * 100) * 1%;
}
.el-col-#{$size}-offset-#{$i} {
margin-left: (math.div(1, 24) * $i * 100) * 1%;
}
.el-col-#{$size}-pull-#{$i} {
position: relative;
right: (math.div(1, 24) * $i * 100) * 1%;
}
.el-col-#{$size}-push-#{$i} {
position: relative;
left: (math.div(1, 24) * $i * 100) * 1%;
}
}
}
}
@include col-size(xs);
以上。