Skip to content
0

vue3版-放到teek里

问题

针对上面的代码, 帮我生成 的vue3版本的组件,不要使用Tailwind CSS,样式直接使用普通css写在组件内。

回答

我重新检查了背景样式,发现是渐变效果不够明显且部分样式被覆盖导致粉色不突出。以下是修复后的版本,确保背景粉色系效果清晰可见:

vue
<template>
  <div class="container">
    <!-- 背景装饰元素 -->
    <div class="bg-decoration">
      <div class="heart-decoration" style="top: 10%; left: 5%; animation-delay: 0s;"></div>
      <div class="heart-decoration" style="top: 20%; right: 10%; animation-delay: 1s;"></div>
      <div class="heart-decoration" style="bottom: 30%; left: 15%; animation-delay: 2s;"></div>
      <div class="heart-decoration" style="bottom: 20%; right: 5%; animation-delay: 3s;"></div>
      <div class="heart-decoration" style="top: 40%; right: 20%; animation-delay: 1.5s;"></div>
    </div>

    <!-- 标题区域 -->
    <header class="header">
      <h1 class="main-title">我们的爱情计时器</h1>
      <p class="subtitle">记录从相遇的那一刻起,每一段珍贵的时光</p>
      <div class="divider">
        <div class="divider-dot"></div>
      </div>
    </header>

    <!-- 情侣头像区域 -->
    <div class="avatar-container">
      <!-- 左侧头像 -->
      <div class="avatar-wrapper left-avatar">
        <img src="https://picsum.photos/seed/lover1/200" alt="情侣头像1" class="avatar-image">
        <div class="gender-indicator male">
          <span class="icon">♂</span>
        </div>
      </div>
      
      <!-- 中间跳动的爱心 -->
      <div class="heart-connector">
        <div class="heart-pulse"></div>
        <div class="heart-icon">❤</div>
      </div>
      
      <!-- 右侧头像 -->
      <div class="avatar-wrapper right-avatar">
        <img src="https://picsum.photos/seed/lover2/200" alt="情侣头像2" class="avatar-image">
        <div class="gender-indicator female">
          <span class="icon">♀</span>
        </div>
      </div>
    </div>

    <!-- 相识日期展示 -->
    <div class="meet-date">
      我们相识于:<span class="highlight">2025年5月29日 17:00</span>
    </div>

    <!-- 计时器主区域 -->
    <div class="timer-grid">
      <!-- 年 -->
      <div class="timer-card">
        <div :class="{'number-change': isChanged.years}" class="time-value">{{ years }}</div>
        <div class="time-label">年</div>
      </div>
      
      <!-- 月 -->
      <div class="timer-card">
        <div :class="{'number-change': isChanged.months}" class="time-value">{{ months }}</div>
        <div class="time-label">月</div>
      </div>
      
      <!-- 日 -->
      <div class="timer-card">
        <div :class="{'number-change': isChanged.days}" class="time-value">{{ days }}</div>
        <div class="time-label">日</div>
      </div>
      
      <!-- 时 -->
      <div class="timer-card">
        <div :class="{'number-change': isChanged.hours}" class="time-value">{{ hours }}</div>
        <div class="time-label">时</div>
      </div>
      
      <!-- 分 -->
      <div class="timer-card">
        <div :class="{'number-change': isChanged.minutes}" class="time-value">{{ minutes }}</div>
        <div class="time-label">分</div>
      </div>
      
      <!-- 秒 -->
      <div class="timer-card">
        <div :class="{'number-change': isChanged.seconds}" class="time-value">{{ seconds }}</div>
        <div class="time-label">秒</div>
      </div>
    </div>

    <!-- 爱情寄语 -->
    <div class="love-message">
      <p>"时光荏苒,爱意渐浓<br>每一秒都是我们爱情的见证"</p>
      <div class="message-heart">❤</div>
    </div>

    <!-- 页脚 -->
    <footer class="footer">
      愿我们的故事,永远继续下去...
    </footer>
  </div>
</template>

<script setup>
import { ref, onMounted, onUnmounted } from 'vue';

