Vant Space 间距组件:5 个 Props 搞定元素间距,还能分别设置横向纵向间距
【免费下载链接】vantA lightweight, customizable Vue UI library for mobile web apps.项目地址: https://gitcode.com/GitHub_Trending/va/vant
在 Vant 中,van-space是专门负责"元素之间间距"的布局组件:把子元素包进<van-space>,组件会自动在每个子元素之间注入统一间距,横向、纵向、换行行距都可以单独控制,不需要你再给子元素手工补 margin。
快速接入:安装并渲染第一个 van-space
先安装 Vant 并注册组件,然后把子元素直接放进<van-space>:
import { createApp } from 'vue'; import { Space } from 'vant'; const app = createApp(); app.use(Space);<van-space> <van-button type="primary">按钮</van-button> <van-button type="primary">按钮</van-button> <van-button type="primary">按钮</van-button> </van-space>不传任何属性时,子元素之间会自动出现8px 的横向间距(默认值来自packages/vant/src/space/Space.tsx中size的default: 8)。除全局注册外,也可以按需import { Space } from 'vant'后在组件里局部注册,用法一致。
横向按钮组:默认行为就够了
问题:一行按钮要拉开间距,又不想在每个按钮上写margin-right。
代码:就是上面的基础用法,什么都不用传。组件会为每个子元素包一层.van-space-item,用内联样式注入margin-right: 8px,末项不注入,所以按钮组两端不会多出空白。
关键点:间距是加在"包裹层"上的,不会污染子组件自身样式;子元素高度不一致时,默认按align-items: center垂直居中(见下文对齐一节)。
纵向通栏列表:direction="vertical" 搭配 fill 和 block
问题:按钮、卡片需要纵向排成一列并占满整行宽度。
<van-space direction="vertical" fill> <van-button type="primary" block>按钮</van-button> <van-button type="primary" block>按钮</van-button> <van-button type="primary" block>按钮</van-button> </van-space>三个属性缺一不可地配合:
direction="vertical":容器切换为flex-direction: column,间距从margin-right换成margin-bottom;fill:Space 默认是display: inline-flex,宽度由内容撑开;加上fill后变成display: flex块级容器,才能撑满父元素;- 子元素加
block:Button 默认是自适应宽度,通栏效果需要子元素自己撑满。
如何分别设置横向纵向间距:size 的三种写法
size支持三种形态,对应三种诉求:
<!-- 数字:自动补 px --> <van-space :size="20">...</van-space> <!-- 字符串:自带单位,原样使用 --> <van-space size="2rem">...</van-space> <!-- 数组:[横向间距, 纵向间距],配合 wrap 分别控制列距和行距 --> <van-space wrap :size="[12, 20]">...</van-space>数组形态是size最实用的隐藏能力:size[0]决定margin-right,size[1]决定margin-bottom。在wrap模式下每个子项都会同时携带横向与纵向两个 margin,正好对应"列距"和"行距"两个概念。字符串类型请带单位(如20px、2em、5vw),组件不会替你补。
对齐方式:align 的四种取值与默认行为
问题:按钮和高块元素并排时,垂直方向怎么对齐。
<van-space align="start" style="padding: 16px; background: #f3f2f5"> <van-button type="primary">按钮</van-button> <div style="padding: 40px 20px; background: #fff">Block</div> </van-space>align可选start、center、end、baseline,映射为align-items: flex-start / center / flex-end / baseline。注意默认值取决于方向:水平模式不传align时默认按center处理,垂直模式不传则不加对齐类(纵向排列中align-items影响不大)。所以align主要服务于水平模式。
自动换行:wrap 之后行距从哪来
问题:子元素多、一行放不下时,折行后第二行会紧贴第一行,没有行距。
<van-space wrap :size="[12, 16]"> <!-- 大量子元素,一行放不下时自动折行 --> </van-space>开启wrap后容器加上flex-wrap: wrap。行距的保证方式是:开启wrap后所有子项(包括最后一项)都会注入margin-bottom,这样每一行的高度天然包含行距,折行后第二行不会贴住第一行。横向间距仍由margin-right提供,只是换到新一行时该行不再受上一行末项的margin-right影响——这正是size数组形态存在的原因。
API 速查
Props
| 参数 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| direction | 间距方向 | vertical | horizontal | horizontal |
| size | 间距大小,如20px、2em;数字默认补px单位;数组形式[横向间距, 纵向间距] | number | string | [number | string, number | string] | 8 |
| align | 子元素对齐方式 | start | end | center | baseline | 水平模式center,垂直模式无 |
| wrap | 是否自动换行,仅水平方向有效 | boolean | false |
| fill | 是否变为块级元素,填充整个父元素宽度 | boolean | false |
Slots
| 名称 | 说明 |
|---|---|
| default | 间距组件内容 |
类型定义
import type { SpaceProps, SpaceSize, SpaceAlign } from 'vant';推荐组合:纵向通栏用direction="vertical" + fill + 子元素 block;标签墙、筛选按钮组用wrap + size 数组;纯横向小组合直接裸用即可。wrap只对水平方向有意义,垂直模式下没有"换行"概念。
内部实现:间距到底是怎么注入的
Space 的全部逻辑集中在 packages/vant/src/space/Space.tsx,样式在 packages/vant/src/space/index.less,四个实现点决定了它的行为边界:
- 间距是内联 margin,不是 CSS 变量。渲染时每个子元素被包进
.van-space-item,由getMarginStyle计算内联样式:水平方向写margin-right,垂直方向或开启wrap时写margin-bottom。因此子项数量变化、动态渲染都能即时生效,不依赖兄弟选择器。 - 最后一项特殊处理。
getMarginStyle(isLast)对末项默认返回空样式,避免行尾/列尾出现多余空白;唯独wrap模式下末项保留margin-bottom,否则最后一行高度缺行距,下一行会贴上来。 - 空节点过滤。
filterEmpty递归展开 Fragment,剔除注释节点、空 Fragment 和纯空白文本节点。没有这一步,<van-space><A /><B /></van-space>中换行产生的文本节点会占据一个间距位,导致间距数量与子元素数量对不上。 - 类名走 BEM 规则。
createNamespace('space')生成的bem把direction、align、wrap、fill映射为van-space--vertical、van-space--align-center、van-space--wrap、van-space--fill等类名;align缺省时由mergedAlign计算属性回退为水平模式的'center'。
单元测试(packages/vant/src/space/test/index.spec.tsx)覆盖了默认 8px 右间距、末项无间距、垂直排列类名与下间距、自定义20px、align与wrap类名等核心行为;demo.spec.ts则以快照方式锁定演示页渲染结果。
避坑与最佳实践
fill与inline-flex的宽度差异:不开fill时 Space 是行内 Flex,宽度由内容决定,垂直模式下的子元素不会撑满父容器;需要通栏必须fill和子元素block同时给。size传字符串要带单位:数字才会自动补px,size="2rem"原样生效,size="20"会变成非法值20。wrap模式下末项也有margin-bottom:这是刻意行为(保证行距一致),如果容器本身又加了padding-bottom,注意叠加后的底部空隙。align只对水平模式有明显意义:垂直模式下align-items作用在纵向轴上,通常无需设置。- TS 项目用
SpaceProps标注 props 对象,SpaceSize、SpaceAlign可用于局部类型收窄,均从vant包根路径导入。
间距场景优先用van-space而不是手工 margin:间距语义集中在一处,增删子元素时布局不会错位,横纵、换行这些边界情况也已由组件内部处理完毕。
【免费下载链接】vantA lightweight, customizable Vue UI library for mobile web apps.项目地址: https://gitcode.com/GitHub_Trending/va/vant
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考