#

下载卡片组件开发

By DoubleSpirit121 1 Views 21 MIN READ 0 Comments
详细介绍如何开发一个高性能的下载卡片组件DownloadCard,用于在VitePress中展示资源下载链接。涵盖组件需求分析、Vue3+TypeScript代码实现、组件注册方法、随机马卡龙色背景、按钮文字动态切换、响应式布局与暗色模式适配等核心功能的完整开发流程。

下载卡片组件开发

组件需求

在资源下载页面中,我们需要一个能够集中展示多个下载链接的卡片组件,满足以下需求:

  • 支持多个下载链接,每个链接单独显示为一个卡片
  • 每个卡片显示:名称、描述、下载按钮
  • 根据链接类型动态切换按钮文字(下载/前往)
  • 卡片使用随机马卡龙色背景,每次刷新或添加新卡片时颜色不同
  • 响应式设计,适配移动端和桌面端
  • 悬浮动效提升用户体验

组件实现

创建文件 docs/.vitepress/theme/components/DownloadCard.vue

<script setup lang="ts">
import { computed } from 'vue'

interface DownloadItem {
  name: string
  url: string
  description?: string
}

interface Props {
  downloads: DownloadItem[]
}

const props = defineProps<Props>()

const macaronColors = [
  'rgba(255, 182, 193, 0.25)',
  'rgba(173, 216, 230, 0.25)',
  'rgba(144, 238, 144, 0.25)',
  'rgba(255, 218, 185, 0.25)',
  'rgba(221, 160, 221, 0.25)',
  'rgba(175, 238, 238, 0.25)',
  'rgba(255, 255, 224, 0.25)',
  'rgba(230, 230, 250, 0.25)',
]

const getRandomColor = (index: number) => {
  return macaronColors[index % macaronColors.length]
}

const getBtnText = (url: string) => {
  if (url.includes('qm.qq.com') || url.includes('qq.com')) {
    return '立即前往'
  }
  return '立即下载'
}
</script>

<template>
  <div v-if="downloads && downloads.length > 0" class="download-section">
    <div 
      v-for="(item, index) in downloads" 
      :key="index" 
      class="download-card"
      :style="{ backgroundColor: getRandomColor(index) }"
    >
      <div class="download-icon">
        <svg viewBox="0 0 24 24" width="24" height="24">
          <path fill="currentColor" d="M19 9h-4V3H9v6H5l7 7 7-7zM5 18v2h14v-2H5z"/>
        </svg>
      </div>
      <div class="download-content">
        <div class="download-header">
          <span class="download-name">{{ item.name }}</span>
        </div>
        <p v-if="item.description" class="download-desc">{{ item.description }}</p>
        <a :href="item.url" class="download-btn" target="_blank">
          <span>{{ getBtnText(item.url) }}</span>
          <svg viewBox="0 0 24 24" width="16" height="16">
            <path fill="currentColor" d="M19 9h-4V3H9v6H5l7 7 7-7zM5 18v2h14v-2H5z"/>
          </svg>
        </a>
      </div>
    </div>
  </div>
</template>

<style scoped lang="scss">
.download-section {
  display: flex;
  flex-direction: column;
  gap: 16px;
  margin: 1.5rem 0;
}

.download-card {
  display: flex;
  gap: 16px;
  padding: 16px 20px;
  border-radius: 12px;
  border: none;
  backdrop-filter: blur(10px);
  transition: all 0.3s ease;

  &:hover {
    transform: translateY(-2px);
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
  }
}

.download-icon {
  flex-shrink: 0;
  width: 48px;
  height: 48px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(255, 255, 255, 0.4);
  border-radius: 12px;
  color: var(--vp-c-text-1);
}

.download-content {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.download-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.download-name {
  font-size: 1.1rem;
  font-weight: 600;
  color: var(--vp-c-text-1);

  &::before {
    display: none !important;
  }
}

.download-desc {
  font-size: 0.9rem;
  color: var(--vp-c-text-2);
  line-height: 1.5;
  margin: 0;
}

.download-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 8px 16px;
  background: rgba(0, 0, 0, 0.15);
  color: var(--vp-c-text-1);
  border-radius: 8px;
  text-decoration: none;
  font-size: 0.9rem;
  font-weight: 500;
  transition: all 0.3s ease;
  width: fit-content;
  border: none;

  &:hover {
    background: rgba(0, 0, 0, 0.25);
    transform: translateY(-1px);
  }

  svg {
    flex-shrink: 0;
  }

  &::before {
    display: none !important;
  }
}

@media (max-width: 640px) {
  .download-card {
    padding: 12px 16px;
    gap: 12px;
  }

  .download-icon {
    width: 40px;
    height: 40px;
  }

  .download-name {
    font-size: 1rem;
  }
}
</style>

组件注册

docs/.vitepress/theme/index.ts 中注册组件:

import DownloadCard from "./components/DownloadCard.vue";

export default {
  enhanceApp({ app }) {
    app.component('DownloadCard', DownloadCard);
  },
}

组件使用

在 Markdown 文件中使用:

<DownloadCard :downloads="[
  { name: 'Github', url: 'https://github.com/xxx/release.zip', description: '官方下载地址,可能需要代理' },
  { name: 'Github 加速', url: 'https://gh-proxy.org/https://github.com/xxx/release.zip', description: '使用 Gh Proxy 加速下载' },
  { name: '百度网盘', url: 'https://pan.baidu.com/s/xxx?pwd=xxxx', description: '使用百度网盘进行下载,提取码:xxxx' },
  { name: 'QQ群', url: 'https://qm.qq.com/q/xxx', description: '加入 QQ 群下载资源' }
]" />

关键实现点

1. 随机马卡龙色背景

通过数组存储多种马卡龙色,使用索引取模实现每个卡片不同的颜色:

const macaronColors = [
  'rgba(255, 182, 193, 0.25)',  // 粉色
  'rgba(173, 216, 230, 0.25)',  // 浅蓝色
  'rgba(144, 238, 144, 0.25)',  // 浅绿色
  // ... 更多颜色
]

const getRandomColor = (index: number) => {
  return macaronColors[index % macaronColors.length]
}

2. 按钮文字动态切换

根据链接类型动态显示不同的按钮文字,QQ链接显示"立即前往",其他链接显示"立即下载":

const getBtnText = (url: string) => {
  if (url.includes('qm.qq.com') || url.includes('qq.com')) {
    return '立即前往'
  }
  return '立即下载'
}

3. 屏蔽链接图标

通过 CSS 伪元素 ::before 屏蔽主题自带的链接图标:

.download-name, .download-btn {
  &::before {
    display: none !important;
  }
}

4. 响应式设计

使用媒体查询适配移动端:

@media (max-width: 640px) {
  .download-card {
    padding: 12px 16px;
    gap: 12px;
  }
  .download-icon {
    width: 40px;
    height: 40px;
  }
}

参数说明

参数类型必填说明
downloadsDownloadItem[]下载项数组

DownloadItem 类型

参数类型必填说明
namestring下载项名称
urlstring下载链接
descriptionstring下载项描述

本文由 DoubleSpirit121 原创

采用 CC BY-NC-SA 4.0 协议进行许可

转载请注明出处:https://blog.mcoo.top/index.php/archives/41/

加入 Mcoo

0 评论

发表评论