SVG数据可视化组件基础教程6:翻牌倒计时

我是设计师邱兴,一个学习前端的设计师,今天给大家制作一个用SVG实现的带有翻牌效果的SVG倒计时器,SVG相较于Echart来说制作简单,但是效果可以非常丰富。

一、目标

通过HTML、CSS和JavaScript创建一个带有翻牌效果的SVG倒计时器,实现以下功能:

  1. 显示时、分、秒的数字卡片。
  2. 使用翻牌效果更新数字。
  3. 通过输入框设置倒计时时间。
  4. 开始、停止倒计时控制。

二、所需工具与准备

  1. 工具:

    • 一个文本编辑器(如Notepad++、VS Code等)。
    • 浏览器(用于预览效果)。
  2. 基础准备:

    • 确保你对HTML、CSS和JavaScript有一定的了解。
    • 确保你对SVG的基本语法有一定了解。

三、代码分析与操作步骤

1. 创建HTML结构

创建一个HTML文件(如Lesson6.html)并设置基本的HTML结构:

xml 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>SVG 翻牌倒计时</title>
  <style>
    /* 样式部分 */
  </style>
</head>
<body>
  <div class="clock-container">
    <div class="digit-group">
      <div class="digit" id="hours-tens"></div>
      <div class="digit" id="hours-ones"></div>
    </div>
    <div class="separator">:</div>
    <div class="digit-group">
      <div class="digit" id="minutes-tens"></div>
      <div class="digit" id="minutes-ones"></div>
    </div>
    <div class="separator">:</div>
    <div class="digit-group">
      <div class="digit" id="seconds-tens"></div>
      <div class="digit" id="seconds-ones"></div>
    </div>
  </div>
  <div class="controls">
    <input type="number" id="timeInput" min="0" max="999999" value="60" placeholder="输入秒数">
    <button onclick="startTimer()">开始倒计时</button>
    <button onclick="stopTimer()">停止</button>
  </div>

  <script>
    // JavaScript部分
  </script>
</body>
</html>

2. 添加CSS样式

在<style>标签中,添加以下CSS样式:

css 复制代码
body {
  background: #1a1a1a;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: 100vh;
  margin: 0;
  font-family: Arial, sans-serif;
}
.clock-container {
  display: flex;
  gap: 20px;
  padding: 20px;
  background: #2a2a2a;
  border-radius: 10px;
  box-shadow: 0 0 20px rgba(0,0,0,0.3);
}
.digit-group {
  display: flex;
  gap: 5px;
}
.digit {
  position: relative;
  width: 60px;
  height: 80px;
}
.separator {
  display: flex;
  align-items: center;
  font-size: 40px;
  color: #fff;
  font-weight: bold;
}
.controls {
  margin-top: 30px;
  display: flex;
  gap: 10px;
}
button {
  padding: 10px 20px;
  font-size: 16px;
  border: none;
  border-radius: 5px;
  background: #4CAF50;
  color: white;
  cursor: pointer;
  transition: background 0.3s;
}
button:hover {
  background: #45a049;
}
input {
  padding: 10px;
  font-size: 16px;
  border: none;
  border-radius: 5px;
  width: 100px;
}
  • 设置页面背景颜色为深色。
  • 使用flexbox布局将倒计时器和控制按钮居中显示。
  • 设置数字卡片和分隔符的样式。
  • 设置输入框和按钮的样式。

3. 编写JavaScript代码

在<script>标签中,添加以下JavaScript代码来实现翻牌倒计时功能:

ini 复制代码
// 创建数字卡片SVG
function createDigitSVG(container, digit) {
  const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
  svg.setAttribute("width", "100%");
  svg.setAttribute("height", "100%");
  svg.setAttribute("viewBox", "0 0 60 80");

  // 卡片背景
  const card = document.createElementNS("http://www.w3.org/2000/svg", "rect");
  card.setAttribute("x", "2");
  card.setAttribute("y", "2");
  card.setAttribute("width", "56");
  card.setAttribute("height", "76");
  card.setAttribute("rx", "5");
  card.setAttribute("fill", "#333");
  card.setAttribute("stroke", "#444");
  card.setAttribute("stroke-width", "2");

  // 数字
  const text = document.createElementNS("http://www.w3.org/2000/svg", "text");
  text.setAttribute("x", "30");
  text.setAttribute("y", "50");
  text.setAttribute("text-anchor", "middle");
  text.setAttribute("font-size", "40");
  text.setAttribute("fill", "#fff");
  text.setAttribute("font-weight", "bold");
  text.textContent = digit;

  svg.appendChild(card);
  svg.appendChild(text);
  container.appendChild(svg);
}

