news 2026/9/21 16:35:40

Vant Weapp Layout 布局组件实战:van-row / van-col 24 列栅格系统原理与用法

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Vant Weapp Layout 布局组件实战:van-row / van-col 24 列栅格系统原理与用法
  • 前端
  • 小程序
  • UI组件
  • 移动开发

【免费下载链接】vant-weapp

轻量、可靠的小程序 UI 组件库

项目地址:https://gitcode.com/gh_mirrors/va/vant-weapp
点击查看免费下载

Layout 布局是 Vant Weapp 中最基础、最常用的布局方案,由van-rowvan-col两个组件配合实现一套完整的 24 列栅格系统。本文以 packages/col/README.md 为核心,结合rowcol的源码实现、WXS 计算逻辑与测试用例,系统讲解从组件引入、基本用法到span/offset/gutter参数细节,再到栅格宽度与间距的底层计算原理,帮助你完全掌握在小程序中快速搭建响应式行列布局的能力。

组件介绍与引入

什么是 van-row / van-col

Layout组件提供了van-row(行)和van-col(列)两个组件来进行行列布局,其设计思路与 Web 端常见的 24 列栅格系统一致:每一行被均分为 24 等份,列组件通过span属性声明自己占据的份数,从而组合出任意比例的多列布局。栅格系统同时支持列偏移(offset)与列间距(gutter),足以覆盖绝大多数列表、表单、卡片等页面的排版需求。

引入组件

在小程序中,组件使用前需要先完成注册。按 Vant Weapp 的标准方式,在页面或自定义组件的app.json(全局)或index.json(页面级)中通过usingComponents声明两个组件:

"usingComponents": { "van-row": "@vant/weapp/row/index", "van-col": "@vant/weapp/col/index" }

完整的组件注册步骤可参考官方快速上手文档。引入后即可在 WXML 中直接使用<van-row><van-col>标签。

从仓库目录结构看,rowcol作为两个独立组件包分别维护在 packages/row/ 与 packages/col/ 下,各自包含index.ts(逻辑)、index.wxml(模板)、index.wxs(样式计算)、index.less(样式)与index.json(组件声明),编译产物对应lib/row/lib/col/

基本用法:span 与 offset

通过 span 设置列宽

van-col提供span属性设置列元素宽度,取值表示该列在 24 列栅格中所占的份数。例如span="8"表示该列宽度为容器宽度的 8/24,即 1/3:

<van-row> <van-col span="8">span: 8</van-col> <van-col span="8">span: 8</van-col> <van-col span="8">span: 8</van-col> </van-row>

通过 offset 设置偏移

offset属性用于设置列的偏移宽度,计算方式与span完全相同(偏移份数 × 容器宽度 / 24)。下面示例中,第二行第一列占span="4",第二列在span="10"的基础上再向左偏移offset="4";第三行则展示了纯偏移布局offset="12" span="12",让列恰好居中:

<van-row> <van-col span="4">span: 4</van-col> <van-col span="10" offset="4">offset: 4, span: 10</van-col> </van-row> <van-row> <van-col offset="12" span="12">offset: 12, span: 12</van-col> </van-row>

spanoffset相加不超过 24 时,各列可在同一行内并排展示;若相加超过 24,多出的列会自动折行,这与经典栅格系统的行为一致。

源码中的属性定义

在 packages/col/index.ts 中,col组件通过VantComponent声明了spanoffset两个属性,类型均为Number

VantComponent({ relation: useParent('row'), props: { span: Number, offset: Number, }, });

可以看到col组件本身并不直接感知布局宽度,它通过relation: useParent('row')建立与父级row的关联关系(详见下文“父子组件关联机制”一节),真正决定列宽与偏移的样式类由模板和 LESS 样式共同生成。

模板中的类名拼接

在 packages/col/index.wxml 中,列根节点根据spanoffset动态拼接类名:

<view class="custom-class {{ utils.bem('col', [span]) }} {{ offset ? 'van-col--offset-' + offset : '' }}" style="{{ computed.rootStyle({ gutter }) }}" > <slot /> </view>
  • utils.bem('col', [span])基于 BEM 规范生成形如van-col--8的类名;
  • offset存在时追加van-col--offset-4形式的类名;
  • 内联style则由 WXS 模块computed.rootStyle({ gutter })根据间距动态计算(见下文“gutter 间距的底层实现”)。

24 列栅格样式的生成

在 packages/col/index.less 中,col的基础样式为左浮动布局,并通过 Less 递归循环一次性生成 24 档宽度与 24 档偏移:

