先看效果:
再看代码(查看更多):
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>计时器</title><style>* {padding: 0;margin: 0;box-sizing: border-box;}body {background: #98ede0;transition: background 500ms;font-family: ui-rounded, "Hiragino Maru Gothic ProN", Quicksand, Comfortaa, Manjari, "Arial Rounded MT", "Arial Rounded MT Bold", Calibri, source-sans-pro, sans-serif;}.content {margin: 0 auto;max-width: 500px;height: 100vh;height: 100svh;min-height: 400px;display: flex;flex-direction: column;padding: 40px 40px 80px;justify-content: center;}a {transition: color 200ms;color: rgba(0, 0, 0, 0.5);border-radius: 5px;text-decoration: none;margin: 40px auto 0;}a:hover {color: black;text-decoration: underline;}a:focus-visible {color: black;outline: 3px solid rgba(255, 255, 255, 0.3);outline-offset: 5px;}.pagination {display: flex;gap: 10px;height: 4px;min-height: 4px;}.pagination-item {border-radius: 100px;height: 100%;flex: auto;background: rgba(0, 0, 0, 0.08);overflow: hidden;border: 0;cursor: pointer;}@keyframes progress {from {width: 0;}to {width: 100%;}}.pagination-progress {flex: auto;background: #333;height: 100%;width: 0;}.pagination-item--running .pagination-progress {animation: progress 3s linear forwards;}.pagination-item--done .pagination-progress {width: 100%;}.pagination--paused .pagination-progress {animation-play-state: paused;}:-moz-window-inactive .pagination-progress {animation-play-state: paused;}.controls {display: flex;justify-content: center;gap: 12px;}.control {display: flex;align-items: center;justify-content: center;border-radius: 100px;border: none;outline: none;height: 40px;flex: 40px 0 0;max-width: 100px;background: rgba(255, 255, 255, 0.3);transition: transform 200ms, background-color 200ms;will-change: transform, background-color;font-size: 20px;}.control:hover {cursor: pointer;transform: scale(1.15);background: rgba(255, 255, 255, 0.45);}.control:focus {background: rgba(255, 255, 255, 0.6);}.icon {width: 20px;}.icon--play {margin-right: -2px;}.pagination--paused ~ .controls .icon--pause,.pagination:not(.pagination--paused) ~ .controls .icon--play {display: none;}.state {font-size: 120px;text-align: center;}</style>
</head>
<body>
<div class="content"><div class="pagination"></div><div class="state"> </div><div class="controls"><button class="control control--prev" aria-label="Previous"><svg class="icon" viewBox="0 0 32 32"><path d="M20 28a1 1 0 0 1-.521-.146l-18-11a1.002 1.002 0 0 1 0-1.708l18-11A.999.999 0 0 1 21 5v6.11a1 1 0 0 1-.479.854L13.918 16l6.603 4.035c.297.182.479.506.479.854V27a1 1 0 0 1-1 1zM3.918 16 19 25.217V21.45l-7.521-4.596a1 1 0 0 1 0-1.707L19 10.55V6.783L3.918 16z" /><path d="M30 28a1 1 0 0 1-.521-.146l-18-11a1.002 1.002 0 0 1 0-1.708l18-11A.999.999 0 0 1 31 5v22a1 1 0 0 1-1 1zM13.918 16 29 25.217V6.783L13.918 16z" /></svg></button><button class="control control--play-pause" aria-label="Play/Pause"><svg class="icon icon--play" viewBox="0 0 32 32"><path d="M7 28a.999.999 0 0 1-1-1V5a1 1 0 0 1 1.521-.854l18 11a1.001 1.001 0 0 1 0 1.708l-18 11A1 1 0 0 1 7 28zM8 6.783v18.434L23.082 16 8 6.783z" /></svg><svg class="icon icon--pause" viewBox="0 0 32 32"><path d="M13 28H7a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1v22a1 1 0 0 1-1 1zm-5-2h4V6H8v20zM25 28h-6a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1v22a1 1 0 0 1-1 1zm-5-2h4V6h-4v20z" /></svg></button><button class="control control--next" aria-label="Next"><svg class="icon" viewBox="0 0 32 32"><path d="M12 28a1 1 0 0 1-1-1v-6.111c0-.348.182-.672.479-.854L18.082 16l-6.603-4.035A1.001 1.001 0 0 1 11 11.11V5a1 1 0 0 1 1.521-.854l18 11a1.002 1.002 0 0 1 0 1.708l-18 11A1 1 0 0 1 12 28zm1-6.55v3.767L28.082 16 13 6.783v3.767l7.521 4.596a1.001 1.001 0 0 1 0 1.708L13 21.45z" /><path d="M2 28a1 1 0 0 1-1-1V5a1 1 0 0 1 1.521-.854l18 11a1.002 1.002 0 0 1 0 1.708l-18 11A1 1 0 0 1 2 28zM3 6.783v18.434L18.082 16 3 6.783z" /></svg></button></div><a target="_blank" href="https://blog.csdn.net/qq_35241329?type=blog">博客文章</a>
</div>
</body>
<script>"use strict";function getItem(index) {const item = document.createElement('button');item.classList.add('pagination-item');item.addEventListener('animationend', next);item.addEventListener('click', () => update(index));const progress = document.createElement('div');progress.classList.add('pagination-progress');item.appendChild(progress);return item;}function createItems(itemsCount) {const items = [];for (let i = 0; i < itemsCount; i++) {items.push(getItem(i));}return items;}function jumpTo(item) {if (isPaused) {item.classList.remove(classNames.RUNNING);item.classList.add(classNames.DONE);}else {item.classList.add(classNames.RUNNING);item.classList.remove(classNames.DONE);}let sibling = item;while ((sibling = sibling.previousSibling)) {sibling.classList.remove(classNames.RUNNING);sibling.classList.add(classNames.DONE);}sibling = item;while ((sibling = sibling.nextSibling)) {sibling.classList.remove(classNames.RUNNING, classNames.DONE);}}function update(index) {activeIndex = index;jumpTo(items[activeIndex]);// 更新幻灯片和背景颜色$state.innerHTML = activeIndex + 1;document.body.style.backgroundColor = colors[activeIndex];}function prev() {if (activeIndex > 0) {update(activeIndex - 1);}}function next() {if (activeIndex < ITEMS_COUNT - 1) {update(activeIndex + 1);}}function playPause() {$pagination.classList.toggle(classNames.PAUSED);isPaused = !isPaused;///如果当前幻灯片已完成,跳到下一张if (!isPaused && items[activeIndex].classList.contains(classNames.DONE)) {next();}}const colors = ['#98ede0', '#74b9ff', '#a29bfe', '#fd79a8', '#ffeaa7'];const classNames = {RUNNING: 'pagination-item--running',DONE: 'pagination-item--done',PAUSED: 'pagination--paused',};let activeIndex = 0;let isPaused = false;const ITEMS_COUNT = 5;const items = createItems(ITEMS_COUNT);const $pagination = document.querySelector('.pagination');const $state = document.querySelector('.state');const $prev = document.querySelector('.control--prev');const $next = document.querySelector('.control--next');const $playPause = document.querySelector('.control--play-pause');$pagination.replaceChildren(...items);$prev.addEventListener('click', prev);$next.addEventListener('click', next);$playPause.addEventListener('click', playPause);update(activeIndex);</script>
</html>