#

作者卡片组件开发

By DoubleSpirit121 1 Views 21 MIN READ 0 Comments
详细介绍如何开发一个高性能的作者卡片组件AuthorCard,用于在VitePress中展示作者信息。涵盖组件需求分析、Vue3+TypeScript代码实现、组件注册方法、随机马卡龙色背景、插槽传值、响应式布局与暗色模式适配等核心功能的完整开发流程,还包含将长文本内容作为插槽传递以避免特殊字符解析问题的技巧。

概述

本文介绍如何开发一个美观的作者卡片组件 AuthorCard,用于在 VitePress 中展示作者信息、简介和许可证等内容。

组件需求

  1. 圆角矩形卡片设计
  2. 左上角作者头像(支持本地图片和图链)
  3. 作者名点击跳转链接
  4. 副名称显示(斜体)
  5. 简介内容(支持多行文本和链接)
  6. 许可证显示
  7. 随机马卡龙色渐变背景
  8. 悬浮动效
  9. 响应式适配

组件代码

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

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

interface Props {
  avatar: string
  name: string
  link?: string
  subtitle?: string
  license?: string
}

const props = withDefaults(defineProps<Props>(), {
  link: '#',
  subtitle: '',
  license: ''
})

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

const randomColor = computed(() => {
  const index = Math.floor(Math.random() * macaronColors.length)
  return macaronColors[index]
})
</script>

<template>
  <div class="author-card" :style="{ background: `linear-gradient(180deg, ${randomColor.bg} 0%, ${randomColor.bgEnd} 100%)` }">
    <div class="avatar">
      <img :src="avatar" :alt="name" />
    </div>
    <div class="content">
      <a v-if="link" :href="link" class="name" target="_blank">{{ name }}</a>
      <span v-else class="name">{{ name }}</span>
      <span v-if="subtitle" class="subtitle">{{ subtitle }}</span>
      <div v-if="$slots.description" class="description">
        <slot name="description" />
      </div>
      <span v-if="license" class="license">许可证:{{ license }}</span>
    </div>
  </div>
</template>

<style scoped lang="scss">
.author-card {
  display: flex;
  gap: 16px;
  padding: 16px 20px;
  border-radius: 12px;
  border: none;
  margin: 1.5rem 0;
  backdrop-filter: blur(10px);
  transition: transform 0.3s ease, box-shadow 0.3s ease;

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

.avatar {
  flex-shrink: 0;
  width: 56px;
  height: 56px;
  border-radius: 50%;
  overflow: hidden;

  img {
    width: 100%;
    height: 100%;
    object-fit: cover;
  }
}

.content {
  flex: 1;
  min-width: 0;
}

.name {
  display: block;
  font-size: 1.1rem;
  font-weight: 600;
  color: var(--vp-c-text-1);
  text-decoration: none;
  transition: color 0.3s ease;

  &:hover {
    color: var(--vp-c-brand);
  }

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

.subtitle {
  display: block;
  font-size: 0.9rem;
  color: var(--vp-c-text-3);
  font-style: italic;
}

.description {
  margin: 8px 0;
  font-size: 0.95rem;
  color: var(--vp-c-text-2);
  line-height: 1.5;
}

.license {
  display: inline-block;
  font-size: 0.8rem;
  color: var(--vp-c-text-2);
  padding: 2px 8px;
  background: rgba(0, 0, 0, 0.1);
  border-radius: 4px;
}

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

  .avatar {
    width: 48px;
    height: 48px;
  }

  .name {
    font-size: 1rem;
  }

  .description {
    font-size: 0.9rem;
  }
}
</style>

注册组件

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

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

export default {
  enhanceApp({ app }: { app: any }) {
    app.component('AuthorCard', AuthorCard);
  },
};

使用方法

基础用法

<AuthorCard 
  avatar="/avatar.png" 
  name="作者名称" 
  link="https://example.com"
  subtitle="副名称"
  license="MIT"
>
  <template #description>
    这里是多行简介内容
  </template>
</AuthorCard>

完整示例

<AuthorCard 
  avatar="/mcoo/avatar.png" 
  name="凉宫山风" 
  link="https://space.bilibili.com/39934370" 
  subtitle="Y_Suzumiya"
  license="CC BY-NC-SA 4.0" 
>
  <template #description>
    来自@方块工程师杯官方 比赛瑞士轮第四轮的赛博马场,快来和xdm来一场紧张刺激的赛马罢*<br><br>
    感兴趣的兄弟们可以进群一起赤石awa~:927868234<br><br>
    ----------------------------<br><br>
    Mcoo服务器基于 Fabric 1.21 的原版生存玩法运行...
  </template>
</AuthorCard>

关键实现点

1. 使用插槽传递长文本

当需要传递包含特殊字符的多行文本时,使用 prop 传值会导致解析错误。解决方案是使用 Vue 插槽:

<div v-if="$slots.description" class="description">
  <slot name="description" />
</div>

使用时通过 <template #description> 传递内容:

<AuthorCard ...>
  <template #description>
    多行文本内容...
  </template>
</AuthorCard>

2. 随机马卡龙色背景

使用 computedMath.random() 实现每次渲染随机选择颜色:

const macaronColors = [
  { bg: 'rgba(255, 182, 193, 0.25)', bgEnd: 'rgba(255, 182, 193, 0.05)' },
  // ... 更多颜色
]

const randomColor = computed(() => {
  const index = Math.floor(Math.random() * macaronColors.length)
  return macaronColors[index]
})

背景使用渐变,从顶部颜色到底部透明:

:style="{ background: `linear-gradient(180deg, ${randomColor.bg} 0%, ${randomColor.bgEnd} 100%)` }"

3. 屏蔽链接图标

由于我们之前为外部链接添加了图标,所以需要通过 CSS 屏蔽:

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

4. 响应式适配

使用媒体查询调整移动端样式:

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

  .avatar {
    width: 48px;
    height: 48px;
  }
}

组件参数说明

参数说明类型默认值
avatar头像图片地址string-
name作者名称string-
link作者链接string#
subtitle副名称(斜体)string''
license许可证文本string''
插槽说明
description简介内容,支持 HTML 标签

本文由 DoubleSpirit121 原创

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

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

加入 Mcoo

0 评论

发表评论