第 4 篇:布局骨架——页面壳、栅格、卡片

第 4 篇:布局骨架------页面壳、栅格、卡片

本篇目标

把「统一布局」做成几个固定的布局组件。之后每个页面 = 布局骨架 + 一份 schema,

AI 不碰布局,布局由这几个组件锁定。

1. 布局拆成四个固定件

组件 职责 放哪
PageShell 整个页面的外层:内边距、最大宽度、纵向节奏 src/components/layout/PageShell.vue
PageHeader 页头:标题 + 右侧操作区 src/components/layout/PageHeader.vue
SectionCard 内容卡片:白底、圆角、可带标题 src/components/layout/SectionCard.vue
FormGrid 表单单栅格:字段按列排布、自动换行 src/components/layout/FormGrid.vue

这四个组件是本系列自研的,代码很短、可自由改。布局规则全部内聚在这里,

后续所有页面共用,等于「布局写死」的落地实现。

2. 逐个实现

PageShell.vue

vue 复制代码
<script setup lang="ts">
defineProps<{ maxWidth?: string }>()
</script>

<template>
  <div class="min-h-screen bg-background">
    <main
      class="mx-auto w-full px-[var(--spacing-page)] py-[var(--spacing-page)]"
      :style="{ maxWidth: maxWidth ?? '960px' }"
    >
      <slot />
    </main>
  </div>
</template>

PageHeader.vue

vue 复制代码
<script setup lang="ts">
defineProps<{ title: string; description?: string }>()
</script>

<template>
  <div class="mb-[var(--spacing-page)] flex flex-wrap items-center justify-between gap-4">
    <div>
      <h1 class="text-[var(--text-title)] font-semibold text-foreground">{{ title }}</h1>
      <p v-if="description" class="mt-1 text-[var(--text-caption)] text-muted-foreground">
        {{ description }}
      </p>
    </div>
    <div class="flex items-center gap-2"><slot name="actions" /></div>
  </div>
</template>

SectionCard.vue

vue 复制代码
<script setup lang="ts">
defineProps<{ title?: string }>()
</script>

<template>
  <section class="rounded-[var(--radius-lg)] border border-border bg-card p-[var(--spacing-card)]">
    <h2 v-if="title" class="mb-4 text-[var(--text-body)] font-semibold text-foreground">
      {{ title }}
    </h2>
    <slot />
  </section>
</template>

FormGrid.vue

vue 复制代码
<script setup lang="ts">
import { computed } from 'vue'

const props = defineProps<{ columns?: number }>()
// 每格最小宽度,窄屏自动换行成单列
const style = computed(() => ({
  gridTemplateColumns: `repeat(${props.columns ?? 2}, minmax(0, 1fr))`,
}))
</script>

<template>
  <div class="grid gap-[var(--spacing-field)]" :style="style">
    <slot />
  </div>
</template>

说明:columns 默认 2 列。移动端如果想强制单列,可在 FormGrid 内加一条媒体查询,

或用 Tailwind 的响应式类自行调整(本系列保持简单,字段多时第 6 篇的 span 属性可跨列)。

3. 组合成一个「固定壳」示例

vue 复制代码
<script setup lang="ts">
import PageShell from '@/components/layout/PageShell.vue'
import PageHeader from '@/components/layout/PageHeader.vue'
import SectionCard from '@/components/layout/SectionCard.vue'
import FormGrid from '@/components/layout/FormGrid.vue'
import { Button } from '@/components/ui/button'
</script>

<template>
  <PageShell>
    <PageHeader title="客户资料" description="统一样式的表单页示例">
      <template #actions><Button>保存</Button></template>
    </PageHeader>

    <SectionCard title="基本信息">
      <FormGrid :columns="2">
        <div>(这里放第 6 篇的 SchemaForm 渲染结果)</div>
      </FormGrid>
    </SectionCard>
  </PageShell>
</template>

4. 为什么这能锁死布局

  • 页边距、最大宽度、卡片圆角、字段间距,全部在四个组件里写死
  • 新页面只需「用这四个组件拼壳 + 塞 schema」,布局不可能歪
  • AI 无论生成多少页,都进同一个壳

5. 验证

  1. 复制上面代码,跑 pnpm dev,确认标题 / 卡片 / 操作区位置正常。
  2. 把 FormGrid 的 columns 改成 3,看是否自动变三列;缩窄浏览器窗口到手机宽度,确认能换行。
  3. 修改 --spacing-page(第 3 篇变量),整页留白跟着变 → 布局与 Tokens 联动成功。

本篇小结

  • 布局被收敛成 PageShell / PageHeader / SectionCard / FormGrid 四个组件
  • 所有页面共用,布局固定
  • 下一步定义「每次变」的那部分------第 5 篇:Schema 设计
相关推荐
LucianaiB16 小时前
【元宝搜索开发者征文大赛】AI时代,学得慢就不用学?用元宝搜索打造一个教程保质期,确保每一个教程符合你的现状
前端·人工智能·ai编程
excel16 小时前
JavaScript 对象池:减少高频对象创建与 GC 压力
前端
陈随易18 小时前
纯 Go 写的 JS 引擎,跑分超过了 C 语言的 QuickJS
前端·后端·程序员
LongRunning18 小时前
【Linux】RK3568-OpenCV+YOLO(八)
linux·opencv·yolo
子兮曰19 小时前
Chrome 权限元素实战:144 与 151 的渐进增强写法
前端·javascript·chrome
IT_陈寒20 小时前
Redis连接池泄漏那次,我差点把生产环境搞崩了
前端·人工智能·后端
强尼银手20 小时前
我花一天做了个格斗游戏原型,判定全对,然后被「美术」劝退了
前端·javascript
石小石Orz20 小时前
AI 正在蚕食我们的编码能力
前端·后端·算法
陈随易21 小时前
专注飞机 FocusFlight,两个人把番茄钟做成了一趟航班
前端·后端·程序员
GrowingIO技术社区21 小时前
用户行为分析怎么做?从业务目标到改进验证的完整流程
大数据·数据挖掘·数据分析