第 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 设计
相关推荐
java1234_小锋5 小时前
【技术专题】HTML5 网页技术 - HTML5 Canvas 基础以及动画入门
前端·html·html5
知了学历孙老师8 小时前
小自考的校考和统考,出题方和难度差在哪
java·大数据·前端
ShineWinsu10 小时前
对于JavaScript:操作元素的解析
开发语言·前端·javascript·面试·web·dom·元素
福兮说11 小时前
JSON 格式正确,数据就可靠吗?我用一份自编配置检查类型与空值
java·前端·json
xhyu6112 小时前
【学习笔记】图像质量评估方法 (5.生成图像是否符合用户要求)
笔记·学习·计算机视觉
程序员老赵13 小时前
Docker 部署青龙面板:轻松搭建定时任务管理平台
前端·docker·开源
Swot13 小时前
Asciidoctor 公式数字下标错位问题:原因分析与解决方案
前端
Swot13 小时前
leo-editor 中将 Markdown 内容转成 asciidoc 格式
前端
狒狒AI13 小时前
Remotion / GSAP+Three / HyperFrames / Skia 四栈实测:代码渲染知识视频的选栈方法(附开源技能)
前端·人工智能·aigc
修炼的dance13 小时前
浏览器里导出H.265,8.5秒和55.5秒差在硬件
前端