Code前端首页关于Code前端联系我们

一、先搞懂,Vue2 Grid Layout是干啥的?

terry 4小时前 阅读数 7 #Vue
文章标签 Vue2;Grid Layout

想在Vue2项目里快速实现漂亮的网格布局,比如仪表盘、卡片墙这类需求,Vue2 Grid Layout(常指适配Vue2的网格布局组件库,如 grid-layout-vue)能帮大忙!但新手刚接触时,总会纠结“怎么装?怎么写基础布局?响应式咋搞?” 这篇从基础用法、进阶技巧到实战案例,一步步拆明白,就算是刚学Vue的小白也能跟着做~

很多同学第一次听到“Grid Layout”,会和CSS原生Grid混淆,简单说,**Vue2 Grid Layout是把CSS Grid的能力封装成Vue组件**,让我们不用写一堆CSS,通过组件属性就能配置行、列、子元素位置,还能结合Vue的数据驱动,动态调整布局。

举个实际场景:做后台管理系统的仪表盘,有图表、数据卡片、统计模块,要适配PC、平板,还要支持拖拽调整(部分库自带拖拽功能),用Vue2 Grid Layout,只需配置好网格的行数、列数、每个模块的位置,就能自动排版,比纯手写CSS Grid效率高太多!

基础篇:从安装到写第一个网格布局

怎么把Grid Layout装到Vue2项目里?

以社区常用的 grid-layout-vue(Vue2兼容版)为例,步骤很简单:

  • 通过npm安装:执行 npm i grid-layout-vue@legacy(加 @legacy 选择Vue2兼容版本);
  • 全局注册(在 main.js 中):
    import Vue from 'vue'
    import GridLayout from 'grid-layout-vue'
    Vue.use(GridLayout)
  • 或单组件局部引入:
    import { GridLayout, GridItem } from 'grid-layout-vue'
    export default {
    components: { GridLayout, GridItem }
    }

写个最简单的2×2网格,咋操作?

核心是用 <grid-layout> 当容器,<grid-item> 当子元素,通过属性配置行列和位置,直接上代码:

<template>
  <grid-layout 
    :row-height="100"  <!-- 每行高度100px -->
    :cols="2"         <!-- 列数设为2列 -->
    :layout="[        <!-- 子元素的布局配置 -->
      { x: 0, y: 0, w: 1, h: 1, i: 'item1' },
      { x: 1, y: 0, w: 1, h: 1, i: 'item2' },
      { x: 0, y: 1, w: 1, h: 1, i: 'item3' },
      { x: 1, y: 1, w: 1, h: 1, i: 'item4' }
    ]"
  >
    <grid-item 
      v-for="item in layout" 
      :key="item.i" 
      :x="item.x" 
      :y="item.y" 
      :w="item.w" 
      :h="item.h"
    >
      {{ item.i }}
    </grid-item>
  </grid-layout>
</template>
<script>
export default {
  data() {
    return {
      layout: [/* 上述布局数据 */]
    }
  }
}
</script>

解释关键属性:

  • row-height:控制每行的高度(单位px);
  • cols:指定网格总列数;
  • layout 数组中,每个对象的 x 是列起点(从0开始),y 是行起点,w 是占几列,h 是占几行,i 是唯一标识(需和 grid-itemkey 对应)。

这样写后,页面会自动生成2行2列的网格,每个格子显示 item1item2 等内容~

进阶篇:响应式、嵌套、动画全解锁

响应式咋做?不同屏幕下自动变列数

比如PC端3列、平板2列、手机1列,核心思路是 根据屏幕宽度,动态修改 cols 属性,结合Vue的计算属性和窗口 resize 监听实现:

<template>
  <grid-layout :cols="colNum" ...>...</grid-layout>
</template>
<script>
export default {
  data() {
    return {
      windowWidth: window.innerWidth
    }
  },
  computed: {
    colNum() {
      if (this.windowWidth >= 1200) return 3;
      if (this.windowWidth >= 768) return 2;
      return 1;
    }
  },
  mounted() {
    window.addEventListener('resize', () => {
      this.windowWidth = window.innerWidth;
    });
  },
  beforeDestroy() {
    window.removeEventListener('resize', () => {
      this.windowWidth = window.innerWidth;
    });
  }
}
</script>

屏幕变化时,列数自动切换,子元素也会重新排版~

网格里套网格,实现复杂布局

若一个模块内需要再分小网格(图表+按钮栏”的组合),可在 <grid-item> 里嵌套 <grid-layout>

<grid-item ...>
  <grid-layout :cols="2" :row-height="50">
    <grid-item x="0" y="0" w="1" h="1">图表</grid-item>
    <grid-item x="1" y="0" w="1" h="1">按钮栏</grid-item>
  </grid-layout>
</grid-item>

注意内层网格的尺寸要和外层协调(比如外层行高100,内层行高50,确保两层对齐)~

给布局变化加动画,让交互更丝滑

CSS Grid本身支持过渡(transition),给网格容器加过渡属性,布局变化时就会平滑过渡。

<grid-layout> 加个类:

