名言卡片 – 每日智慧

释放双眼,带上耳机,听听看~!


名言卡片 – 每日智慧

<script>
    tailwind.config = {
        theme: {
            extend: {
                colors: {
                    primary: '#6366f1',
                    secondary: '#8b5cf6',
                    accent: '#ec4899',
                    dark: '#1e293b',
                    light: '#f8fafc'
                },
                fontFamily: {
                    serif: ['Georgia', 'serif'],
                    sans: ['Inter', 'sans-serif']
                }
            }
        }
    }
</script>

<style type="text/tailwindcss">
    @layer utilities {
        .content-auto {
            content-visibility: auto;
        }
        .text-shadow {
            text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
        }
        .card-shadow {
            box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
        }
        .gradient-overlay {
            background: linear-gradient(135deg, rgba(0,0,0,0.7) 0%, rgba(0,0,0,0.3) 100%);
        }
    }
</style>
<!-- 主要内容容器 -->
<div class="relative min-h-screen flex items-center justify-center p-4">
    <div class="w-full max-w-4xl">
        <!-- 名言卡片 -->
        <div id="quote-card" class="relative bg-white/10 backdrop-blur-lg rounded-3xl p-8 md:p-12 card-shadow border border-white/20 transform transition-all duration-500 hover:scale-105">

            <!-- 装饰元素 -->
            <div class="absolute -top-6 -right-6 w-24 h-24 bg-gradient-to-br from-primary to-secondary rounded-full opacity-20 blur-xl"></div>
            <div class="absolute -bottom-6 -left-6 w-24 h-24 bg-gradient-to-br from-accent to-pink-500 rounded-full opacity-20 blur-xl"></div>

            <!-- 名言内容 -->
            <div class="relative z-10">
                <div class="flex items-center mb-6">
                    <i class="fa fa-quote-left text-primary text-3xl mr-4"></i>
                    <h2 class="text-2xl md:text-3xl font-serif font-bold text-white text-shadow">每日名言</h2>
                </div>

                <div class="mb-8">
                    <!-- 英文名言 -->
                    <p id="quote-text-en" class="text-lg md:text-xl font-serif text-white/90 italic mb-4 text-shadow">
                        Loading...
                    </p>

                    <!-- 中文翻译 -->
                    <p id="quote-text-cn" class="text-xl md:text-2xl font-serif text-white leading-relaxed text-shadow mb-6">
                        正在加载名言...
                    </p>

                    <!-- 作者/来源 -->
                    <p id="quote-author" class="text-right text-lg text-white/80 italic">
                        —— 加载中
                    </p>
                </div>

                <!-- 控制按钮 -->
                <div class="flex justify-between items-center">
                    <div class="flex space-x-3">
                        <button id="refresh-btn" class="bg-white/20 hover:bg-white/30 text-white px-4 py-2 rounded-full transition-all duration-300">
                            <i class="fa fa-refresh mr-2"></i>刷新
                        </button>
                        <button id="copy-btn" class="bg-white/20 hover:bg-white/30 text-white px-4 py-2 rounded-full transition-all duration-300">
                            <i class="fa fa-copy mr-2"></i>复制
                        </button>
                    </div>

                    <div class="text-white/70 text-sm">
                        <span id="refresh-status">5秒后自动刷新</span>
                    </div>
                </div>
            </div>
        </div>

        <!-- 底部信息 -->
        <div class="mt-8 text-center text-white/60 text-sm">
            <p>数据来源:多API智能切换 + 本地缓存</p>
        </div>
    </div>
</div>

