打开/关闭菜单
打开/关闭外观设置菜单
打开/关闭个人菜单
未登录
未登录用户的IP地址会在进行任意编辑后公开展示。

MediaWiki:Citizen.js:修订间差异

MediaWiki界面页面
OnlyOTO留言 | 贡献
创建页面,内容为“这里所有JavaScript都会加载给Citizen皮肤的用户:​ (function() { mw.loader.using('jquery', function() { $(function() { // 防重复挂载 if (document.querySelector('.magnetic-pointer-original')) return; // 创建光标DOM const pointer = document.createElement('div'); pointer.className = 'magnetic-pointer-original'; pointer.innerHTML = '<div></div><div></div><di…”
 
OnlyOTO留言 | 贡献
无编辑摘要
标签手工回退
 
(未显示同一用户的17个中间版本)
第1行: 第1行:
/* 这里所有JavaScript都会加载给Citizen皮肤的用户 */
(function() {
(function() {
    mw.loader.using('jquery', function() {
// 页面白名单
        $(function() {
const allowPages = [
            // 防重复挂载
  "首页",
            if (document.querySelector('.magnetic-pointer-original')) return;
  "Main Page",
  "你的自定义首页名字"
];
const currentPage = mw.config.get("wgTitle");


            // 创建光标DOM
            const pointer = document.createElement('div');
            pointer.className = 'magnetic-pointer-original';
            pointer.innerHTML = '<div></div><div></div><div></div><div></div>';
            document.body.appendChild(pointer);


            // 终极修复CSS:纯镂空四角 + 适配Citizen层级
if( !allowPages.includes(currentPage) ){
            const style = document.createElement('style');
  return;
            style.textContent = `
/* 光标本体 */
.magnetic-pointer-original {
    --width: 4rem;
    --height: 4rem;
    position: fixed;
    top: calc(var(--height) / -2);
    left: calc(var(--width) / -2);
    width: var(--width);
    height: var(--height);
    transition: all 0.2s ease-out;
    pointer-events: none;
    z-index: 999999 !important; /* 压过Citizen所有弹窗/导航 */
}
}
/* 四角拐角 - 杜绝方块 */
if( window.magneticCursorInit ) return;
.magnetic-pointer-original div {
window.magneticCursorInit = true;
     position: absolute;
 
     width: 12px;
mw.loader.using( [], function() {
     height: 12px;
     // 创建四角光标
     border-color: #17f700;
     const ptr = document.createElement('div');
     background: transparent !important;
     ptr.className = 'magnetic-true-corner';
     box-shadow: none !important;
     ptr.innerHTML = `<i></i><i></i><i></i><i></i>`;
     margin: 0 !important;
     document.body.appendChild(ptr);
     padding: 0 !important;
 
     // 样式
     const css = document.createElement('style');
     css.textContent = `
 
/* 隐藏浏览器原生光标 */
body {
  cursor: none !important;
}
}
.magnetic-pointer-original div:nth-child(1) {top:0;left:0;border-top:2px solid;border-left:2px solid;}
/* 防止输入框/按钮露馅,强制全局隐藏 */
.magnetic-pointer-original div:nth-child(2) {top:0;right:0;border-top:2px solid;border-right:2px solid;}
* {
.magnetic-pointer-original div:nth-child(3) {bottom:0;left:0;border-bottom:2px solid;border-left:2px solid;}
  cursor: none !important;
.magnetic-pointer-original div:nth-child(4) {bottom:0;right:0;border-bottom:2px solid;border-right:2px solid;}
 
/* 锁定Citizen皮肤所有按钮为磁吸目标 */
.citizen-button,
.citizen-ui-button,
.citizen-nav-item a,
.citizen-menu-item a,
#citizen-header a,
#citizen-sidebar a,
.vector-tabs a,
.mw-editsection,
a.citizen-link-button {
    position: relative !important;
}
}
            `;
            document.head.appendChild(style);


            let currentTarget = null;
    .magnetic-true-corner{
            let currentX = 0, currentY = 0;
        position:fixed;
        left:0;top:0;
        width:0;height:0;
        pointer-events:none;
        z-index:999999!important;
    }
    .magnetic-true-corner i{
        position:absolute;
        width:14px;height:14px;
        border:2px solid #888e99;
        background:transparent!important;
        box-shadow:none!important;
    }
    .magnetic-true-corner i:nth-child(1){top:-2px;left:-2px;border-right:none;border-bottom:none;}
    .magnetic-true-corner i:nth-child(2){top:-2px;right:-2px;border-left:none;border-bottom:none;}
    .magnetic-true-corner i:nth-child(3){bottom:-2px;left:-2px;border-right:none;border-top:none;}
    .magnetic-true-corner i:nth-child(4){bottom:-2px;right:-2px;border-left:none;border-top:none;}
    `;
    document.head.appendChild(css);


            // 磁吸跟随逻辑
    let hoverEl = null;
            const onMouseMove = function(e) {
    let mx = 0, my = 0;
                let x = e.clientX;
    // 光标缓冲坐标
                let y = e.clientY;
    let smoothX = 0, smoothY = 0;
                if (currentTarget) {
    let curW = 40, curH = 40;
                    const rect = currentTarget.getBoundingClientRect();
                    const centerX = rect.left + rect.width / 2;
                    const centerY = rect.top + rect.height / 2;
                    x = centerX + (x - centerX) * 0.12; // 微调吸附顺滑度
                    y = centerY + (y - centerY) * 0.12;
                }
                currentX = x;
                currentY = y;
                pointer.style.transform = `translate(${currentX}px, ${currentY}px)`;
            };


            const onMouseEnter = function(e) {
    // 鼠标实时位置
                currentTarget = e.currentTarget;
    document.addEventListener('mousemove', e => {
                const rect = currentTarget.getBoundingClientRect();
        mx = e.clientX;
                // 贴合Citizen按钮间距,放大留白更自然
        my = e.clientY;
                const gap = window.innerWidth / 60;
    });
                pointer.style.setProperty('--width', rect.width + gap + 'px');
                pointer.style.setProperty('--height', rect.height + gap + 'px');
            };


            const onMouseLeave = function() {
    // 顺滑帧磁吸缓冲
                currentTarget = null;
    function loop(){
                pointer.style.setProperty('--width', '4rem');
        const ease = 0.15; // 磁吸顺滑度
                pointer.style.setProperty('--height', '4rem');
        if(hoverEl){
             };
            // 吸附到元素中心 + 缓冲
            const r = hoverEl.getBoundingClientRect();
            const targetX = r.left + r.width / 2;
            const targetY = r.top + r.height / 2;
            smoothX += (targetX - smoothX) * ease;
            smoothY += (targetY - smoothY) * ease;
            curW = r.width;
             curH = r.height;


             // 自动绑定:Citizen全系列按钮 + 原有自定义_target
             // 四角框
             const bindCitizenButtons = function() {
             ptr.style.left = (smoothX - curW / 2) + 'px';
                const selector = `
            ptr.style.top = (smoothY - curH / 2) + 'px';
                    .citizen-button:not([data-bound]),
            ptr.style.width = curW + 'px';
                    .citizen-ui-button:not([data-bound]),
            ptr.style.height = curH + 'px';
                    .citizen-nav-item a:not([data-bound]),
        }else{
                    .citizen-menu-item a:not([data-bound]),
            // 常态跟随鼠标
                    #citizen-header a:not([data-bound]),
            curW = 40;
                    #citizen-sidebar a:not([data-bound]),
            curH = 40;
                    .mw-editsection:not([data-bound]),
            smoothX += (mx - smoothX) * ease;
                    a.citizen-link-button:not([data-bound]),
            smoothY += (my - smoothY) * ease;
                    ._target:not([data-bound])
                `;
                document.querySelectorAll(selector).forEach(el => {
                    el.dataset.bound = "1";
                    el.addEventListener('mouseenter', onMouseEnter);
                    el.addEventListener('mouseleave', onMouseLeave);
                });
            };


             // 全局鼠标监听
             ptr.style.left = (smoothX - 20) + 'px';
             window.addEventListener('mousemove', onMouseMove);
             ptr.style.top = (smoothY - 20) + 'px';
            ptr.style.width = curW + 'px';
            ptr.style.height = curH + 'px';
        }
        requestAnimationFrame(loop);
    }
    loop();


            // 初始绑定
const sel = [
            bindCitizenButtons();
    // 官方皮肤按钮
    '.citizen-nav a',
    '.citizen-menu a',
    '.citizen-button',
    '.citizen-action-button',
    '.cdx-button',
    '.mw-editsection a',
    '#citizen-header__nav a',
    '.citizen-sidebar a',
   
    // 自己加的 _target
    '._target',
   
    // Commentstreams扩展
    '.commentstreams-button',
    '.commentstreams-submit',
    '.commentstreams-header button',
    '.commentstreams-box button',
   
    // 常用
    '.mw-ui-button',
    'button',
    'a[role="button"]'
].join(',');


             // 监听动态加载(侧边栏折叠/展开、AJAX页面、弹窗)
    function bind(){
             const observer = new MutationObserver(() => bindCitizenButtons());
        document.querySelectorAll(sel).forEach(el=>{
             observer.observe(document.body, { childList: true, subtree: true, attributes: true });
             if(el._magBind)return;
             el._magBind = 1;
            el.addEventListener('mouseenter', ()=> hoverEl = el);
             el.addEventListener('mouseleave', ()=> hoverEl = null);
         });
         });
     });
     }
 
    bind();
    new MutationObserver(bind).observe(document.body,{childList:true,subtree:true});
});
})();
})();

2026年3月31日 (二) 23:17的最新版本

(function() {
// 页面白名单
const allowPages = [
  "首页",
  "Main Page",
  "你的自定义首页名字"
];
const currentPage = mw.config.get("wgTitle");


if( !allowPages.includes(currentPage) ){
  return;
}
if( window.magneticCursorInit ) return;
window.magneticCursorInit = true;

mw.loader.using( [], function() {
    // 创建四角光标
    const ptr = document.createElement('div');
    ptr.className = 'magnetic-true-corner';
    ptr.innerHTML = `<i></i><i></i><i></i><i></i>`;
    document.body.appendChild(ptr);

    // 样式
    const css = document.createElement('style');
    css.textContent = `

/* 隐藏浏览器原生光标 */
body {
  cursor: none !important;
}
/* 防止输入框/按钮露馅,强制全局隐藏 */
* {
  cursor: none !important;
}

    .magnetic-true-corner{
        position:fixed;
        left:0;top:0;
        width:0;height:0;
        pointer-events:none;
        z-index:999999!important;
    }
    .magnetic-true-corner i{
        position:absolute;
        width:14px;height:14px;
        border:2px solid #888e99;
        background:transparent!important;
        box-shadow:none!important;
    }
    .magnetic-true-corner i:nth-child(1){top:-2px;left:-2px;border-right:none;border-bottom:none;}
    .magnetic-true-corner i:nth-child(2){top:-2px;right:-2px;border-left:none;border-bottom:none;}
    .magnetic-true-corner i:nth-child(3){bottom:-2px;left:-2px;border-right:none;border-top:none;}
    .magnetic-true-corner i:nth-child(4){bottom:-2px;right:-2px;border-left:none;border-top:none;}
    `;
    document.head.appendChild(css);

    let hoverEl = null;
    let mx = 0, my = 0;
    // 光标缓冲坐标
    let smoothX = 0, smoothY = 0;
    let curW = 40, curH = 40;

    // 鼠标实时位置
    document.addEventListener('mousemove', e => {
        mx = e.clientX;
        my = e.clientY;
    });

    // 顺滑帧磁吸缓冲
    function loop(){
        const ease = 0.15; // 磁吸顺滑度
        if(hoverEl){
            // 吸附到元素中心 + 缓冲
            const r = hoverEl.getBoundingClientRect();
            const targetX = r.left + r.width / 2;
            const targetY = r.top + r.height / 2;
            smoothX += (targetX - smoothX) * ease;
            smoothY += (targetY - smoothY) * ease;
            curW = r.width;
            curH = r.height;

            // 四角框
            ptr.style.left = (smoothX - curW / 2) + 'px';
            ptr.style.top = (smoothY - curH / 2) + 'px';
            ptr.style.width = curW + 'px';
            ptr.style.height = curH + 'px';
        }else{
            // 常态跟随鼠标
            curW = 40;
            curH = 40;
            smoothX += (mx - smoothX) * ease;
            smoothY += (my - smoothY) * ease;

            ptr.style.left = (smoothX - 20) + 'px';
            ptr.style.top = (smoothY - 20) + 'px';
            ptr.style.width = curW + 'px';
            ptr.style.height = curH + 'px';
        }
        requestAnimationFrame(loop);
    }
    loop();

const sel = [
    // 官方皮肤按钮
    '.citizen-nav a',
    '.citizen-menu a',
    '.citizen-button',
    '.citizen-action-button',
    '.cdx-button',
    '.mw-editsection a',
    '#citizen-header__nav a',
    '.citizen-sidebar a',
    
    // 自己加的 _target 
    '._target',
    
    // Commentstreams扩展
    '.commentstreams-button',
    '.commentstreams-submit',
    '.commentstreams-header button',
    '.commentstreams-box button',
    
    // 常用
    '.mw-ui-button',
    'button',
    'a[role="button"]'
].join(',');

    function bind(){
        document.querySelectorAll(sel).forEach(el=>{
            if(el._magBind)return;
            el._magBind = 1;
            el.addEventListener('mouseenter', ()=> hoverEl = el);
            el.addEventListener('mouseleave', ()=> hoverEl = null);
        });
    }

    bind();
    new MutationObserver(bind).observe(document.body,{childList:true,subtree:true});
});
})();