.grid-layout {
  transition: all 0.3s ease;
}

这样,响应式切换列数或动态修改子元素位置时,布局变化会带动画,不再生硬~

实战篇:做个能响应式的后台仪表盘

需求:PC端3列、平板2列、手机1列;模块可点击,支持简单交互;布局数据从接口获取(模拟)。

步骤1:设计布局结构

先规划模块(如统计卡片、折线图、柱状图等),用 layout 数组定义每个模块的位置。

步骤2:数据驱动+动态渲染

假设接口返回布局数据,用 v-for 动态渲染:

<template>
  <grid-layout 
    :cols="colNum" 
    :row-height="100" 
    :layout="remoteLayout"
  >
    <grid-item 
      v-for="item in remoteLayout" 
      :key="item.i" 
      :x="item.x" 
      :y="item.y" 
      :w="item.w" 
      :h="item.h"
      @click="handleClick(item)"
    >
      <component :is="item.component" :data="item.data" />
    </grid-item>
  </grid-layout>
</template>
<script>
import StatCard from './components/StatCard.vue'
import LineChart from './components/LineChart.vue'
export default {
  components: { StatCard, LineChart },
  data() {
    return {
      remoteLayout: [], // 接口返回的布局数据
      windowWidth: window.innerWidth
    }
  },
  computed: {
    colNum() { /* 同响应式逻辑 */ },
    // 将组件字符串转为实际组件(假设接口返回component: 'StatCard')
    layoutWithComponent() {
      return this.remoteLayout.map(item => ({
        ...item,
        component: item.component === 'StatCard' ? StatCard : LineChart
      }));
    }
  },
  mounted() {
    // 模拟接口请求
    setTimeout(() => {
      this.remoteLayout = [
        { x: 0, y: 0, w: 1, h: 1, i: 'stat1', component: 'StatCard', data: { title: '用户数', value: 1234 } },
        { x: 1, y: 0, w: 2, h: 1, i: 'line1', component: 'LineChart', data: { ... } },
        // 其他模块...
      ];
    }, 1000);
    window.addEventListener('resize', () => {
      this.windowWidth = window.innerWidth;
    });
  },
  methods: {
    handleClick(item) {
      console.log('点击了', item.i);
    }
  }
}
</script>

步骤3:细节优化

  • 加载状态:接口请求时显示 loading
  • 空状态:无数据时显示“暂无布局”;
  • hover效果:给 grid-item:hover 样式(如阴影、放大);
  • 响应式测试:在平板、手机尺寸下调试,确保布局不挤不乱。

避坑篇:这些问题新手常踩!

布局错位:子元素“飞”出网格

原因:子元素未正确绑定 x/y/w/h,或 layout 数组与实际渲染的 grid-item 数量不一致。

解决:

  • 检查每个 grid-itemxywh 是否与 layout 对应;
  • 确保 layout 数组的 igrid-itemkey 一一对应,避免重复/缺失。

响应式失效:屏幕变了列数没变化

问题:窗口 resize 监听逻辑错误(如 mounted 加监听但 beforeDestroy 未销毁,或计算属性条件判断写错)。

解决:

  • 严格编写 resize 的添加/销毁逻辑;
  • console.log 打印 windowWidthcolNum,验证是否触发变化。

性能问题:大量模块时页面卡顿

当网格包含几十上百个模块,Vue渲染压力大,优化方法:

  • v-if 代替 v-show,仅渲染可见区域模块(可结合虚拟滚动思路,需自行封装);
  • grid-itemkey 时,用唯一稳定标识(如接口返回的 id),避免不必要的重渲染;
  • 将复杂逻辑抽至计算属性/方法,减少模板内逻辑判断。

拓展:生态工具和替代方案

若需拖拽调整布局(如用户自定义仪表盘模块位置),可选用 vue-grid-layout(注意Vue2需用特定分支),它支持拖拽、拉伸,配置 isDraggableisResizable 等属性即可。

若偏好更灵活的实现,也可纯手写CSS Grid,结合Vue的动态 classstyle

<template>
  <div :style="gridStyle" class="my-grid">
    <div class="item">模块1</div>
    <div class="item">模块2</div>
  </div>
</template>
<script>
export default {
  computed: {
    gridStyle() {
      return {
        'grid-template-columns': this.colNum === 3 ? '1fr 1fr 1fr' : '1fr 1fr'
      };
    }
  }
}
</script>
<style scoped>
.my-grid {
  display: grid;
  gap: 10px;
  transition: all 0.3s;
}
.item {
  background: #fff;
  padding: 20px;
}
</style>

这种方式更灵活,但需自行处理响应式和布局逻辑,适合对CSS熟悉的同学。

最后总结:Vue2 Grid Layout本质是简化CSS Grid的使用,结合Vue数据驱动优势,快速实现复杂布局,从基础安装、静态布局,到响应式、嵌套、实战,再到避坑,吃透这些环节,做后台系统、数据可视化页面都能游刃有余~ 练手时,建议先仿写一个仪表盘,跑通响应式和交互逻辑,遇到问题再回看避坑篇,熟练后就能灵活发挥啦!

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

热门