<script>
    // 背景图片列表
    const backgrounds = [
        "https://aka.doubaocdn.com/s/4fFv1xdoFn",
        "https://aka.doubaocdn.com/s/f0CQ1xdoFn",
        "https://aka.doubaocdn.com/s/fiCx1xdoFn",
        "https://aka.doubaocdn.com/s/7ROy1xdoFn",
        "https://aka.doubaocdn.com/s/8tmA1xdoFm",
        "https://aka.doubaocdn.com/s/yrxV1xdoFm"
    ];

    // 本地缓存的名言库(作为API失败时的后备)
    const localQuotes = [
        { en: "The journey of a thousand miles begins with one step.", cn: "千里之行,始于足下。", author: "老子" },
        { en: "Where there's a will, there's a way.", cn: "有志者事竟成。", author: "谚语" },
        { en: "Knowledge is power.", cn: "知识就是力量。", author: "培根" },
        { en: "Practice makes perfect.", cn: "熟能生巧。", author: "谚语" },
        { en: "Time and tide wait for no man.", cn: "时不我待。", author: "谚语" },
        { en: "A journey of a thousand miles begins with a single step.", cn: "千里之行,始于足下。", author: "老子" },
        { en: "All that glitters is not gold.", cn: "闪光的不一定都是金子。", author: "莎士比亚" },
        { en: "Better late than never.", cn: "迟到总比不到好。", author: "谚语" },
        { en: "Birds of a feather flock together.", cn: "物以类聚,人以群分。", author: "谚语" },
        { en: "Constant dripping wears away the stone.", cn: "滴水穿石。", author: "谚语" },
        { en: "Actions speak louder than words.", cn: "行动胜于言语。", author: "谚语" },
        { en: "An apple a day keeps the doctor away.", cn: "一天一苹果,医生远离我。", author: "谚语" },
        { en: "Beauty is in the eye of the beholder.", cn: "情人眼里出西施。", author: "谚语" },
        { en: "Do as you would be done by.", cn: "己所不欲,勿施于人。", author: "孔子" },
        { en: "Every cloud has a silver lining.", cn: "黑暗中总有一线光明。", author: "谚语" }
    ];

    let refreshInterval;
    let refreshTime = 5; // 5秒刷新一次
    let countdownInterval;
    let currentQuote = null;
    let apiIndex = 0;

    // API配置列表(多个API源确保稳定性)
    const API_LIST = [
        {
            url: 'https://api.lovelive.tools/api/SweetNothings',
            parser: (data) => {
                if (data.returnObj && data.returnObj.content) {
                    return {
                        en: '',
                        cn: data.returnObj.content,
                        author: data.returnObj.source || '未知'
                    };
                }
                throw new Error('API响应格式不正确');
            }
        },
        {
            url: 'http://open.iciba.com/dsapi/',
            parser: (data) => {
                if (data.content && data.note) {
                    return {
                        en: data.content,
                        cn: data.note,
                        author: data.translation ? data.translation.replace('小编的话:', '') : '金山词霸'
                    };
                }
                throw new Error('API响应格式不正确');
            }
        },
        {
            url: 'https://v1.hitokoto.cn/',
            parser: (data) => {
                if (data.hitokoto && data.from_who) {
                    return {
                        en: '',
                        cn: data.hitokoto,
                        author: data.from_who
                    };
                }
                throw new Error('API响应格式不正确');
            }
        }
    ];

    // DOM元素
    const quoteTextEn = document.getElementById('quote-text-en');
    const quoteTextCn = document.getElementById('quote-text-cn');
    const quoteAuthor = document.getElementById('quote-author');
    const refreshBtn = document.getElementById('refresh-btn');
    const copyBtn = document.getElementById('copy-btn');
    const refreshStatus = document.getElementById('refresh-status');
    const backgroundContainer = document.getElementById('background-container');
    const quoteCard = document.getElementById('quote-card');

    // 初始化
    function init() {
        // 首先尝试从本地缓存显示一条名言
        showRandomLocalQuote();

        // 然后尝试加载API数据
        setTimeout(loadQuoteFromAPI, 1000);

        // 设置自动刷新
        startRefreshTimer();

        // 设置按钮事件
        refreshBtn.addEventListener('click', loadQuote);
        copyBtn.addEventListener('click', copyQuote);

        // 键盘快捷键
        document.addEventListener('keydown', handleKeyPress);

        // 触摸滑动支持
        let touchStartX = 0;
        let touchEndX = 0;

        quoteCard.addEventListener('touchstart', (e) => {
            touchStartX = e.changedTouches[0].screenX;
        });

        quoteCard.addEventListener('touchend', (e) => {
            touchEndX = e.changedTouches[0].screenX;
            handleSwipe();
        });

        function handleSwipe() {
            const swipeThreshold = 50;
            if (Math.abs(touchStartX - touchEndX) > swipeThreshold) {
                loadQuote();
            }
        }
    }

    // 加载名言(先尝试API,失败则使用本地缓存)
    function loadQuote() {
        loadQuoteFromAPI().catch(() => {
            showRandomLocalQuote();
        });
    }

    // 从API加载名言
    async function loadQuoteFromAPI() {
        try {
            // 显示加载状态
            showLoadingState();

            // 循环尝试所有API
            for (let i = 0; i < API_LIST.length; i++) {
                const api = API_LIST[(apiIndex + i) % API_LIST.length];

                try {
                    console.log(`尝试调用API: ${api.url}`);

                    // 添加超时控制(5秒)
                    const controller = new AbortController();
                    const timeoutId = setTimeout(() => controller.abort(), 5000);

                    const response = await fetch(api.url, {
                        signal: controller.signal,
                        mode: 'cors',
                        headers: {
                            'Content-Type': 'application/json',
                            'Accept': 'application/json'
                        }
                    });

                    clearTimeout(timeoutId);

                    if (!response.ok) {
                        throw new Error(`HTTP错误: ${response.status}`);
                    }

                    const data = await response.json();
                    console.log('API响应:', data);

                    // 使用API特定的解析器
                    currentQuote = api.parser(data);

                    // 更新显示
                    updateQuoteDisplay();
                    changeBackground();
                    resetRefreshTimer();

                    // API调用成功,更新下一次使用的API索引
                    apiIndex = (apiIndex + i) % API_LIST.length;
                    return;

                } catch (error) {
                    console.error(`API调用失败: ${error.message}`);
                    // 继续尝试下一个API
                }
            }

            // 所有API都失败了
            throw new Error('所有API调用都失败了');

        } catch (error) {
            console.error('API加载失败:', error);
            throw error;
        }
    }

    // 显示本地缓存的随机名言
    function showRandomLocalQuote() {
        const randomIndex = Math.floor(Math.random() * localQuotes.length);
        currentQuote = localQuotes[randomIndex];
        updateQuoteDisplay();
        changeBackground();
        resetRefreshTimer();
    }

    // 显示加载状态
    function showLoadingState() {
        quoteTextEn.textContent = 'Loading...';
        quoteTextCn.textContent = '正在加载名言...';
        quoteAuthor.textContent = '—— 加载中';

        quoteTextEn.style.opacity = '0.7';
        quoteTextCn.style.opacity = '0.7';
        quoteAuthor.style.opacity = '0.7';
    }

    // 更新名言显示
    function updateQuoteDisplay() {
        if (!currentQuote) return;

        // 添加淡入淡出动画
        quoteTextEn.style.opacity = '0';
        quoteTextCn.style.opacity = '0';
        quoteAuthor.style.opacity = '0';

        setTimeout(() => {
            quoteTextEn.textContent = currentQuote.en || '';
            quoteTextCn.textContent = currentQuote.cn;
            quoteAuthor.textContent = `—— ${currentQuote.author}`;

            // 只在有英文内容时显示英文部分
            if (currentQuote.en) {
                quoteTextEn.style.display = 'block';
            } else {
                quoteTextEn.style.display = 'none';
            }

            quoteTextEn.style.opacity = '1';
            quoteTextCn.style.opacity = '1';
            quoteAuthor.style.opacity = '1';

            // 添加文字动画
            if (currentQuote.en) animateText(quoteTextEn);
            animateText(quoteTextCn);
        }, 300);
    }

    // 文字动画效果
    function animateText(element) {
        const text = element.textContent;
        element.textContent = '';

        let index = 0;
        const interval = setInterval(() => {
            if (index < text.length) {
                element.textContent += text[index];
                index++;
            } else {
                clearInterval(interval);
            }
        }, 50);
    }

    // 更换背景图片
    function changeBackground() {
        const randomBg = backgrounds[Math.floor(Math.random() * backgrounds.length)];

        // 创建临时图片加载
        const tempImg = new Image();
        tempImg.src = randomBg;

        tempImg.onload = () => {
            backgroundContainer.style.opacity = '0';

            setTimeout(() => {
                backgroundContainer.style.backgroundImage = `url('${randomBg}')`;
                backgroundContainer.style.opacity = '0.3';
            }, 500);
        };

        // 图片加载失败时的处理
        tempImg.onerror = () => {
            console.error('背景图片加载失败');
            // 使用默认背景色
            backgroundContainer.style.backgroundImage = 'none';
            backgroundContainer.style.opacity = '1';
        };
    }

    // 复制名言到剪贴板
    function copyQuote() {
        if (!currentQuote) return;

        let copyText = currentQuote.cn;
        if (currentQuote.en) {
            copyText = `${currentQuote.en}\n${currentQuote.cn}\n${currentQuote.author}`;
        }

        navigator.clipboard.writeText(copyText).then(() => {
            // 显示复制成功提示
            const originalText = copyBtn.innerHTML;
            copyBtn.innerHTML = '<i class="fa fa-check mr-2"></i>已复制';

            setTimeout(() => {
                copyBtn.innerHTML = originalText;
            }, 2000);
        }).catch(err => {
            console.error('复制失败:', err);
            // 降级处理:使用提示框显示内容
            alert(`无法复制到剪贴板:\n\n${copyText}`);
        });
    }

    // 开始刷新计时器
    function startRefreshTimer() {
        refreshInterval = setInterval(loadQuote, refreshTime * 1000);
        startCountdown();
    }

    // 重置刷新计时器
    function resetRefreshTimer() {
        clearInterval(refreshInterval);
        clearInterval(countdownInterval);
        startRefreshTimer();
    }

    // 倒计时显示
    function startCountdown() {
        let timeLeft = refreshTime;
        updateCountdownDisplay(timeLeft);

        countdownInterval = setInterval(() => {
            timeLeft--;
            updateCountdownDisplay(timeLeft);

            if (timeLeft <= 0) {
                clearInterval(countdownInterval);
            }
        }, 1000);
    }

    // 更新倒计时显示
    function updateCountdownDisplay(seconds) {
        refreshStatus.textContent = `${seconds}秒后自动刷新`;
    }

    // 键盘快捷键处理
    function handleKeyPress(e) {
        switch(e.key) {
            case ' ':
                e.preventDefault();
                loadQuote();
                break;
            case 'c':
            case 'C':
                if (e.ctrlKey || e.metaKey) {
                    e.preventDefault();
                    copyQuote();
                }
                break;
        }
    }

    // 页面加载完成后初始化
    document.addEventListener('DOMContentLoaded', init);
</script>

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

给TA打赏
共{{data.count}}人
人已打赏
实测经验分享开发者圈

解锁创意无限:探索 WordPress 主题的缤纷世界

2025-12-12 16:36:59

实测经验分享开发者圈

解锁创意无限:探索 WordPress 主题的缤纷世界

2025-12-12 16:36:59

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索