// 初始化所有数字卡片
function initializeDigits() {
  const positions = ['hours-tens', 'hours-ones', 'minutes-tens', 'minutes-ones', 'seconds-tens', 'seconds-ones'];
  positions.forEach(pos => {
    createDigitSVG(document.getElementById(pos), '0');
  });
}

// 更新数字显示
function updateDisplay(time) {
  const hours = Math.floor(time / 3600);
  const minutes = Math.floor((time % 3600) / 60);
  const seconds = time % 60;

  const digits = [
    Math.floor(hours / 10),
    hours % 10,
    Math.floor(minutes / 10),
    minutes % 10,
    Math.floor(seconds / 10),
    seconds % 10
  ];

  const positions = ['hours-tens', 'hours-ones', 'minutes-tens', 'minutes-ones', 'seconds-tens', 'seconds-ones'];
  positions.forEach((pos, index) => {
    const container = document.getElementById(pos);
    container.innerHTML = '';
    createDigitSVG(container, digits[index]);
  });
}

let timerInterval;
let remainingTime = 0;

function startTimer() {
  const inputTime = parseInt(document.getElementById('timeInput').value);
  if (isNaN(inputTime) || inputTime < 0) {
    alert('请输入有效的秒数!');
    return;
  }

  remainingTime = inputTime;
  updateDisplay(remainingTime);

  if (timerInterval) {
    clearInterval(timerInterval);
  }

  timerInterval = setInterval(() => {
    remainingTime--;
    if (remainingTime < 0) {
      clearInterval(timerInterval);
      alert('倒计时结束!');
      return;
    }
    updateDisplay(remainingTime);
  }, 1000);
}

function stopTimer() {
  if (timerInterval) {
    clearInterval(timerInterval);
  }
}

// 初始化显示
initializeDigits();

4. 完整代码

将上述代码整合到一个HTML文件中,完整的代码如下:

xml 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>SVG 翻牌倒计时</title>
  <style>
    body {
      background: #1a1a1a;
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      min-height: 100vh;
      margin: 0;
      font-family: Arial, sans-serif;
    }
    .clock-container {
      display: flex;
      gap: 20px;
      padding: 20px;
      background: #2a2a2a;
      border-radius: 10px;
      box-shadow: 0 0 20px rgba(0,0,0,0.3);
    }
    .digit-group {
      display: flex;
      gap: 5px;
    }
    .digit {
      position: relative;
      width: 60px;
      height: 80px;
    }
    .separator {
      display: flex;
      align-items: center;
      font-size: 40px;
      color: #fff;
      font-weight: bold;
    }
    .controls {
      margin-top: 30px;
      display: flex;
      gap: 10px;
    }
    button {
      padding: 10px 20px;
      font-size: 16px;
      border: none;
      border-radius: 5px;
      background: #4CAF50;
      color: white;
      cursor: pointer;
      transition: background 0.3s;
    }
    button:hover {
      background: #45a049;
    }
    input {
      padding: 10px;
      font-size: 16px;
      border: none;
      border-radius: 5px;
      width: 100px;
    }
  </style>
