《Vue写UI轮子之Grid网格布局》

1,495 阅读2分钟

网格布局

什么是网格布局?

就是把一个 div 分成 N 个部分(N = 12,16,24...),每个部分无空隙或者有空隙。

制作雏形:

一行分成24份,可以用span指定多少份

增加gutter:

每个column之间有间隙,但是两边无间隙

实现思路:

  1. column设置 Padding,值为 gutter / 2,这样两个column之间的间隙值就是gutter
  2. 父元素row 设置负Margin,值为 - gutter / 2

怎么通过row给col传递gutter参数?

用户在使用UI时会这么写:

<m-row gutter="2">
			<m-col>1</m-col>
			<m-col>2</m-col>
			<m-col>3</m-col>
</m-row>

这样的话,就只有row组件能拿到gutter的值,而col拿不到。

怎么办?怎么才能让row悄悄给col传值?用mounted钩子函数!

父子组件里钩子函数执行顺序

created()这个钩子表示在内存中生成对象,类似于const div = document.createElement('div')

mounted()这个钩子表示把对象挂载在页面上, 类似于 document.body.appendChild(div)

我们再来分析一下父组件row 和子组件 col 的created和Mounted的执行顺序:

分别在两者的钩子函数里打log可以得到:

所以,顺序就是,先在内存里创建爸爸,再在内存里创建儿子,然后把儿子挂到爸爸身上,然后把爸爸挂到body上

所以我们可以利用这一特点,在父组件的mounted函数里,找到儿子,然后把数据传给他

row.vue

mounted() {
      this.$children.forEach((vm)=>{
        vm.$data.gutter = this.gutter
			})
    }

实现响应式

目标:在不同的页面宽度实现不同的布局

方法是传入一个phone 对象,里面覆盖已有的span和offset

<div>
			<m-row gutter="20">
				<m-col span="4" offset="2" :phone="{span:12, offset:4}">1</m-col>
				<m-col span="20" offset="2" :phone="{span:12, offset:4}">2</m-col>
			</m-row>
</div>

我们需要判断传入的对象是否是{span:xxx, offset:xxx}的子集

@Prop({
      validator(value: Record<string, number | string>) {
        const keys = Object.keys(value);
        let valid = true;
        keys.forEach(key => {
          if (!['span', 'offset'].includes(key)) {
            valid = false;
          }
        });
        return valid;
      }
    }) phone: Record<string, number | string> | undefined;

本文为fjl的原创文章,著作权归本人和饥人谷所有,转载务必注明来源