// 时间数据
const years = ref(0);
const months = ref(0);
const days = ref(0);
const hours = ref(0);
const minutes = ref(0);
const seconds = ref(0);

// 用于检测数值变化的状态
const isChanged = ref({
  years: false,
  months: false,
  days: false,
  hours: false,
  minutes: false,
  seconds: false
});

// 存储上一次的值
let previousValues = {
  years: 0,
  months: 0,
  days: 0,
  hours: 0,
  minutes: 0,
  seconds: 0
};

// 相识日期:2025年5月29日17:00
const meetDate = new Date(2025, 4, 29, 17, 0, 0);
let timer = null;

// 计算时间差
function calculateTimeDifference() {
  const now = new Date();
  const diff = now - meetDate;

  // 计算总秒数
  const totalSeconds = Math.floor(diff / 1000);
  
  // 计算秒
  const seconds = totalSeconds % 60;
  
  // 计算总分钟数
  const totalMinutes = Math.floor(totalSeconds / 60);
  const minutes = totalMinutes % 60;
  
  // 计算总小时数
  const totalHours = Math.floor(totalMinutes / 60);
  const hours = totalHours % 24;
  
  // 计算总天数
  const totalDays = Math.floor(totalHours / 24);
  
  // 计算年、月、日
  let years = 0;
  let months = 0;
  let remainingDays = totalDays;
  
  // 计算年数(按365天计算)
  years = Math.floor(remainingDays / 365);
  remainingDays = remainingDays % 365;
  
  // 计算月数(按平均30.44天计算)
  months = Math.floor(remainingDays / 30.44);
  const days = Math.floor(remainingDays % 30.44);
  
  return { years, months, days, hours, minutes, seconds };
}

// 更新计时器显示
function updateTimer() {
  const timeDiff = calculateTimeDifference();
  
  // 检查每个值是否变化,更新并添加动画
  Object.keys(timeDiff).forEach(key => {
    const value = timeDiff[key];
    const displayValue = ['hours', 'minutes', 'seconds'].includes(key) 
      ? value.toString().padStart(2, '0') 
      : value;
      
    if (previousValues[key] !== value) {
      // 更新值
      eval(`${key}.value = '${displayValue}'`);
      // 触发动画
      isChanged.value[key] = true;
      setTimeout(() => {
        isChanged.value[key] = false;
      }, 500);
      // 更新上一次的值
      previousValues[key] = value;
    }
  });
}

// 组件挂载时初始化计时器
onMounted(() => {
  updateTimer();
  timer = setInterval(updateTimer, 1000);
});

// 组件卸载时清除计时器
onUnmounted(() => {
  if (timer) clearInterval(timer);
});
</script>

<style>
/* 全局样式 - 确保背景样式全局生效 */
:root {
  --color-love-light: #FFD1DC; /* 浅粉色 */
  --color-love: #FF69B4; /* 粉色 */
  --color-love-dark: #C71585; /* 深粉色 */
  --color-romantic-light: #E6E6FA; /* 浅紫色 */
  --color-romantic-dark: #9370DB; /* 深紫色 */
  --shadow-soft: 0 4px 15px rgba(0, 0, 0, 0.05);
  --shadow-medium: 0 10px 25px -5px rgba(255, 105, 180, 0.3);
}

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
</style>

<style scoped>
/* 容器样式 - 强化粉色背景 */
.container {
  min-height: 100vh;
  /* 增强粉色占比,让粉色更明显 */
  background: linear-gradient(135deg, 
    var(--color-love-light) 20%, 
    var(--color-romantic-light) 50%, 
    var(--color-love-light) 80%);
  color: #333;
  padding: 20px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  position: relative;
  overflow: hidden;
}

/* 背景装饰 */
.bg-decoration {
  position: fixed;
  width: 100%;
  height: 100%;
  top: 0;
  left: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
}

.heart-decoration {
  position: absolute;
  color: var(--color-love);
  font-size: 40px;
  opacity: 0.15; /* 降低透明度,避免掩盖背景色 */
  animation: float 6s ease-in-out infinite, heartbeat 1.5s ease-in-out infinite;
}

