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構建的企業級移動端解決方案