一、先搞懂,Vue2 Grid Layout是干啥的?
想在Vue2项目里快速实现漂亮的网格布局,比如仪表盘、卡片墙这类需求,Vue2 Grid Layout(常指适配Vue2的网格布局组件库,如 grid-layout-vue)能帮大忙!但新手刚接触时,总会纠结“怎么装?怎么写基础布局?响应式咋搞?” 这篇从基础用法、进阶技巧到实战案例,一步步拆明白,就算是刚学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-item的key对应)。
这样写后,页面会自动生成2行2列的网格,每个格子显示 item1、item2 等内容~
进阶篇:响应式、嵌套、动画全解锁
响应式咋做?不同屏幕下自动变列数
比如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-item的x、y、w、h是否与layout对应; - 确保
layout数组的i和grid-item的key一一对应,避免重复/缺失。
响应式失效:屏幕变了列数没变化
问题:窗口 resize 监听逻辑错误(如 mounted 加监听但 beforeDestroy 未销毁,或计算属性条件判断写错)。
解决:
- 严格编写
resize的添加/销毁逻辑; - 用
console.log打印windowWidth和colNum,验证是否触发变化。
性能问题:大量模块时页面卡顿
当网格包含几十上百个模块,Vue渲染压力大,优化方法:
- 用
v-if代替v-show,仅渲染可见区域模块(可结合虚拟滚动思路,需自行封装); - 给
grid-item加key时,用唯一稳定标识(如接口返回的id),避免不必要的重渲染; - 将复杂逻辑抽至计算属性/方法,减少模板内逻辑判断。
拓展:生态工具和替代方案
若需拖拽调整布局(如用户自定义仪表盘模块位置),可选用 vue-grid-layout(注意Vue2需用特定分支),它支持拖拽、拉伸,配置 isDraggable、isResizable 等属性即可。
若偏好更灵活的实现,也可纯手写CSS Grid,结合Vue的动态 class 或 style:
<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前端网发表,如需转载,请注明页面地址。
code前端网




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