首页中间区域开发
本节聚焦首页中间区域的内容展示模块,包括项目推荐卡片列表和官方课程列表,核心知识点涵盖 Grid 响应式布局、Hover 交互效果和 Vue 深度选择器。
响应式 Grid 布局
使用 UnoCSS 的 Grid 工具类实现响应式多列布局:
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-3 lt-sm:px-4">
<a
v-for="(item, index) in projects"
:key="index"
:href="item.url"
target="_blank"
class="card flex transition-all"
>
<Card :title="item.title" :subtitle="item.subtitle">
<template #footer>
<div class="flex items-center justify-between mx-4 text-gray-500">
<span>查看更多</span>
<Icon icon="mdi:arrow-right-thin" :width="20" />
</div>
</template>
</Card>
</a>
</div>
vue
Grid 与 Flex 的对比
| 特性 | Grid 布局 | Flex 布局 |
|---|---|---|
| 维度 | 二维(行列同时控制) | 一维(主轴方向) |
| 等宽分配 | grid-cols-* 自动等宽 | 需要手动设置宽度 |
| 删除元素 | 自动重新排列,保持等宽 | 需要额外处理对齐 |
| 跨行跨列 | 原生支持 | 不支持 |
| 适用场景 | 网格卡片、图片墙 | 导航栏、行内排列 |
响应式断点说明:
grid-cols-1-- 默认单列(移动端)md:grid-cols-2-- 768px 以上双列lg:grid-cols-4-- 1024px 以上四列lt-sm:px-4-- 小于 640px 时添加左右内边距
Hover 交互效果实现
卡片上浮效果
目标效果:鼠标悬停时卡片上浮、添加阴影、文字变白。
首先尝试 Tailwind/UnoCSS 原子类方案:
<a class="hover:(shadow-lg -translate-y-1 text-white)">
<Card />
</a>
vue
问题:Card 组件内部通过 Props 设置的 title 和 subtitle 文字颜色无法被外层 class 覆盖,因为 Vue 的 Scoped 样式会为组件内部的元素生成独立的 scoped ID。
group-hover 方案
<a class="group">
<Card class="group-hover:text-white" />
</a>
vue
局限性:group-hover 只能作用于 Card 组件的根元素,无法穿透到内部的 <p> 标签。
深度选择器方案(推荐)
使用 Vue 的 :deep() 选择器穿透 Scoped 样式边界:
<template>
<a class="card transition-all">
<Card />
</a>
</template>
<style lang="scss" scoped>
.card {
transition: all 0.3s ease;
&:hover {
transform: translateY(-4px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
// 深度选择器穿透子组件
:deep(p) {
color: white;
}
}
}
</style>
vue
深度选择器语法对比
| Vue 版本 | 语法 | 说明 |
|---|---|---|
| Vue 2 | ::v-deep .class | 已废弃 |
| Vue 3 | :deep(.class) | 推荐写法 |
| SCSS | ::v-deep(.class) | SCSS 中可用 |
| 通用 | >>> .class | 非 SCSS 场景 |
完整的 Hover 效果清单
.card {
// 过渡动画
transition: all 0.3s ease;
&:hover {
// 上浮效果
transform: translateY(-4px);
// 阴影效果
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
// 文字颜色穿透
:deep(p) {
color: white;
}
}
}
scss
三个关键效果:
- 上浮 --
transform: translateY(-4px),产生轻微浮起感 - 阴影 --
box-shadow添加柔和投影,增强层次感 - 文字变白 --
:deep()穿透子组件,统一改变文字颜色
Mock 数据结构
项目列表的数据模型:
const projects = [
{
title: '前端高级工程师',
subtitle: '从入门到精通',
icon: 'mdi:language-javascript',
url: '/course/frontend',
},
// ... 更多项目数据
]
typescript
Card 组件的 Footer 插槽
Card 组件预留了 #footer 插槽,用于自定义底部内容:
<Card :title="item.title" :subtitle="item.subtitle">
<template #footer>
<div class="flex items-center justify-between text-gray-500">
<span>查看更多</span>
<Icon icon="mdi:arrow-right-thin" :width="20" />
</div>
</template>
</Card>
vue
官方课程列表
官方课程部分的实现与项目列表结构一致,主要差异在于 Grid 列数:
<!-- 三列布局 -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-3">
<!-- 课程卡片 -->
</div>
vue
关键收获
- Grid 布局天然支持等宽分配和响应式断点,适合卡片网格场景
:deep()是 Vue 3 中穿透 Scoped 样式边界的标准方案- Hover 效果三件套:上浮 + 阴影 + 文字变色,提升交互体验
- 组件设计时应预留具名插槽(如
#footer),增强灵活性
↑