Skip to content

Layout 布局 - Vant 4

Layout 布局

📐 介绍

Layout 布局组件就像一位经验丰富的建筑师,为你的页面搭建起坚实而灵活的骨架 🏗️!通过 van-rowvan-col 这对黄金搭档,你可以轻松构建出各种复杂的页面布局。Row 就像是房屋的横梁,负责水平方向的整体规划;而 Col 则像是精心设计的房间,可以自由调整大小和位置。24列栅格系统让你拥有精确到毫厘的布局控制力,无论是简单的两栏布局还是复杂的多栏结构,都能信手拈来 ✨。

📦 引入

通过以下方式来全局注册组件,更多注册方式请参考组件注册

js
import { createApp } from'vue'; import { Col, Row } from'vant'; const app = createApp(); app.use(Col); app.use(Row);

🎯 代码演示

基础用法

24列栅格系统就像一把精密的尺子,为你的布局提供了无限可能 📏!通过在 Col 上设置 span 属性,你可以精确控制每一列的宽度占比,就像在画布上自由分配空间一样。而 offset 属性则像是一个贴心的间隔器,让你可以轻松创造出留白和错位效果,让布局更有层次感和呼吸感!

html

设置列元素间距

空间的艺术在于恰到好处的留白 🎨!gutter 属性就像是布局中的呼吸空间,通过设置合适的间距,让各个列元素之间保持优雅的距离。就像音乐中的休止符一样,这些间距让整个布局更加和谐悦目,避免了元素之间的拥挤感!

html

垂直间距

有时候,水平间距还不够,你还需要垂直方向的呼吸空间 🌬️!通过数组形式的 gutter 设置,你可以同时控制水平和垂直两个维度的间距。这就像是为你的布局增加了立体感,让页面不再是平面的排列,而是有了空间的层次!

html

对齐方式

对齐是布局美学的精髓所在 ✨!justify 属性就像是一位专业的排版师,帮你精确控制内容在主轴上的分布方式。无论是左对齐的严谨、居中对齐的平衡,还是两端对齐的饱满,都能让你的布局呈现出不同的视觉效果和情感表达!

html

API

Row Props

参数说明类型默认值
gutter列元素之间的间距(单位为 px)*numberstring
tag自定义元素标签stringdiv
justify主轴对齐方式,可选值为 end``center``space-around``space-betweenstringstart
align交叉轴对齐方式,可选值为 center``bottomstringtop
wrap是否自动换行booleantrue

Col Props

参数说明类型默认值
span列元素宽度*numberstring*
offset列元素偏移距离*numberstring*
tag自定义元素标签stringdiv

Row Events

事件名说明回调参数
click点击时触发event: MouseEvent

Col Events

事件名说明回调参数
click点击时触发event: MouseEvent

类型定义

组件导出以下类型定义:

ts
importtype { ColProps, RowProps, RowAlign, RowJustify } from'vant';

最佳实践

栅格系统设计原则

设计响应式布局时,应该遵循以下原则 📐:

html
<!-- ✅ 推荐:合理的栅格分配 -->
<van-row :gutter="20">
  <van-col :span="8">主要内容</van-col>
  <van-col :span="16">次要内容</van-col>
</van-row>

<!-- ❌ 避免:不合理的栅格分配 -->
<van-row>
  <van-col :span="23">内容过宽</van-col>
  <van-col :span="1">内容过窄</van-col>
</van-row>

响应式布局策略

html
<!-- 移动端优先的响应式设计 -->
<van-row :gutter="[16, 16]">
  <van-col 
    :span="24" 
    :class="{ 'desktop-half': isDesktop }"
  >
    <div class="content-block">内容区域</div>
  </van-col>
</van-row>

<style>
@media (min-width: 768px) {
  .desktop-half {
    flex: 0 0 50% !important;
    max-width: 50% !important;
  }
}
</style>

嵌套布局最佳实践

html
<!-- 复杂布局的嵌套使用 -->
<van-row :gutter="20">
  <van-col :span="16">
    <van-row :gutter="10">
      <van-col :span="12">子内容1</van-col>
      <van-col :span="12">子内容2</van-col>
    </van-row>
  </van-col>
  <van-col :span="8">侧边栏</van-col>
</van-row>

性能优化小贴士

减少不必要的重渲染

优化布局组件的性能表现 🚀:

javascript
// ✅ 推荐:使用计算属性优化响应式布局
const layoutConfig = computed(() => {
  if (screenWidth.value < 768) {
    return { span: 24, gutter: 16 };
  } else if (screenWidth.value < 1200) {
    return { span: 12, gutter: 20 };
  } else {
    return { span: 8, gutter: 24 };
  }
});

// 在模板中使用
<van-row :gutter="layoutConfig.gutter">
  <van-col :span="layoutConfig.span">
    内容
  </van-col>
</van-row>

避免过深的嵌套