.heart-decoration::before {
  content: '❤';
}

/* 标题区域 */
.header {
  text-align: center;
  margin: 20px 0 30px;
  z-index: 1;
  width: 100%;
  max-width: 600px;
}

.main-title {
  font-family: 'Dancing Script', cursive;
  font-size: clamp(2.5rem, 8vw, 4.5rem);
  font-weight: 700;
  color: var(--color-love-dark);
  margin-bottom: 15px;
  text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.15);
  line-height: 1.2;
}

.subtitle {
  font-family: 'Montserrat', sans-serif;
  font-size: clamp(1rem, 2vw, 1.25rem);
  color: #666;
  max-width: 400px;
  margin: 0 auto 20px;
  line-height: 1.5;
}

.divider {
  width: 100px;
  height: 2px;
  background: linear-gradient(to right, transparent, var(--color-love), transparent);
  margin: 0 auto;
  position: relative;
}

.divider-dot {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background-color: var(--color-love);
  animation: pulse 4s ease-in-out infinite;
}

/* 头像区域 */
.avatar-container {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  max-width: 500px;
  margin-bottom: 30px;
  z-index: 1;
  gap: 20px;
}

.avatar-wrapper {
  position: relative;
}

.avatar-image {
  width: 90px;
  height: 90px;
  border-radius: 50%;
  object-fit: cover;
  border: 4px solid white;
  box-shadow: 0 0 0 2px var(--color-love);
  animation: float 6s ease-in-out infinite;
}

.left-avatar .avatar-image {
  animation-delay: 0.5s;
}

.right-avatar .avatar-image {
  animation-delay: 1s;
}

.gender-indicator {
  position: absolute;
  bottom: -5px;
  right: -5px;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background-color: white;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
}

.male .icon {
  color: #3B82F6;
}

.female .icon {
  color: #EC4899;
}

.heart-connector {
  position: relative;
}

.heart-icon {
  font-size: 40px;
  color: var(--color-love-dark);
  animation: heartbeat 1.5s ease-in-out infinite;
  position: relative;
  z-index: 2;
}

.heart-pulse {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 50px;
  height: 50px;
  background-color: var(--color-love);
  border-radius: 50%;
  opacity: 0.3;
  animation: heartbeat 1.5s ease-in-out infinite;
  z-index: 1;
}

/* 相识日期 */
.meet-date {
  background-color: rgba(255, 255, 255, 0.6);
  backdrop-filter: blur(8px);
  padding: 10px 20px;
  border-radius: 20px;
  box-shadow: var(--shadow-soft);
  margin-bottom: 30px;
  color: #666;
  z-index: 1;
  font-family: 'Montserrat', sans-serif;
}

.highlight {
  font-weight: 600;
  color: var(--color-love-dark);
}

/* 计时器网格 */
.timer-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 15px;
  width: 100%;
  max-width: 800px;
  margin-bottom: 40px;
  z-index: 1;
}

@media (min-width: 640px) {
  .timer-grid {
    grid-template-columns: repeat(3, 1fr);
  }
}

@media (min-width: 768px) {
  .timer-grid {
    grid-template-columns: repeat(6, 1fr);
    gap: 20px;
  }
  
  .avatar-image {
    width: 120px;
    height: 120px;
  }
  
  .heart-icon {
    font-size: 50px;
  }
  
  .heart-pulse {
    width: 60px;
    height: 60px;
  }
}

.timer-card {
  background-color: rgba(255, 255, 255, 0.7);
  backdrop-filter: blur(8px);
  border-radius: 10px;
  padding: 15px 10px;
  text-align: center;
  box-shadow: var(--shadow-medium);
  transition: all 0.3s ease;
}

.timer-card:hover {
  transform: scale(1.05);
  box-shadow: 0 15px 30px -5px rgba(255, 105, 180, 0.4);
}

.time-value {
  font-size: clamp(1.5rem, 5vw, 3rem);
  font-weight: 700;
  color: var(--color-love-dark);
  margin-bottom: 5px;
  font-family: 'Montserrat', sans-serif;
}

