Vant 移动端 Layout 布局组件完全指南:Row / Col 24 栅格系统的配置、源码原理与实战

发布时间:2026/9/12 13:11:29
Vant 移动端 Layout 布局组件完全指南:Row / Col 24 栅格系统的配置、源码原理与实战 Vant 移动端 Layout 布局组件完全指南Row / Col 24 栅格系统的配置、源码原理与实战【免费下载链接】vantA lightweight, customizable Vue UI library for mobile web apps.项目地址: https://gitcode.com/GitHub_Trending/va/vant导读Vant 是基于 Vue 3 的移动端组件库其 Layout 布局 提供了van-row与van-col两个组件以经典的24 列栅格系统快速搭建页面骨架。本文以 Vant 仓库中的 Layout 官方文档为主体结合 Row.tsx、Col.tsx 及对应 index.less 样式源码系统讲解栅格布局的安装引入、基础用法、间距控制、对齐方式、完整 API 与底层实现原理。读完本文你将能独立完成移动端页面的栅格化布局并理解 gutter 间距为何是内边距分摊而非简单的 margin以及 24 栅格宽度是如何生成的。一、Layout 组件是什么Layout 布局由van-row行与van-col列两个组件组成van-row负责承载一行栅格内部基于Flex 布局渲染并负责计算、下发栅格间距数据van-col负责渲染单个栅格列通过span指定列宽、offset指定左偏移。两者配合即可快速、轻松地创建页面布局这也是官方文档对 Layout 的核心定位。整个组件设计对标了 Element UI 等桌面组件库的栅格体系但针对移动端窄屏做了精简只保留最常用的 span / offset / gutter / justify / align 能力。二、安装与组件注册Layout 属于 Vant 的核心组件随主包一起发布。通过app.use全局注册即可使用import { createApp } from vue; import { Col, Row } from vant; const app createApp(); app.use(Col); app.use(Row);在 Vant 仓库中col/index.ts 与 row/index.ts 通过withInstall包装组件并声明了全局类型declare module vue { export interface GlobalComponents { VanCol: typeof Col; VanRow: typeof Row; } }因此注册后模板中既可使用van-col/van-row也能在 TS 中获得组件的属性类型提示。更多注册方式如按需引入、Volar 支持等可参考 Vant 的 组件注册进阶用法。三、基础用法span 与 offsetLayout 组件提供24 列栅格。在van-col上添加span属性即可设置列所占的宽度百分比span的值即占多少列添加offset属性可设置列的左侧偏移距离计算方式与 span 相同也是以 24 列计。van-row van-col span8span: 8/van-col van-col span8span: 8/van-col van-col span8span: 8/van-col /van-row van-row van-col span4span: 4/van-col van-col span10 offset4offset: 4, span: 10/van-col /van-row van-row van-col offset12 span12offset: 12, span: 12/van-col /van-row第一个例子中三个span8的列正好铺满一行8 × 3 24第二个例子通过offset4让第二列空出 4 格再展示第三个例子则让单列右移 12 格、占据半屏。底层实现栅格宽度从哪来span/offset最终会转换成 CSS 类名。在 Col.tsx 中return () { const { tag, span, offset } props; return ( tag style{style.value} class{bem({ [span]: span, [offset-${offset}]: offset })} {slots.default?.()} /tag ); };bem会生成形如van-col--8、van-col--offset-4的类名其宽度由 col/index.less 中递归生成的样式规则决定.generate-col(24); .generate-col(n, i: 1) when (i n) { .van-col--{i} { flex: 0 0 i * (100% / 24); max-width: i * (100% / 24); } .van-col--offset-{i} { margin-left: i * (100% / 24); } .generate-col(n, (i 1)); }Less 的generate-col递归为 1 到 24 每一档生成flex-basis/max-width均为i * 100% / 24的宽度类以及对应的margin-left偏移类。同时.van-col基础类设置了box-sizing: border-box保证 gutter 内边距不会撑破列宽。可见24 列栅格本质上是 24 档预生成的百分比宽度。另外注意 Col.tsx 中span使用makeNumericProp(0)即默认值为 0offset使用numericProp[Number, String]类型无默认值所以 span / offset 都支持数字与字符串两种写法如span8或:span8均合法。四、列间距gutter 水平间距通过van-row的gutter属性可以设置列元素之间的水平间距单位为 px默认值为 0官方文档明确说明van-row gutter20 van-col span8span: 8/van-col van-col span8span: 8/van-col van-col span8span: 8/van-col /van-row原理gutter 是内边距分摊而非 margin从源码结构看gutter的实现并非给每个列加 margin而是在 Row.tsx 中计算每个列应有的paddingLeft/paddingRight再经linkChildren注入子组件const spaces computed(() { let gutter 0; if (Array.isArray(props.gutter)) { gutter Number(props.gutter[0]) || 0; } else { gutter Number(props.gutter); } const spaces: RowSpaces []; if (!gutter) return spaces; groups.value.forEach((group) { const averagePadding (gutter * (group.length - 1)) / group.length; group.forEach((item, index) { if (index 0) { spaces.push({ right: averagePadding }); } else { const left gutter - spaces[item - 1].right; const right averagePadding - left; spaces.push({ left, right }); } }); }); return spaces; });其核心思路是设一行有 n 个列、gutter 为 g则列与列之间共有 n-1 个空隙每个列分得的平均内边距为g * (n-1) / n相邻两列的 left 与 right 之和恰好等于 g从而保证列间净间距为 g、而首列不产生多余左内边距。随后 Col.tsx 通过useParent(ROW_KEY)读取这些间距并写入内联样式const style computed(() { if (!parent) return; const { spaces, verticalSpaces } parent; let styles {}; if (spaces spaces.value spaces.value[index.value]) { const { left, right } spaces.value[index.value]; styles { paddingLeft: left ? ${left}px : null, paddingRight: right ? ${right}px : null, }; } const { bottom } verticalSpaces.value[index.value] || {}; return extend(styles, { marginBottom: bottom ? ${bottom}px : null, }); });Row 与 Col 之间的数据传递基于vant/use的useChildren/useParent关系注入ROW_KEY定义于 Row.tsx因此 gutter 只对直接包裹在当前van-row内的van-col生效。自动换行分组groupsRow.tsx 中还有一个groups计算属性它依次累加每个子列的 span当totalSpan 24时开启新的一组。这决定了一行放不下时自动换行到下一组而 gutter 间距是按组分别计算的——即换行后第一列重新从无左内边距开始。这也是 Row 组件wrap默认开启换行的配套逻辑。五、垂直间距gutter 数组形式如果同时需要垂直方向的行间距可以将gutter设置为数组[水平间距, 垂直间距]!-- 设置垂直间距 -- van-row :gutter[20, 20] van-col span12span: 12/van-col van-col span12span: 12/van-col van-col span12span: 12/van-col van-col span12span: 12/van-col /van-row垂直间距的实现细节verticalSpaces的计算逻辑位于 Row.tsxconst verticalSpaces computed(() { const { gutter } props; const spaces: VerticalSpaces []; if (Array.isArray(gutter) gutter.length 1) { const bottom Number(gutter[1]) || 0; if (bottom 0) return spaces; groups.value.forEach((group, index) { if (index groups.value.length - 1) return; group.forEach(() { spaces.push({ bottom }); }); }); } return spaces; });从源码结构看有以下三个值得注意的行为最后一组不设置垂直间距index groups.value.length - 1时直接跳过避免在布局最底部产生多余的 marginBottom垂直间距通过marginBottom实现区别于水平间距用 padding见 Col.tsx负数或非法值会被忽略bottom 0或Number(gutter[1])为 NaN如字符串invalid时返回空数组不产生任何垂直间距。这些边界行为在 col/test/index.spec.tsx 中有对应的单元测试验证例如gutter{[0, 20]}时前三列marginBottom为20px最后一列为空测试第 46-64 行gutter{[16, -16]}时所有列marginBottom均为空测试第 66-83 行gutter{[]}空数组时不产生任何内边距测试第 85-101 行gutter{[0, invalid]}非法数值时垂直间距为空测试第 103-117 行。六、对齐方式justify 与 align主轴对齐justifyjustify属性控制 Flex主轴水平方向上的内容对齐等价于 CSS 的justify-content可选值及对应效果如下!-- 居中 -- van-row justifycenter van-col span6span: 6/van-col van-col span6span: 6/van-col van-col span6span: 6/van-col /van-row !-- 右对齐 -- van-row justifyend van-col span6span: 6/van-col van-col span6span: 6/van-col van-col span6span: 6/van-col /van-row !-- 两端对齐 -- van-row justifyspace-between van-col span6span: 6/van-col van-col span6span: 6/van-col van-col span6span: 6/van-col /van-row !-- 每个元素的两侧间隔相等 -- van-row justifyspace-around van-col span6span: 6/van-col van-col span6span: 6/van-col van-col span6span: 6/van-col /van-row类型定义在 Row.tsx 中限定为五种取值start默认、end、center、space-around、space-between。交叉轴对齐alignalign属性控制 Flex交叉轴垂直方向上的对齐等价于align-items可选值有top默认、center、bottomvan-row aligncenter van-col span8span: 8/van-col van-col span8span: 8/van-col van-col span8span: 8/van-col /van-row类型定义对应 Row.tsx 中的RowAlign top | center | bottom。样式映射以上对齐能力由 row/index.less 中的修饰类驱动.van-row { display: flex; flex-wrap: wrap; --nowrap { flex-wrap: nowrap; } --justify-center { justify-content: center; } --justify-end { justify-content: flex-end; } --justify-space-between { justify-content: space-between; } --justify-space-around { justify-content: space-around; } --align-center { align-items: center; } --align-bottom { align-items: flex-end; } }组件渲染时根据 props 动态拼装这些类名Row.tsx例如alignbottom会映射为align-items: flex-end。注意justify的取值end映射为flex-end与 CSS 标准保持一致。七、完整 API 一览Row Props参数说明类型默认值gutter列元素之间的间距单位为 px数组形式为[水平间距, 垂直间距]number | string | Array0tag自定义元素标签stringdivjustify主轴对齐方式可选值endcenterspace-aroundspace-betweenstringstartalign交叉轴对齐方式可选值centerbottomstringtopwrap是否自动换行booleantrueCol Props参数说明类型默认值span列元素宽度占 24 栅格中的几列number | string0offset列元素左侧偏移距离同样按 24 栅格计number | string-tag自定义元素标签stringdivRow Events事件名说明回调参数click点击时触发event: MouseEventCol Events事件名说明回调参数click点击时触发event: MouseEvent关于默认值的源码佐证Row 的gutter默认值为0、wrap使用truthPropBoolean 类型、默认true、justify与align无默认值但文档标注为start/top见 Row.tsxCol 的span默认0见 Col.tsx。truthProp/makeNumericProp等工具函数定义在 utils/props.ts。类型定义Row 与 Col 均导出可复用的 TypeScript 类型便于二次封装或在业务代码中声明变量import type { ColProps, RowProps, RowAlign, RowJustify } from vant;对应源码row/index.ts 导出RowProps, RowAlign, RowJustifycol/index.ts 导出ColProps。八、事件使用示例Row 与 Col 都支持原生click事件回调参数为MouseEventvan-row clickonRowClick van-col span12 clickonColClickspan: 12/van-col van-col span12span: 12/van-col /van-rowfunction onRowClick(event) { console.log(row clicked, event); } function onColClick(event) { console.log(col clicked, event); }事件冒泡遵循 DOM 原生规则点击列时两个事件都会依次触发可根据业务需要选择监听层级。九、配套演示与测试如何快速验证仓库中提供了完整的示例与测试是学习与验证布局行为的最佳入口官方演示col/demo/index.vue 覆盖了基础用法、列间距、垂直间距与对齐方式四组场景与本文示例一一对应单元测试col/test/index.spec.tsx 验证了 Col 渲染、gutter 内边距计算、垂直间距边界条件负数 / 空数组 / 非法值等关键行为快照测试col/test/__snapshots__/目录下的.snap文件保存了组件渲染的 DOM 快照可直观查看最终输出的类名与内联样式。结语Vant 的 Layout 组件以 24 列栅格为基础用极少的 APIspan/offset/gutter/justify/align/tag/wrap覆盖了移动端页面布局的绝大多数场景。透过源码可以看到24 档列宽由 Less 递归生成gutter 水平间距由 Row 统一计算内边距并注入 Col垂直间距则仅对非末组列追加marginBottom而换行分组、默认值处理与边界防御负数、空数组、非法值都被细致地实现并有测试兜底。掌握这套机制后无论是日常页面搭建还是基于 Row / Col 做二次封装都能事半功倍。【免费下载链接】vantA lightweight, customizable Vue UI library for mobile web apps.项目地址: https://gitcode.com/GitHub_Trending/va/vant创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询