PageSourceSearch

https://gddhy.github.io/js/wechat-qq-blocker.js

js gddhy.github.io collected 2026-10-03 09:13:52 UTC 14,943 bytes, 449 lines download raw bytes

1/**
2 * 微信/QQ内置浏览器拦截弹窗
3 * 自动检测环境,若在微信或QQ内置浏览器中,则显示全屏遮罩,引导用户复制链接或使用浏览器打开。
4 * 用法:在HTML中引入 <script src="wechat-qq-blocker.js"></script> 即可,无需其他操作。
5 */
6(function() {
7    'use strict';
8
9    // ---------- 配置(可按需修改) ----------
10    var CONFIG = {
11        title: '温馨提示',
12        description: '检测到您在 <strong>微信</strong> 或 <strong>QQ</strong> 内置浏览器中打开,部分功能可能受限。',
13        guideSteps: [
14            '点击右上角 <span class="menu-icon">···</span> 菜单,选择「在浏览器中打开」',
15            '或 <strong>点击下方按钮</strong> 复制链接,手动打开浏览器粘贴访问'
16        ],
17        copyButtonText: '📋 复制网页链接',
18        copyButtonSub: '点击即可复制',
19        toastSuccess: '✅ 链接已复制,请前往浏览器打开',
20        toastError: '⚠️ 复制失败,请手动复制链接',
21        // 复制成功后的回调(可选)
22        onCopy: null
23    };
24
25    // ---------- 检测环境 ----------
26    function isWechatOrQQ() {
27        var ua = navigator.userAgent.toLowerCase();
28        return ua.indexOf('micromessenger') !== -1 ||
29            ua.indexOf('qq/') !== -1 ||
30            ua.indexOf('mqqbrowser') !== -1;
31    }
32
33    // 若不在微信/QQ中,直接退出
34    if (!isWechatOrQQ()) {
35        return;
36    }
37
38    // ---------- 避免重复注入 ----------
39    if (document.getElementById('wechat-qq-blocker-overlay')) {
40        return;
41    }
42
43    // ---------- 创建样式 ----------
44    var style = document.createElement('style');
45    style.id = 'wechat-qq-blocker-style';
46    style.textContent = `
47        /* 遮罩层 */
48        #wechat-qq-blocker-overlay {
49            position: fixed;
50            top: 0;
51            left: 0;
52            width: 100vw;
53            height: 100vh;
54            background: rgba(0, 0, 0, 0.72);
55            z-index: 999999;
56            display: flex;
57            justify-content: center;
58            align-items: center;
59            overflow: hidden;
60            pointer-events: auto;
61            touch-action: none;
62            animation: wqb-overlay-fade-in 0.35s ease-out;
63        }
64        @keyframes wqb-overlay-fade-in {
65            0% { opacity: 0; }
66            100% { opacity: 1; }
67        }
68
69        /* 弹窗卡片 */
70        #wechat-qq-blocker-modal {
71            position: relative;
72            width: 88%;
73            max-width: 380px;
74            background: #ffffff;
75            border-radius: 20px;
76            padding: 32px 26px 28px;
77            box-shadow: 0 20px 60px rgba(0, 0, 0, 0.45);
78            text-align: center;
79            pointer-events: auto;
80            touch-action: auto;
81            user-select: text;
82            -webkit-user-select: text;
83            animation: wqb-modal-pop 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
84        }
85        @keyframes wqb-modal-pop {
86            0% { transform: scale(0.85) translateY(30px); opacity: 0; }
87            100% { transform: scale(1) translateY(0); opacity: 1; }
88        }
89
90        #wechat-qq-blocker-modal .wqb-icon {
91            display: inline-block;
92            width: 56px;
93            height: 56px;
94            background: #ff6b35;
95            border-radius: 50%;
96            color: #fff;
97            font-size: 30px;
98            line-height: 56px;
99            text-align: center;
100            font-weight: 700;
101            margin-bottom: 14px;
102            box-shadow: 0 6px 20px rgba(255, 107, 53, 0.35);
103        }
104        #wechat-qq-blocker-modal h2 {
105            font-size: 22px;
106            font-weight: 700;
107            color: #1a1a2e;
108            margin-bottom: 10px;
109            letter-spacing: 0.5px;
110        }
111        #wechat-qq-blocker-modal .wqb-desc {
112            font-size: 15px;
113            line-height: 1.7;
114            color: #3d3d4e;
115            margin-bottom: 18px;
116            padding: 0 4px;
117        }
118        #wechat-qq-blocker-modal .wqb-desc strong {
119            color: #e84118;
120            font-weight: 600;
121        }
122
123        #wechat-qq-blocker-modal .wqb-guide {
124            background: #f8f9fc;
125            border-radius: 12px;
126            padding: 14px 16px;
127            margin: 12px 0 20px;
128            text-align: left;
129            font-size: 14px;
130            color: #2d3436;
131            border-left: 4px solid #ff6b35;
132        }
133        #wechat-qq-blocker-modal .wqb-guide .wqb-step {
134            display: flex;
135            align-items: flex-start;
136            gap: 10px;
137            padding: 4px 0;
138        }
139        #wechat-qq-blocker-modal .wqb-guide .wqb-step .wqb-num {
140            display: inline-flex;
141            justify-content: center;
142            align-items: center;
143            width: 22px;
144            height: 22px;
145            background: #ff6b35;
146            color: #fff;
147            border-radius: 50%;
148            font-size: 12px;
149            font-weight: 700;
150            flex-shrink: 0;
151            margin-top: 1px;
152        }
153        #wechat-qq-blocker-modal .wqb-guide .wqb-step .wqb-text {
154            line-height: 1.6;
155        }
156        #wechat-qq-blocker-modal .wqb-guide .wqb-step .wqb-text .menu-icon {
157            display: inline-block;
158            background: #e0e4ea;
159            padding: 0 10px;
160            border-radius: 4px;
161            font-size: 13px;
162            font-weight: 500;
163            color: #2d3436;
164        }
165
166        #wechat-qq-blocker-modal .wqb-copy-area {
167            margin-top: 8px;
168            padding: 12px 0 4px;
169            border-top: 1px dashed #e0e4ea;
170        }
171        #wechat-qq-blocker-modal .wqb-copy-btn {
172            display: inline-block;
173            width: 100%;
174            padding: 14px 0;
175            background: linear-gradient(135deg, #ff6b35, #f53b2c);
176            color: #fff;
177            font-size: 18px;
178            font-weight: 700;
179            border: none;
180            border-radius: 14px;
181            cursor: pointer;
182            letter-spacing: 1px;
183            box-shadow: 0 6px 24px rgba(255, 107, 53, 0.38);
184            transition: all 0.2s ease;
185            touch-action: manipulation;
186            -webkit-tap-highlight-color: transparent;
187        }
188        #wechat-qq-blocker-modal .wqb-copy-btn:active {
189            transform: scale(0.96);
190            box-shadow: 0 3px 12px rgba(255, 107, 53, 0.25);
191        }
192        #wechat-qq-blocker-modal .wqb-copy-btn .wqb-sub {
193            display: block;
194            font-size: 13px;
195            font-weight: 400;
196            opacity: 0.85;
197            margin-top: 2px;
198            letter-spacing: 0.3px;
199        }
200        #wechat-qq-blocker-modal .wqb-footer-tip {
201            margin-top: 14px;
202            font-size: 12px;
203            color: #999;
204            letter-spacing: 0.3px;
205        }
206
207        /* Toast */
208        #wechat-qq-blocker-toast {
209            position: fixed;
210            bottom: 15%;
211            left: 50%;
212            transform: translateX(-50%) scale(0.9);
213            background: rgba(0, 0, 0, 0.78);
214            color: #fff;
215            padding: 14px 32px;
216            border-radius: 12px;
217            font-size: 16px;
218            font-weight: 500;
219            z-index: 1000000;
220            opacity: 0;
221            transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
222            pointer-events: none;
223            backdrop-filter: blur(4px);
224            -webkit-backdrop-filter: blur(4px);
225            white-space: nowrap;
226            box-shadow: 0 10px 40px rgba(0, 0, 0, 0.35);
227        }
228        #wechat-qq-blocker-toast.wqb-show {
229            opacity: 1;
230            transform: translateX(-50%) scale(1);
231        }
232
233        /* 响应式 */
234        @media (max-width: 420px) {
235            #wechat-qq-blocker-modal {
236                padding: 24px 18px 22px;
237                width: 92%;
238            }
239            #wechat-qq-blocker-modal h2 {
240                font-size: 20px;
241            }
242            #wechat-qq-blocker-modal .wqb-desc {
243                font-size: 14px;
244            }
245            #wechat-qq-blocker-modal .wqb-copy-btn {
246                font-size: 17px;
247                padding: 13px 0;
248            }
249            #wechat-qq-blocker-modal .wqb-guide {
250                font-size: 13px;
251                padding: 12px 14px;
252            }
253            #wechat-qq-blocker-modal .wqb-icon {
254                width: 48px;
255                height: 48px;
256                font-size: 26px;
257                line-height: 48px;
258            }
259        }
260        @media (max-width: 350px) {
261            #wechat-qq-blocker-modal {
262                padding: 18px 14px 18px;
263            }
264            #wechat-qq-blocker-modal h2 {
265                font-size: 17px;
266            }
267            #wechat-qq-blocker-modal .wqb-desc {
268                font-size: 13px;
269            }
270            #wechat-qq-blocker-modal .wqb-copy-btn {
271                font-size: 15px;
272                padding: 11px 0;
273            }
274        }
275    `;
276    document.head.appendChild(style);
277
278    // ---------- 创建 HTML 结构 ----------
279    var overlay = document.createElement('div');
280    overlay.id = 'wechat-qq-blocker-overlay';
281
282    // 构建引导步骤
283    var stepsHtml = CONFIG.guideSteps.map(function(step, index) {
284        return '<div class="wqb-step"><span class="wqb-num">' + (index + 1) + '</span><span class="wqb-text">' + step + '</span></div>';
285    }).join('');
286
287    overlay.innerHTML = `
288        <div id="wechat-qq-blocker-modal">
289            <div class="wqb-icon">⚠</div>
290            <h2>${CONFIG.title}</h2>
291            <p class="wqb-desc">${CONFIG.description}</p>
292            <div class="wqb-guide">${stepsHtml}</div>
293            <div class="wqb-copy-area" id="wqb-copy-trigger">
294                <button class="wqb-copy-btn" id="wqb-copy-btn">
295                    ${CONFIG.copyButtonText}
296                    <span class="wqb-sub">${CONFIG.copyButtonSub}</span>
297                </button>
298            </div>
299            <p class="wqb-footer-tip">— 点击按钮或屏幕任意位置均可复制 —</p>
300        </div>
301    `;
302
303    document.body.appendChild(overlay);
304
305    // ---------- Toast 元素 ----------
306    var toast = document.createElement('div');
307    toast.id = 'wechat-qq-blocker-toast';
308    document.body.appendChild(toast);
309
310    // ---------- 锁定页面 ----------
311    document.body.style.overflow = 'hidden';
312    document.body.style.position = 'fixed';
313    document.body.style.width = '100%';
314    document.body.style.height = '100%';
315    document.body.style.webkitOverflowScrolling = 'none';
316
317    // ---------- 阻止遮罩下的滚动和事件 ----------
318    overlay.addEventListener('touchmove', function(e) {
319        e.preventDefault();
320    }, { passive: false });
321    overlay.addEventListener('wheel', function(e) {
322        e.preventDefault();
323    }, { passive: false });
324
325    document.addEventListener('keydown', function(e) {
326        if (e.key === 'Escape' || e.key === 'Esc') {
327            e.preventDefault();
328            e.stopPropagation();
329        }
330    }, true);
331    document.addEventListener('contextmenu', function(e) {
332        e.preventDefault();
333    }, true);
334
335    // ---------- 复制功能 ----------
336    var currentUrl = window.location.href;
337    var toastTimer = null;
338
339    function showToast(msg, isError) {
340        toast.textContent = msg;
341        toast.style.background = isError ? 'rgba(200,50,50,0.88)' : 'rgba(0,0,0,0.78)';
342        toast.classList.add('wqb-show');
343        if (toastTimer) clearTimeout(toastTimer);
344        toastTimer = setTimeout(function() {
345            toast.classList.remove('wqb-show');
346        }, 2200);
347    }
348
349    function copyLink() {
350        if (navigator.clipboard && navigator.clipboard.writeText) {
351            navigator.clipboard.writeText(currentUrl).then(function() {
352                showToast(CONFIG.toastSuccess);
353                if (typeof CONFIG.onCopy === 'function') CONFIG.onCopy(true);
354            }).catch(function() {
355                fallbackCopy(currentUrl);
356            });
357        } else {
358            fallbackCopy(currentUrl);
359        }
360    }
361
362    function fallbackCopy(text) {
363        var textarea = document.createElement('textarea');
364        textarea.value = text;
365        textarea.style.position = 'fixed';
366        textarea.style.opacity = '0';
367        textarea.style.left = '-9999px';
368        textarea.style.top = '-9999px';
369        document.body.appendChild(textarea);
370        textarea.select();
371        try {
372            var success = document.execCommand('copy');
373            if (success) {
374                showToast(CONFIG.toastSuccess);
375                if (typeof CONFIG.onCopy === 'function') CONFIG.onCopy(true);
376            } else {
377                showToast(CONFIG.toastError, true);
378                if (typeof CONFIG.onCopy === 'function') CONFIG.onCopy(false);
379            }
380        } catch (e) {
381            showToast(CONFIG.toastError, true);
382            if (typeof CONFIG.onCopy === 'function') CONFIG.onCopy(false);
383        }
384        document.body.removeChild(textarea);
385    }
386
387    // ---------- 绑定事件 ----------
388    var modal = document.getElementById('wechat-qq-blocker-modal');
389    var copyBtn = document.getElementById('wqb-copy-btn');
390    var copyTrigger = document.getElementById('wqb-copy-trigger');
391
392    // 点击复制按钮
393    copyBtn.addEventListener('click', function(e) {
394        e.stopPropagation();
395        copyLink();
396    });
397
398    // 点击复制区域
399    copyTrigger.addEventListener('click', function(e) {
400        e.stopPropagation();
401        copyLink();
402    });
403
404    // 点击弹窗卡片(除按钮/区域外)
405    modal.addEventListener('click', function(e) {
406        if (e.target.closest('#wqb-copy-btn') || e.target.closest('#wqb-copy-trigger')) {
407            return;
408        }
409        copyLink();
410    });
411
412    // 点击遮罩背景
413    overlay.addEventListener('click', function(e) {
414        if (e.target.closest('#wechat-qq-blocker-modal')) {
415            return;
416        }
417        copyLink();
418    });
419
420    // 阻止事件冒泡到下层
421    overlay.addEventListener('click', function(e) {
422        if (e.target.closest('#wechat-qq-blocker-modal')) {
423            return;
424        }
425        e.stopPropagation();
426    }, true);
427
428    overlay.addEventListener('touchstart', function(e) {
429        if (e.target.closest('#wechat-qq-blocker-modal')) {
430            return;
431        }
432        e.preventDefault();
433        e.stopPropagation();
434    }, { passive: false });
435
436    // 允许用户配置扩展(暴露全局对象)
437    window.WechatQQBlocker = {
438        config: CONFIG,
439        // 可手动调用复制
440        copyLink: copyLink,
441        // 可更新配置(需重新生成?但简单起见,只暴露)
442        updateConfig: function(newConfig) {
443            Object.assign(CONFIG, newConfig);
444        }
445    };
446
447    console.log('[WechatQQBlocker] 已拦截微信/QQ内置浏览器,弹窗已启动。');
448
449})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.