html
<!-- ✅ 推荐:扁平化的布局结构 -->
<van-row :gutter="20">
  <van-col :span="8">内容1</van-col>
  <van-col :span="8">内容2</van-col>
  <van-col :span="8">内容3</van-col>
</van-row>

<!-- ❌ 避免:过深的嵌套层级 -->
<van-row>
  <van-col :span="24">
    <van-row>
      <van-col :span="24">
        <van-row>
          <van-col :span="24">内容</van-col>
        </van-row>
      </van-col>
    </van-row>
  </van-col>
</van-row>

设计建议

视觉层次

  • 主次分明:使用不同的列宽突出重要内容 📊
  • 间距统一:保持一致的间距规范 📏
  • 对齐规整:确保元素对齐整齐美观 📐
  • 留白合理:适当的留白让布局更透气 🌬️

响应式设计

  • 移动优先:从小屏幕开始设计,逐步适配大屏 📱
  • 断点合理:选择合适的响应式断点 💻
  • 内容适配:确保内容在不同屏幕下都能良好展示 🖥️

常见问题解决

Q: 如何实现不等高列的底部对齐?

html
<van-row align="bottom" :gutter="20">
  <van-col :span="8">
    <div class="content-box">
      <p>短内容</p>
    </div>
  </van-col>
  <van-col :span="8">
    <div class="content-box">
      <p>这是一段比较长的内容</p>
      <p>包含多行文字</p>
    </div>
  </van-col>
  <van-col :span="8">
    <div class="content-box">
      <p>中等长度的内容</p>
    </div>
  </van-col>
</van-row>

<style>
.content-box {
  height: 100%;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
}
</style>

Q: 如何实现响应式的栅格布局?

javascript
// 使用组合式 API 实现响应式布局
import { ref, computed, onMounted, onUnmounted } from 'vue';

export default {
  setup() {
    const screenWidth = ref(window.innerWidth);
    
    const updateScreenWidth = () => {
      screenWidth.value = window.innerWidth;
    };
    
    const colSpan = computed(() => {
      if (screenWidth.value < 576) return 24;      // 手机
      if (screenWidth.value < 768) return 12;      // 平板竖屏
      if (screenWidth.value < 992) return 8;       // 平板横屏
      if (screenWidth.value < 1200) return 6;      // 小桌面
      return 4;                                    // 大桌面
    });
    
    onMounted(() => {
      window.addEventListener('resize', updateScreenWidth);
    });
    
    onUnmounted(() => {
      window.removeEventListener('resize', updateScreenWidth);
    });
    
    return { colSpan };
  }
};

Q: 如何实现动态的栅格间距?

html
<template>
  <div>
    <van-slider 
      v-model="gutterValue" 
      :min="0" 
      :max="40" 
      @change="handleGutterChange"
    />
    
    <van-row :gutter="dynamicGutter">
      <van-col :span="8">内容1</van-col>
      <van-col :span="8">内容2</van-col>
      <van-col :span="8">内容3</van-col>
    </van-row>
  </div>
</template>

<script>
const gutterValue = ref(20);
const dynamicGutter = computed(() => [gutterValue.value, gutterValue.value]);

const handleGutterChange = (value) => {
  console.log('间距变更为:', value);
};
</script>

高级用法示例

卡片式布局

html
<template>
  <van-row :gutter="[16, 16]">
    <van-col 
      v-for="card in cardList" 
      :key="card.id"
      :span="cardSpan"
    >
      <div class="card-container">
        <div class="card-header">{{ card.title }}</div>
        <div class="card-content">{{ card.content }}</div>
        <div class="card-footer">{{ card.date }}</div>
      </div>
    </van-col>
  </van-row>
</template>

<style>
.card-container {
  background: #fff;
  border-radius: 8px;
  padding: 16px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  height: 100%;
  display: flex;
  flex-direction: column;
}

.card-header {
  font-weight: bold;
  margin-bottom: 12px;
}

.card-content {
  flex: 1;
  color: #666;
  line-height: 1.5;
}

.card-footer {
  margin-top: 12px;
  font-size: 12px;
  color: #999;
}
</style>

仪表板布局

html
<template>
  <div class="dashboard">
    <!-- 顶部统计区域 -->
    <van-row :gutter="20" class="stats-row">
      <van-col :span="6" v-for="stat in stats" :key="stat.id">
        <div class="stat-card">
          <div class="stat-value">{{ stat.value }}</div>
          <div class="stat-label">{{ stat.label }}</div>
        </div>
      </van-col>
    </van-row>
    
    <!-- 主要内容区域 -->
    <van-row :gutter="20" class="content-row">
      <van-col :span="16">
        <div class="chart-container">
          <!-- 图表组件 -->
        </div>
      </van-col>
      <van-col :span="8">
        <div class="sidebar-container">
          <!-- 侧边栏内容 -->
        </div>
      </van-col>
    </van-row>
  </div>
</template>

相关组件

延伸阅读

基於Vant構建的企業級移動端解決方案