.van-col { float: left; box-sizing: border-box; } .generate(24); .generate(@n, @i: 1) when (@i =< @n) { .van-col--@{i} { width: @i * (100% / 24); } .van-col--offset-@{i} { margin-left: @i * (100% / 24); } .generate(@n, (@i + 1)); }
  • 宽度类.van-col--NwidthN × (100% / 24),即 N/24;
  • 偏移类.van-col--offset-N通过margin-left: N × (100% / 24)实现左偏移;
  • 父级 packages/row/index.less 则通过::after伪元素clear: both清除浮动,保证行容器能够正确包裹浮动的列。

这一实现决定了spanoffset的可选值范围为 1~24 的整数,超出该范围的取值不会命中任何生成的类名。

设置列元素间距:gutter

基本用法

通过van-rowgutter属性可以设置列元素之间的间距,单位为 px,默认间距为 0。在行组件上声明一次,即可作用于其内部所有列:

<van-row gutter="20"> <van-col span="8">span: 8</van-col> <van-col span="8">span: 8</van-col> <van-col span="8">span: 8</van-col> </van-row>

上例中三个span="8"的列之间会产生 20px 的均匀间距。仓库中的实际演示页面 packages/col/demo/index.wxml 也提供了相同的示例,配合 demo 目录下的深色/浅色色块(见 packages/col/demo/index.less)可以直观观察间距效果。

gutter 的响应式下发:row 的源码逻辑

gutter的传递并不依赖 WXML 逐列绑定,而是由row组件通过小程序的自定义组件 relations 机制,在子列接入时主动下发。见 packages/row/index.ts:

VantComponent({ relation: useChildren('col', function (target) { const { gutter } = this.data; if (gutter) { target.setData({ gutter }); } }), props: { gutter: { type: Number, observer: 'setGutter', }, }, methods: { setGutter() { this.children.forEach((col) => { col.setData(this.data); }); }, }, });

这里有两个关键机制:

  1. 首次关联下发useChildren('col', ...)的回调在col子组件 linked(关联)时被触发,row读取自身data.gutter,若存在则通过target.setData({ gutter })写入子列;
  2. 动态更新同步gutter属性配置了observer: 'setGutter',当运行中gutter值发生变化时,setGutter方法会把整份this.data(含最新gutter)同步给所有已关联的子列,保证动态修改间距时列间距即时刷新。

父子组件关联机制:useParent / useChildren

上述useParent('row')useChildren('col', ...)均来自 packages/common/relation.ts,其本质是对小程序relations特性的封装:

  • useParent(name)声明组件与父级路径../{name}/indexancestor(祖先)关系,并在created生命周期中通过getRelationNodes(path)[0]暴露只读的parent引用;
  • useChildren(name, onEffect)声明组件与后代../{name}/indexdescendant(后代)关系,在linked/linkChanged/unlinked三个时机回调onEffect,并暴露只读的children列表。

这套封装让rowcol可以在不依赖selectComponent硬编码路径的前提下解耦协作:row只负责维护子列集合与分发guttercol只负责消费从父级获取到的gutter并渲染自身宽度。

gutter 间距的底层实现:WXS 动态样式

间距并非通过固定 CSS 类实现,而是由 WXS 模块在渲染期动态计算内联样式。row的根节点样式见 packages/row/index.wxml:

<view class="van-row custom-class" style="{{ computed.rootStyle({ gutter }) }}"> <slot /> </view>

其对应的计算逻辑在 packages/row/index.wxs:

function rootStyle(data) { if (!data.gutter) { return ''; } return style({ 'margin-right': addUnit(-data.gutter / 2), 'margin-left': addUnit(-data.gutter / 2), }); }

col侧对应的内联样式逻辑在 packages/col/index.wxs:

function rootStyle(data) { if (!data.gutter) { return ''; } return style({ 'padding-right': addUnit(data.gutter / 2), 'padding-left': addUnit(data.gutter / 2), }); }

两者配合的核心思路是:

  • row通过负外边距margin-left/margin-right-gutter/2)向外扩展容器的可视宽度,抵消首尾列的内边距带来的缩进;
  • 每个col通过内边距padding-left/padding-rightgutter/2)在自身内部制造间距,从而让相邻列之间恰好呈现gutter的间隙,同时首列与容器左缘、末列与容器右缘不产生多余空白。

