Vant 移动端栅格布局实战:van-row 与 van-col 的 24 栅格体系、间距算法与源码原理解析

发布时间:2026/9/12 9:42:01
Vant 移动端栅格布局实战:van-row 与 van-col 的 24 栅格体系、间距算法与源码原理解析 Vant 移动端栅格布局实战van-row 与 van-col 的 24 栅格体系、间距算法与源码原理解析【免费下载链接】vantA lightweight, customizable Vue UI library for mobile web apps.项目地址: https://gitcode.com/GitHub_Trending/va/vantVant 的 Layout 布局组件由van-row与van-col两个组件组成是基于 24 列栅格体系的移动端页面排版解决方案。本文将围绕 Vant 官方文档packages/vant/src/col/README.zh-CN.md展开从组件引入、基础用法、间距配置到对齐方式逐一讲解每一个配置项并结合仓库源码Row.tsx、Col.tsx、index.less剖析栅格宽度、gutter 均分、垂直间距的实现原理帮助你写出可复制、可维护的栅格布局代码。一、组件引入与注册Layout 组件通过van-row和van-col两个组件协同完成行列布局二者缺一不可。在使用前需要按需引入并注册import { createApp } from vue; import { Col, Row } from vant; const app createApp(); app.use(Col); app.use(Row);从源码看row/index.ts 与 col/index.ts 均通过withInstall包装后导出并声明了VanRow、VanCol全局组件类型因此注册后既可以在模板中直接使用van-row、van-col也支持通过import type { RowProps, ColProps } from vant获得完整的类型提示。更多注册方式如局部注册、自动按需引入可参考 组件注册。二、24 列栅格体系span 与 offset 的宽度计算Layout 组件提供24 列栅格。在van-col上通过span属性设置列所占的栅格数即宽度百分比通过offset属性设置列左侧的偏移栅格数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 !-- 偏移示例span 4 偏移 4 span 10 -- van-row van-col span4span: 4/van-col van-col span10 offset4offset: 4, span: 10/van-col /van-row !-- 居中偏移offset 12 span 12 -- van-row van-col offset12 span12offset: 12, span: 12/van-col /van-row源码层面的宽度实现span与offset的宽度并非由 JavaScript 计算而是由 col/index.less 中的 Less 递归宏在编译期生成全部 24 组栅格类.van-col { display: block; box-sizing: border-box; min-height: 1px; } .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)); }每个span值生成.van-col--{i}类flex: 0 0 i * (100% / 24)与max-width同时锁定保证列宽严格按栅格比例且不会被压缩或拉伸每个offset值生成.van-col--offset-{i}类通过margin-left实现左侧偏移.van-col设置了box-sizing: border-box与min-height: 1px确保 padding 计入宽度、空列也能正常占位。在 Col.tsx 的渲染函数中span与offset被直接拼入类名class{bem({ [span]: span, [offset-${offset}]: offset })}而 row/index.less 为van-row声明了display: flex与flex-wrap: wrap因此van-col能够以 flex 项的形式自动换行排列。span 超 24 自动换行van-row并不强制要求一行内的span总和恰好为 24。在 Row.tsx 中groups计算属性会累加每个子列的span一旦累计值超过 24 就把后续列放入新的行组const groups computed(() { const groups: number[][] [[]]; let totalSpan 0; children.forEach((child, index) { totalSpan Number(child.span); if (totalSpan 24) { groups.push([index]); totalSpan - 24; } else { groups[groups.length - 1].push(index); } }); return groups; });groups分组结果同时用于 gutter 间距的均分计算见下文可见每行 24 栅格是间距计算的基本单元。三、gutter列间距与垂直间距水平间距默认 0通过van-row的gutter属性设置列元素之间的水平间距单位为 px默认值为 0van-row gutter20 van-col span8span: 8/van-col van-col span8span: 8/van-col van-col span8span: 8/van-col /van-rowgutter支持number、string与数组三种类型见 Row.tsx 的rowProps定义。需要注意gutter并非在列之间直接添加margin而是通过给每列设置左右padding实现视觉间距这样列的背景色如有会保持紧贴栅格边界。垂直间距数组形式当需要同时设置垂直间距时使用数组形式[水平间距, 垂直间距]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数组的第一个元素作为水平间距第二个元素作为垂直间距垂直间距通过给列设置marginBottom实现且最后一个行组不会被添加底部间距避免末尾多余空隙。gutter 的实现原理水平与垂直间距的计算均位于 Row.tsx水平间距spacesL74-L102若gutter为数组取第一项并转为数值为 0 或非法值时直接返回空数组。随后按groups行组逐一均分间距——每个行组内首个列的right为averagePadding gutter * (组内列数 - 1) / 组内列数其余列的left用前一项的right反推从而保证相邻两列之间的总间距恰好等于gutter且首列左、末列右不产生多余空白垂直间距verticalSpacesL104-L120仅当gutter为数组且长度大于 1 时生效取第二个元素作为bottombottom 0或非法数值时直接返回空数组非最后一行组中的每一列都会被记录{ bottom }数据下发通过linkChildren({ spaces, verticalSpaces })借助vant/use的useChildren/useParent组合式函数ROW_KEY注入键定义在 Row.tsx把计算好的间距下发到每个van-col列侧应用Col.tsx 根据自己在父组件中的index取出对应间距拼装为paddingLeft、paddingRight与marginBottom样式对象返回。以上逻辑均有对应单元测试覆盖见 col/test/index.spec.tsx例如gutter{[0, 20]}时前两个van-col的marginBottom为20px、后两个为falsygutter{[16, -16]}、空数组、[0, invalid]等边界场景均断言不产生多余间距。四、对齐方式justify 与 alignvan-row基于 flex 布局因此可以直接利用 flex 的对齐能力。主轴对齐 justify通过justify属性设置主轴上内容的对齐方式等价于 flex 布局中的justify-content。可选值start默认、end、center、space-around、space-between。!-- 居中 -- 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对应 CSS 定义在 row/index.less 中justify值被映射为.van-row--justify-{value}类其中end对应justify-content: flex-endspace-between、space-around直接透传。RowJustify类型约束见 Row.tsx。交叉轴对齐 align通过align属性设置交叉轴垂直方向上的对齐方式等价于align-items。可选值top默认、center、bottom。例如让同一行内高度不同的列垂直居中van-row aligncenter van-col span8内容 A/van-col van-col span8内容 B更高/van-col /van-row同样在 row/index.less 中align映射为.van-row--align-centeralign-items: center与.van-row--align-bottomalign-items: flex-end。自动换行控制 wrapwrap属性控制是否自动换行默认值为true。当设为false时行内所有列将强制排在同一行对应 flex 的flex-wrap: nowrap见 row/index.less 中的.van-row--nowrap列宽不足时会被压缩适用于需要横向滚动或固定单行的场景van-row :wrapfalse van-col span12列 1/van-col van-col span12列 2/van-col /van-rowwrap通过truthProp声明Row.tsx因此wrap本身即为true需显式绑定:wrapfalse关闭。五、自定义标签 tagRow与Col都支持tag属性自定义渲染的元素标签默认均为div。这在需要语义化标签如section、li或配合特定选择器时非常有用van-row tagsection van-col tagarticle span12语义化布局/van-col /van-row实现上Row.tsx 与 Col.tsx 都以tag作为动态组件标签渲染tag通过makeStringPropkeyof HTMLElementTagNameMap(div)声明见 Row.tsx 与 Col.tsx类型上限定为合法的 HTML 标签名。六、API 一览Row Props参数说明类型默认值gutter列元素之间的间距单位为 px数组形式为[水平间距, 垂直间距]number | string | Array0tag自定义元素标签stringdivjustify主轴对齐方式可选值startendcenterspace-aroundspace-betweenstringstartalign交叉轴对齐方式可选值centerbottomstringtopwrap是否自动换行booleantrueCol Props参数说明类型默认值span列元素宽度24 栅格体系中的栅格数number | string0offset列元素偏移距离左侧偏移的栅格数number | string-tag自定义元素标签stringdivRow Events事件名说明回调参数click点击时触发event: MouseEventCol Events事件名说明回调参数click点击时触发event: MouseEvent补充说明文档表格中gutter默认值标记为-但从源码 Row.tsx 看其默认值为0即默认无间距span在 Col.tsx 中通过makeNumericProp(0)声明默认值为0。七、类型定义组件导出以下类型定义可在 TS 项目中直接使用import type { ColProps, RowProps, RowAlign, RowJustify } from vant;RowProps、ColProps分别对应 Row 与 Col 的完整 props 类型由 row/index.ts 与 col/index.ts 对外导出内部通过ExtractPropTypestypeof rowProps/ExtractPropTypestypeof colProps推导RowAligntop | center | bottomRow.tsxRowJustifystart | end | center | space-around | space-betweenRow.tsx。八、在真实 Demo 中的运用Vant 官方 Democol/demo/index.vue展示了本组件全部能力的完整组合包括三等分、偏移、水平/垂直间距与四种justify对齐Demo 样式还为每列设置了交替的背景色background-clip: content-box配合 gutter 的 padding 方案可以直观看到列与列之间的真实间距效果。运行pnpm dev或参考仓库 package.json 中的脚本即可在本地站点中预览该 Demo。结语van-rowvan-col用极简的 API 封装了移动端最常用的栅格能力24 列体系由 Less 编译期生成、无需运行时计算gutter通过每列 padding 行组均分算法在保证精确间距的同时不破坏列宽比例justify/align/wrap则完整透传 flex 布局能力。理解 Row.tsx 与 Col.tsx 的分组、间距计算与父子通信逻辑后即使遇到多行嵌套、动态间距等复杂场景也能准确预判每一列的最终尺寸与间距表现。【免费下载链接】vantA lightweight, customizable Vue UI library for mobile web apps.项目地址: https://gitcode.com/GitHub_Trending/va/vant创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考