Vue造轮子系列-Grid组件

3,474 阅读5分钟

1、前言

今天来说一下布局中常用的Grid组件,也叫做栅格系统。基础用法如上面的图片所示。接下来,我就介绍下具体实现过程吧。

2、Grid组件-需求

这个组件需求还是比较简单的,所以这里直接介绍组件的使用吧。采用了24栅格系统,这样可以轻松应对大部分布局问题。使用栅格系统进行网页布局,可以使页面排版美观、舒适。

这里介绍一下两个概念,行row和列col,具体使用方法如下:

  • 使用row在水平方向创建一行
  • 通过设置rowgutter参数,指定列之间的分隔距离
  • 将一组col插入在row
  • 在每个col中,填入自己的内容
  • 通过设置colspan参数,指定跨越的范围,其范围是1到24
  • 每个row中的col总和应该为24
  • 通过设置coloffset参数,指定偏移量

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-leftpadding-right,并且大小正好是gutter/2

由于开始的时候说过,box-sizing设置成border-box,所以这时候设置paddingcontent的宽度就会变小,然后列与列之间的分隔就出来了,但是还有一个问题,由于加了padding,所以第一列和最后一列看起来就往里挪了,那么要实现两个分别与开始,结尾对齐,那么就需要给y-row添加margin-leftmargin-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结构也是很简单的一个divslot部分用户需要展示内容的地方。

<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栅格占据的列数number24
offset栅格左侧的间隔格数number0
orderflex 布局下的 order 顺序number

这里的colStyle就是上面提到的设置padding-leftpadding-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-colorder设置用户传递的值就可以了。

mounted() {
    if (this.order) {
        this.$refs.col.style.order = this.order
    }
},

好了,y-col的组件也介绍完了,整体来说还是比较简单的,还有根据不同屏幕宽度响应式的功能这边就不介绍了,其实就是给不同情况下设置不同的spanoffset,有兴趣的可以通过结尾的项目地址查看。

4、Grid组件-遇到的问题

在实现gutter的时候遇到了问题,一开始没有通过给外面的div设置背景颜色,然后只通过设置了padding,发现两端也是对齐的,然后就以为这样子就行了。到后面再测试的时候发现不行,那样子其实外面的比里面的要宽的,然后才想到通过设置margin-leftmargin-right来实现真正的对齐。

5、结束

Grid组件本身不难,但是要做好的话,考虑的细节还是挺多的,比如怎么实现24等分、如何自适应、gutter值怎么传给子组件等等。好了,这个组件到这就结束了。加油!

项目地址Yue UI