其中addUnit工具函数(见 packages/common/utils.ts)负责为数值追加px单位:数字类型转成"20px",字符串类型则原样保留(可直接传"20rpx"等带单位的字符串)。style函数则来自 packages/wxs/style.wxs,将键值对象序列化为内联样式字符串。

由于col已设置box-sizing: border-boxpadding不会撑破由span决定的百分比宽度,栅格整体宽度依然严格等于容器宽度。

实际演示与测试验证

Demo 示例页

仓库为col提供了完整的演示页面 packages/col/demo/index.wxml,包含“基础用法”与“在列元素之间增加间距”两组示例,其中:

  • 基础用法展示三行布局:等分三列(span="8")、混合偏移(span="4"span="10" offset="4")、居中布局(offset="12" span="12");
  • 间距示例在van-row上设置gutter="20",展示三列之间的 20px 间距效果。

演示页的组件注册见 packages/col/demo/index.json,色块样式定义见 packages/col/demo/index.less。

快照测试

col组件配有自动化测试 packages/col/test/demo.spec.ts,通过miniprogram-simulate加载 demo 页面并断言渲染结果与快照一致:

test('should render demo and match snapshot', () => { const id = simulate.load(path.resolve(__dirname, '../demo/index'), { rootPath: path.resolve(__dirname, '../../'), }); const comp = simulate.render(id); comp.attach(document.createElement('parent-wrapper')); expect(comp.toJSON()).toMatchSnapshot(); });

该测试验证了 demo 页面(含spanoffsetgutter各场景)在模拟环境中的稳定渲染,说明栅格类名拼接、WXS 内联样式计算与父子组件关联在运行时行为正确。

API 一览

Row Props

参数说明类型默认值
gutter列元素之间的间距(单位为 px)string | number-

说明:gutter声明类型为Number(见 packages/row/index.ts),WXS 层的addUnit亦支持传入带单位的字符串(如"20rpx"),实际使用时两种写法均可。

Col Props

参数说明类型默认值
span列元素宽度string | number-
offset列元素偏移距离string | number-

说明:spanoffset在源码中声明为Number类型(见 packages/col/index.ts),推荐取值范围为 1~24 的整数,超出范围的取值不会命中 packages/col/index.less 中生成的栅格类。

外部样式类

类名说明
custom-class根节点样式类

van-rowvan-col的根节点都预留了custom-class,可通过传入自定义样式类覆盖根节点样式(例如为列设置背景色、圆角或内边距等),便于在不侵入组件内部样式的前提下完成视觉定制。

小结

Vant Weapp 的 Layout 布局组件以 24 列栅格为骨架,通过van-row+van-col的组合即可快速搭建等分列、偏移列与带间距的多列布局。其工程实现颇具代表性:col仅声明span/offset两个属性,宽高由 Less 递归生成的 24 档类名驱动;gutter借助relations机制由row统一下发并由 WXS 动态计算正负内/外边距;整个布局不依赖 JS 布局引擎,纯模板 + 样式即可完成,兼具性能与可维护性。掌握这些参数与底层原理后,你可以轻松在小程序页面中实现任意比例的行列排版。

  • 前端
  • 小程序
  • UI组件
  • 移动开发

【免费下载链接】vant-weapp

轻量、可靠的小程序 UI 组件库

项目地址:https://gitcode.com/gh_mirrors/va/vant-weapp
点击查看免费下载

相关推荐

上一篇:终极指南:如何用Oh My Zsh grep/awk插件提升命令行文本处理效率
下一篇:为什么3D Slicer成为医学研究者的首选?揭秘其10大核心功能

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/21 16:26:23

PVE中Intel核显直通LXC的真相与绕过方案

1. 为什么 Intel 核显直通 LXC 在 PVE 7.1–8 上是个“伪需求陷阱”你搜到这篇指南&#xff0c;大概率是因为——刚在 PVE Web 界面里点开 LXC 容器设置页&#xff0c;发现“设备”栏下赫然写着“GPU 设备直通”&#xff0c;旁边还配了个小图标&#xff1b;再一查 Intel UHD Gr…

作者头像 李华
网站建设 2026/9/21 16:25:48

React Native跨平台图片圆角处理与OpenHarmony适配方案

1. 跨平台图片处理的技术挑战在移动应用开发中&#xff0c;图片显示是最基础也最频繁使用的功能之一。而圆角裁剪作为UI设计中的常见需求&#xff0c;看似简单实则暗藏玄机。当我们需要在React Native框架中对接OpenHarmony系统时&#xff0c;这个问题就变得更加复杂。我最近在…

作者头像 李华