</head>
<body>
  <div class="clock-container">
    <div class="digit-group">
      <div class="digit" id="hours-tens"></div>
      <div class="digit" id="hours-ones"></div>
    </div>
    <div class="separator">:</div>
    <div class="digit-group">
      <div class="digit" id="minutes-tens"></div>
      <div class="digit" id="minutes-ones"></div>
    </div>
    <div class="separator">:</div>
    <div class="digit-group">
      <div class="digit" id="seconds-tens"></div>
      <div class="digit" id="seconds-ones"></div>
    </div>
  </div>
  <div class="controls">
    <input type="number" id="timeInput" min="0" max="999999" value="60" placeholder="输入秒数">
    <button onclick="startTimer()">开始倒计时</button>
    <button onclick="stopTimer()">停止</button>
  </div>

  <script>
    // 创建数字卡片SVG
    function createDigitSVG(container, digit) {
      const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
      svg.setAttribute("width", "100%");
      svg.setAttribute("height", "100%");
      svg.setAttribute("viewBox", "0 0 60 80");

      // 卡片背景
      const card = document.createElementNS("http://www.w3.org/2000/svg", "rect");
      card.setAttribute("x", "2");
      card.setAttribute("y", "2");
      card.setAttribute("width", "56");
      card.setAttribute("height", "76");
      card.setAttribute("rx", "5");
      card.setAttribute("fill", "#333");
      card.setAttribute("stroke", "#444");
      card.setAttribute("stroke-width", "2");

      // 数字
      const text = document.createElementNS("http://www.w3.org/2000/svg", "text");
      text.setAttribute("x", "30");
      text.setAttribute("y", "50");
      text.setAttribute("text-anchor", "middle");
      text.setAttribute("font-size", "40");
      text.setAttribute("fill", "#fff");
      text.setAttribute("font-weight", "bold");
      text.textContent = digit;

      svg.appendChild(card);
      svg.appendChild(text);
      container.appendChild(svg);
    }

    // 初始化所有数字卡片
    function initializeDigits() {
      const positions = ['hours-tens', 'hours-ones', 'minutes-tens', 'minutes-ones', 'seconds-tens', 'seconds-ones'];
      positions.forEach(pos => {
        createDigitSVG(document.getElementById(pos), '0');
      });
    }

    // 更新数字显示
    function updateDisplay(time) {
      const hours = Math.floor(time / 3600);
      const minutes = Math.floor((time % 3600) / 60);
      const seconds = time % 60;

      const digits = [
        Math.floor(hours / 10),
        hours % 10,
        Math.floor(minutes / 10),
        minutes % 10,
        Math.floor(seconds / 10),
        seconds % 10
      ];

      const positions = ['hours-tens', 'hours-ones', 'minutes-tens', 'minutes-ones', 'seconds-tens', 'seconds-ones'];
      positions.forEach((pos, index) => {
        const container = document.getElementById(pos);
        container.innerHTML = '';
        createDigitSVG(container, digits[index]);
      });
    }

    let timerInterval;
    let remainingTime = 0;

    function startTimer() {
      const inputTime = parseInt(document.getElementById('timeInput').value);
      if (isNaN(inputTime) || inputTime < 0) {
        alert('请输入有效的秒数!');
        return;
      }

      remainingTime = inputTime;
      updateDisplay(remainingTime);

      if (timerInterval) {
        clearInterval(timerInterval);
      }

      timerInterval = setInterval(() => {
        remainingTime--;
        if (remainingTime < 0) {
          clearInterval(timerInterval);
          alert('倒计时结束!');
          return;
        }
        updateDisplay(remainingTime);
      }, 1000);
    }

    function stopTimer() {
      if (timerInterval) {
        clearInterval(timerInterval);
      }
    }

    // 初始化显示
    initializeDigits();
  </script>
</body>
</html>

四、总结

通过以上步骤,你可以创建一个带有翻牌效果的SVG倒计时器。这个倒计时器具有时、分、秒的数字卡片显示,支持通过输入框设置倒计时时间,并提供开始和停止控制功能。你可以通过调整代码中的参数来改变倒计时器的外观和行为。希望这个教程对你有所帮助!

以上制作的是一个最简单的一个带刻度的仪表盘,我还录制了一个更加美观的带刻度的仪表盘的视频教程,有兴趣的小伙伴可以点击查看。

相关推荐
有味道的男人7 分钟前
搜好货平台关键词商品搜索接口:分页容错与商品数据轻量化提取方案
服务器·前端·javascript
lovingsoft1 小时前
Chrome Lighthouse 详解
前端·chrome
Qlly1 小时前
全栈工程师怎么接需求?从一句「加个功能」聊到能开发、能验收
前端·后端
马可家的菠萝1 小时前
你的微信“文件传输助手”,是不是已经成了第二个网盘?
前端·后端·架构
略略略啦1 小时前
Vibe Coding 基于Spec DD和TDD的实践指南
前端
shmily麻瓜小菜鸡1 小时前
前端实现图片与PDF文字识别敏感信息打码方案
前端·pdf·状态模式
打工仔折腾 AI1 小时前
LangChain 工具调用实战:从 Tool 定义到 Agent 执行链路拆解
java·前端·人工智能·后端·python·langchain·ai agent 实战
汉堡大王95272 小时前
单次输出拉到100万Token:拆完 Gemini 4 Argon 的续写协议,才看懂谷歌这7个月在憋什么
前端·人工智能·后端
看浪的路人2 小时前
第9讲:大模型应用监控与可观测性——OpenTelemetry + Prometheus + Grafana 全链路追踪
java·前端·spring
内存过载2 小时前
用表格模拟甘特图:项目排期的土办法
前端·低代码