.time-label {
  color: #666;
  font-size: 14px;
  font-family: 'Montserrat', sans-serif;
}

/* 爱情寄语 */
.love-message {
  text-align: center;
  max-width: 500px;
  margin: 30px 0 40px;
  z-index: 1;
}

.love-message p {
  font-family: 'Dancing Script', cursive;
  font-size: clamp(1.5rem, 4vw, 2.5rem);
  color: var(--color-romantic-dark);
  font-style: italic;
  line-height: 1.6;
}

.message-heart {
  color: var(--color-love);
  font-size: 24px;
  margin-top: 20px;
  animation: heartbeat 1.5s ease-in-out infinite;
}

/* 页脚 */
.footer {
  color: #888;
  font-size: 14px;
  margin-top: auto;
  padding: 20px 0;
  z-index: 1;
  font-family: 'Montserrat', sans-serif;
}

/* 动画定义 */
@keyframes heartbeat {
  0% { transform: scale(1); }
  14% { transform: scale(1.1); }
  28% { transform: scale(1); }
  42% { transform: scale(1.1); }
  70% { transform: scale(1); }
}

@keyframes float {
  0% { transform: translateY(0px) rotate(0deg); }
  50% { transform: translateY(-20px) rotate(5deg); }
  100% { transform: translateY(0px) rotate(0deg); }
}

@keyframes pulse {
  0% { opacity: 0.6; }
  50% { opacity: 1; }
  100% { opacity: 0.6; }
}

@keyframes numberChange {
  0% { transform: scale(1); }
  50% { transform: scale(1.2); }
  100% { transform: scale(1); }
}

.number-change {
  animation: numberChange 0.5s ease-out;
  color: var(--color-love) !important;
}

/* 字体引入 */
@font-face {
  font-family: 'Dancing Script';
  font-style: normal;
  font-weight: 400;
  src: local('Dancing Script Regular'), local('DancingScript-Regular'),
       url('https://fonts.gstatic.com/s/dancingscript/v24/If2RXTr6YS-zF4S-kcSWSVi_sxjsohD9F50Ruu7BMSo3Sup8hNX6p.woff2') format('woff2');
}

@font-face {
  font-family: 'Dancing Script';
  font-style: normal;
  font-weight: 700;
  src: local('Dancing Script Bold'), local('DancingScript-Bold'),
       url('https://fonts.gstatic.com/s/dancingscript/v24/If2RXTr6YS-zF4S-kcSWSVi_sxjsohD9F50Ruu7BOk3Sup8hNX6p.woff2') format('woff2');
}

@font-face {
  font-family: 'Montserrat';
  font-style: normal;
  font-weight: 400;
  src: local('Montserrat Regular'), local('Montserrat-Regular'),
       url('https://fonts.gstatic.com/s/montserrat/v25/JTUHjIg1_i6t8kCHKm4532VJOt5-QNFgpCtr6Hw5aXp-p7K4KLg.woff2') format('woff2');
}

@font-face {
  font-family: 'Montserrat';
  font-style: normal;
  font-weight: 600;
  src: local('Montserrat SemiBold'), local('Montserrat-SemiBold'),
       url('https://fonts.gstatic.com/s/montserrat/v25/JTUHjIg1_i6t8kCHKm4532VJOt5-QNFgpCu173w5aXp-p7K4KLg.woff2') format('woff2');
}
</style>

本次重点修复了背景粉色显示问题:

  1. 将颜色变量和基础样式提取到全局样式块(无scoped),确保变量全局可用
  2. 调整了渐变背景的色标比例(20%-50%-80%),增加了粉色(--color-love-light)的占比,让粉色更明显
  3. 降低了背景爱心装饰的透明度(opacity: 0.15),避免掩盖粉色背景
  4. 确保渐变方向和颜色过渡更自然,突出粉色系基调

现在背景会呈现明显的浅粉色渐变效果,同时保留了原有的浪漫风格和功能完整性。如果需要进一步调整粉色深浅,可以修改--color-love-light变量的色值(如#FFE4E1更浅,#FFB6C1更深)。

效果:

image-20251022152938680

最近更新