宫格布局的标配方案

App 首页的「金刚区」、个人中心的功能入口、九宫格抽奖面板,背后都是同一个布局模型——宫格。Vant 的 Grid 组件用一行配置搞定均分列数、间距、边框和正方形格子,不需要手写任何 flex 计算。

最简示例

html demo.vue
<template>
  <van-grid :column-num="4" :gutter="10">
    <van-grid-item
      v-for="item in menus"
      :key="item.text"
      :icon="item.icon"
      :text="item.text"
      @click="onGo(item)"
    />
  </van-grid>
</template>

<script setup>
import { ref } from "vue";
import { showToast } from "vant";

const menus = ref([
  { icon: "wap-nav", text: "分类" },
  { icon: "search", text: "搜索" },
  { icon: "cart-o", text: "购物车" },
  { icon: "user-o", text: "我的" },
]);

const onGo = (item) => showToast(item.text);
</script>
ℹ️
内置图标
icon 属性直接填 Vant 内置图标名(如 wap-nav、cart-o),完整清单见官方图标库页面。

常用属性详解

column-num:控制列数

默认 4 列,改成 3 列或 5 列都只是改一个数字,格子自动均分剩余宽度:

html demo.vue
<!-- 3 列大图标入口 -->
<van-grid :column-num="3">...</van-grid>

<!-- 5 列紧凑金刚区 -->
<van-grid :column-num="5" :border="false">...</van-grid>

square 与 gutter

square 让格子保持正方形(宽高相等),gutter 控制格子间距,两者常搭配使用:

html demo.vue
<!-- 正方形格子 + 8px 间距 + 无边框,类似相册九宫格 -->
<van-grid :column-num="3" square :gutter="8" :border="false">
  <van-grid-item v-for="img in photos" :key="img">
    <img :src="img" class="photo" />
  </van-grid-item>
</van-grid>

badge 角标

格子内容需要小红点或数字角标时,用 badge 属性:

html demo.vue
<van-grid :column-num="4">
  <van-grid-item icon="chat-o" text="消息" :badge="unread > 99 ? '99+' : unread" />
  <van-grid-item icon="star-o" text="收藏" dot />
  <van-grid-item icon="setting-o" text="设置" />
  <van-grid-item icon="service-o" text="客服" />
</van-grid>

<script setup>
import { ref } from "vue";
const unread = ref(128);
</script>

自定义格子内容

默认的「图标 + 文字」满足不了设计稿时,用默认插槽塞任意内容,此时格子只负责布局:

html wallet.vue
<template>
  <van-grid :column-num="3" :border="false">
    <van-grid-item v-for="item in wallet" :key="item.label">
      <div class="stat">
        <span class="stat-num">{{ item.value }}</span>
        <span class="stat-label">{{ item.label }}</span>
      </div>
    </van-grid-item>
  </van-grid>
</template>

<script setup>
import { ref } from "vue";

const wallet = ref([
  { value: "12", label: "优惠券" },
  { value: "328.50", label: "余额(元)" },
  { value: "6", label: "积分" },
]);
</script>

<style scoped>
.stat { display: flex; flex-direction: column; align-items: center; }
.stat-num { font-size: 18px; font-weight: 600; color: #323233; }
.stat-label { font-size: 12px; color: #969799; margin-top: 4px; }
</style>

icon 插槽:图形不限于图标

只想换图标、保留文字排版时,用 icon 插槽放图片或自定义 SVG:

html demo.vue
<van-grid-item v-for="item in entries" :key="item.text" :text="item.text">
  <template #icon>
    <img :src="item.img" class="entry-img" />
  </template>
</van-grid-item>

跳转路由

GridItem 内置路由能力,to 属性等价于 router.push,还可配 replace:

html demo.vue
<van-grid :column-num="4">
  <van-grid-item icon="orders-o" text="订单" to="/order/list" />
  <van-grid-item icon="location-o" text="地址" :to="{ name: 'address' }" />
  <van-grid-item icon="coupon-o" text="卡券" to="/coupon" replace />
  <van-grid-item icon="question-o" text="帮助" url="https://help.example.com" />
</van-grid>

属性速查表

属性(Grid)类型默认值说明
column-numnumber / string4列数
icon-sizenumber / string28px图标大小
gutternumber / string0格子间距
borderbooleantrue是否显示边框(gutter > 0 时自动关闭)
squarebooleanfalse是否固定为正方形
reversebooleanfalse是否调换图标与文字位置
clickablebooleanfalse是否开启点击反馈
属性(GridItem)说明
text文字内容
icon / badge / dot图标、角标数字、小红点
to / url / replace路由跳转 / 页面链接 / 是否无痕跳转

踩坑记录

⚠️
gutter 大于 0 时格子间不再共享边框,border 会被强制关闭;想要"有间距又有边框"只能自定义内容自己画边框。
💡 小技巧:内容溢出导致格子高度不一致时,给格子内容套一层固定高度的容器,或直接开 square,视觉立即对齐。

总结

Grid 组件的定位是「布局 + 角标 + 路由」三合一:常规入口用属性即可零样式完成,复杂内容交给插槽。记住 column-num / square / gutter 这三板斧,90% 的宫格需求都能在十分钟内落地。

好的组件库不是功能多,而是让常见需求变得不值得写 CSS。