打开/关闭菜单
打开/关闭外观设置菜单
打开/关闭个人菜单
未登录
未登录用户的IP地址会在进行任意编辑后公开展示。
imported>弃权者
撤销弃权者讨论)的修订版本2092
无编辑摘要
 
(未显示2个用户的3个中间版本)
第1行: 第1行:
<noinclude>仅供{{tl|Countdown}}使用。</noinclude><includeonly><!--{if !isset($wgCountdown) || !$wgCountdown}--><!--{assign var="wgCountdown" value=true scope="global"}--><script>
<noinclude>仅供{{tl|Countdown}}使用。</noinclude><includeonly><script>
"use strict";
"use strict";
(function() {
(function() {
     // 如果 moment 已经存在直接初始化
     // 等候网页基础内容加载完毕再动手防止找不到元素
     if (typeof moment !== 'undefined') {
     if (document.readyState === 'loading') {
        initCountdown();
         document.addEventListener('DOMContentLoaded', setupCountdown);
        return;
    }
   
    // 检查是否支持 mw.loader
    if (typeof mw !== 'undefined' && mw.loader && typeof mw.loader.using === 'function') {
         mw.loader.using('moment').then(initCountdown).catch(loadFromCDN);
     } else {
     } else {
         // mw.loader 不可用,直接从 CDN 加载
         setupCountdown();
        loadFromCDN();
    }
   
    function loadFromCDN() {
        // 国内 CDN 备选列表
        var cdnList = [
            'https://cdn.bootcdn.net/ajax/libs/moment.js/2.29.4/moment.min.js',
            'https://cdn.staticfile.org/moment.js/2.29.4/moment.min.js',
            'https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js'
        ];
       
        tryLoadCDN(0);
       
        function tryLoadCDN(index) {
            if (index >= cdnList.length) {
                // 所有 CDN 都失败
                document.querySelectorAll('.countdownNode').forEach(el => {
                    el.textContent = '(无法加载时间库)';
                    el.classList.add('error');
                });
                return;
            }
           
            var script = document.createElement('script');
            script.src = cdnList[index];
            script.onload = initCountdown;
            script.onerror = function() {
                tryLoadCDN(index + 1); // 尝试下一个 CDN
            };
            document.head.appendChild(script);
        }
     }
     }
   
 
    function initCountdown() {
        // 确保 DOM 加载完成
        if (document.readyState === 'loading') {
            document.addEventListener('DOMContentLoaded', setupCountdown);
        } else {
            setupCountdown();
        }
    }
   
     function setupCountdown() {
     function setupCountdown() {
        // 核心计算逻辑:完全使用原生 Date 对象替代 moment.js
         const fromNow = (then, before, after, on) => {
         const fromNow = (then, before, after, on) => {
             const now = moment();
             const now = new Date();
             const isBefore = then.isBefore(now);
             const isBefore = then.getTime() < now.getTime();
             const monthsHave31Days = [0, 2, 4, 6, 7, 9, 11];
 
             let year = isBefore ? now.year() - then.year() : then.year() - now.year(),
            // 为了方便做减法,把大的时间放前面
                 month = isBefore ? now.month() - then.month() : then.month() - now.month(),
             const t1 = isBefore ? now : then;
                 day = isBefore ? now.date() - then.date() : then.date() - now.date(),
             const t2 = isBefore ? then : now;
                 hour = isBefore ? now.hour() - then.hour() : then.hour() - now.hour(),
 
                 minute = isBefore ? now.minute() - then.minute() : then.minute() - now.minute(),
            let year = t1.getFullYear() - t2.getFullYear(),
                 second = isBefore ? now.second() - then.second() : then.second() - now.second();
                 month = t1.getMonth() - t2.getMonth(),
             if (second < 0) {
                 day = t1.getDate() - t2.getDate(),
                minute--;
                 hour = t1.getHours() - t2.getHours(),
                second += 60;
                 minute = t1.getMinutes() - t2.getMinutes(),
            }
                 second = t1.getSeconds() - t2.getSeconds();
             if (minute < 0) {
 
                hour--;
            // 借位计算(
                minute += 60;
             if (second < 0) { minute--; second += 60; }
            }
             if (minute < 0) { hour--; minute += 60; }
             if (hour < 0) {
             if (hour < 0) { day--; hour += 24; }
                day--;
                hour += 24;
            }
             if (day < 0) {
             if (day < 0) {
                 month--;
                 month--;
                 if (monthsHave31Days.includes((isBefore ? then : now).month())) {
                 // 获取上个月到底有多少天来补齐
                    day += 31;
                let prevMonthDays = new Date(t1.getFullYear(), t1.getMonth(), 0).getDate();
                } else if ((isBefore ? then : now).month() === 1) {
                 day += prevMonthDays;
                    if ((isBefore ? then : now).year() % 4 === 0) {
                        day += 29;
                    } else {
                        day += 28;
                    }
                 } else {
                    day += 30;
                }
            }
            if (month < 0) {
                year--;
                month += 12;
             }
             }
            if (month < 0) { year--; month += 12; }
            // 组装最终显示的文字
             let result = "";
             let result = "";
             if (year > 0) {
             if (year > 0) result += year + "";
                result += `${year}`;
             if (month > 0) result += month + ""; else if (result !== "") result += "0月";
            }
             if (day > 0) result += day + ""; else if (result !== "") result += "0日";
             if (month > 0) {
             if (hour > 0) result += hour + "小时"; else if (result !== "") result += "0小时";
                result += `${month}`;
             if (minute > 0) result += minute + ""; else if (result !== "") result += "0分";
            } else if (result !== "") {
             if (second > 0) result += second + ""; else if (result !== "") result += "0秒";
                result += `${0}`;
 
            }
             return (result === "" ? on : isBefore ? before : after).replace("$1", result);
             if (day > 0) {
                result += `${day}`;
            } else if (result !== "") {
                result += `${0}`;
            }
             if (hour > 0) {
                result += `${hour}小时`;
            } else if (result !== "") {
                result += `${0}小时`;
            }
             if (minute > 0) {
                result += `${minute}`;
            } else if (result !== "") {
                result += `${0}`;
            }
             if (second > 0) {
                result += `${second}`;
            } else if (result !== "") {
                result += `${0}`;
            }
             return (result === "" ? on : isBefore ? before : after).replace("$1", result.replace(/(\d) /g, "$1"));
         };
         };
       
 
         const run = () => {
         // 第一步:把网页上所的倒计时盒子找出来并给它们分配好时间
            if (typeof jQuery === 'undefined') {
        document.querySelectorAll(".countdownNode").forEach(ele => {
                // 如果没jQuery使用原生方法
            const timeStr = ele.dataset.target || ele.getAttribute("data-target");
                document.querySelectorAll(".countdownNode:not(.disabled)").forEach(ele => {
            if (!timeStr) return;
                    const time = moment(ele.dataset.target);
           
                    if (time && time.isValid()) {
            // 兼容性处理:把横杠换成斜杠,防止苹果设备报错
                        ele.textContent = fromNow(time, ele.dataset.before || "$1前", ele.dataset.after || "还剩$1", ele.dataset.on || "就是现在!");
            const safeTimeStr = timeStr.replace(/-/g, '/');
                    }
            const time = new Date(safeTimeStr);
                });
           
            if (isNaN(time.getTime())) {
                ele.classList.add("error", "disabled");
                ele.textContent = "(时间格式解析错误";
             } else {
             } else {
                 // 有 jQuery 就用 jQuery
                 ele._countdownTarget = time;
                jQuery(".countdownNode:not(.disabled)").each((_, ele) => {
                    const self = jQuery(ele);
                    self.text(fromNow(self.data("target"), ele.dataset.before || "$1前", ele.dataset.after || "还剩$1", ele.dataset.on || "就是现在!"));
                });
             }
             }
         };
         });
       
 
         // 初始化所有倒计时节点
         // 第二步:执行更新的动作
         if (typeof jQuery === 'undefined') {
         const run = () => {
            // 原生方式
             document.querySelectorAll(".countdownNode:not(.disabled)").forEach(ele => {
             document.querySelectorAll(".countdownNode").forEach(ele => {
                 const time = ele._countdownTarget;
                 const time = moment(ele.dataset.target);
                 if (time && !isNaN(time.getTime())) {
                 if (!time || !time.isValid()) {
                     ele.textContent = fromNow(
                     ele.classList.add("error", "disabled");
                        time,
                    ele.textContent = "(发生了致命错误";
                        ele.dataset.before || "$1前",  
                } else {
                        ele.dataset.after || "还剩$1",
                     ele._countdownTarget = time;
                        ele.dataset.on || "就是现在!"
                     );
                 }
                 }
             });
             });
         } else {
         };
            // jQuery 方式
 
            jQuery(".countdownNode").each((_, ele) => {
        // 马上显示一次,然后每隔 1000 毫秒(1秒跳动一次
                const self = jQuery(ele),
                    time = moment(ele.dataset.target);
                if (!time || !time.isValid()) {
                    self.addClass("error disabled").text("(发生了致命错误!");
                    return;
                }
                self.data("target", time);
            });
        }
       
         run();
         run();
         window.setInterval(run, 1000);
         window.setInterval(run, 500);
     }
     }
})();
})();
</script><!--{/if}--></includeonly>
</script></includeonly>

2026年3月4日 (三) 13:27的最新版本

仅供{{Countdown}}使用。