1、前言
今天来说一下布局中常用的Grid组件,也叫做栅格系统。基础用法如上面的图片所示。接下来,我就介绍下具体实现过程吧。
2、Grid组件-需求
这个组件需求还是比较简单的,所以这里直接介绍组件的使用吧。采用了24栅格系统,这样可以轻松应对大部分布局问题。使用栅格系统进行网页布局,可以使页面排版美观、舒适。
这里介绍一下两个概念,行row和列col,具体使用方法如下:
- 使用
row在水平方向创建一行 - 通过设置
row的gutter参数,指定列之间的分隔距离 - 将一组
col插入在row中 - 在每个
col中,填入自己的内容 - 通过设置
col的span参数,指定跨越的范围,其范围是1到24 - 每个
row中的col总和应该为24 - 通过设置
col的offset参数,指定偏移量
3、Grid组件-实现
提醒:box-sizing必须设置成border-box
介绍完基本概念之后,看一下组件调用的API:
<y-row class="row">
<y-col class="item" :span="4">col-4</y-col>
<y-col class="item" :span="4">col-4</y-col>
<y-col class="item" :span="4">col-4</y-col>
<y-col class="item" :span="4">col-4</y-col>
<y-col class="item" :span="4">col-4</y-col>
<y-col class="item" :span="4">col-4</y-col>
</y-row>
知道怎么调用后,就是代码实现了。
1、y-row组件
首先先看y-row组件,代码很简单,如下所示:
<div class="y-row" :style="rowStyle" :class="rowClasses">
<slot></slot>
</div>
主要就是一个div,然后内部有一个插槽slot用来放y-rol组件。然后它接收的属性有:
props: {
gutter: {
type: [Number, String],
},
align: {
type: String,
default: 'left',
validator(value) {
return ['left', 'right', 'center'].includes(value)
},
},
},
gutter属性主要用于控制列之间的分隔距离,align属性主要靠控制列是靠左排列还是靠右排,或者是居中排列,默认情况下是靠左排列。
y-row主要是利用flex布局,css代码如下:
.y-row {
display: flex;
flex-wrap: wrap;
&.align-left {
justify-content: flex-start;
}
&.align-right {
justify-content: flex-end;
}
&.align-center {
justify-content: center;
}
}
这个组件还是相对比较简单的,我觉得gutter的实现算是这个组件的一个难点,然后下面就讲一下实现的一个思路。首先看到div上有一个style="rowStyle",它其实是一个计算属性,代码如下所示:
computed: {
rowStyle() {
return {
marginLeft: -this.gutter / 2 + 'px',
marginRight: -this.gutter / 2 + 'px',
}
},
}
gutter实现主要是给y-col添加了padding-left和padding-right,并且大小正好是gutter/2。
由于开始的时候说过,box-sizing设置成border-box,所以这时候设置padding,content的宽度就会变小,然后列与列之间的分隔就出来了,但是还有一个问题,由于加了padding,所以第一列和最后一列看起来就往里挪了,那么要实现两个分别与开始,结尾对齐,那么就需要给y-row添加margin-left,margin-right了,并且为负数,这样整个就会往前和往后移了,就能实现和两侧对齐,这就解释了为什么要给y-row设置rowStyle了。
另一个需要注意的地方,因为gutter是传给y-row的,那么子组件y-col怎么获得呢,这里我是通过给子组件的data上面添加gutter实现的,代码如下:
mounted() {
// 获取子元素
this.$children.forEach((item) => {
item.gutter = this.gutter
})
},
通过$children就可以获取下面的子组件了,然后给它的gutter赋值。
那么可能有人会问,为什么赋值操作要放在mounted,不放在created里面呢?这里来看一下父子组件间的生命周期函数就知道了,
父created --> 子created --> 子mounted --> 父mounted
我想答案显而易见了,如果在created里面设置,这时候子组件的data部分还没有创建,怎么给它设置值呢。
好了,y-row组件已经介绍完了,那么接下来就看看y-col组件的实现。
2、y-col组件
首先y-col组件的html结构也是很简单的一个div,slot部分用户需要展示内容的地方。
<div class="y-col" ref="col" :class="colClasses" :style="colStyle">
<slot></slot>
</div>
然后接收的属性有:
props: {
span: {
type: [String, Number],
},
offset: {
type: [Number, String],
},
order: {
type: [Number, String],
},
}
参数说明如下表:
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
|---|---|---|---|---|
| span | 栅格占据的列数 | number | — | 24 |
| offset | 栅格左侧的间隔格数 | number | — | 0 |
| order | flex 布局下的 order 顺序 | number | — | — |
这里的colStyle就是上面提到的设置padding-left和padding-right,如下所示:
computed: {
colStyle() {
return {
paddingLeft: this.gutter / 2 + 'px',
paddingRight: this.gutter / 2 + 'px',
}
},
},
这里的span主要就是通过设置width实现,下面的$n就代表传的span值。
width: ($n / 24) * 100%;
这里的offset主要就是通过设置margin-left实现,下面的$n就代表传的offset值。
margin-left: ($n / 24) * 100%;
至于order属性的实现就很简单了,因整体布局是采用flex的,所以只需要给y-col的order设置用户传递的值就可以了。
mounted() {
if (this.order) {
this.$refs.col.style.order = this.order
}
},
好了,y-col的组件也介绍完了,整体来说还是比较简单的,还有根据不同屏幕宽度响应式的功能这边就不介绍了,其实就是给不同情况下设置不同的span,offset,有兴趣的可以通过结尾的项目地址查看。
4、Grid组件-遇到的问题
在实现gutter的时候遇到了问题,一开始没有通过给外面的div设置背景颜色,然后只通过设置了padding,发现两端也是对齐的,然后就以为这样子就行了。到后面再测试的时候发现不行,那样子其实外面的比里面的要宽的,然后才想到通过设置margin-left和margin-right来实现真正的对齐。
5、结束
Grid组件本身不难,但是要做好的话,考虑的细节还是挺多的,比如怎么实现24等分、如何自适应、gutter值怎么传给子组件等等。好了,这个组件到这就结束了。加油!
项目地址Yue UI