// ==UserScript== // @name 双击全屏(使用手机浏览器) // @namespace http://tampermonkey.net/ // @version 1.7 // @description 双击切换全屏,不影响视频操作,键盘弹出时对话框自动抬高。就这么一个简单的操作,居然没人能做好,那就自己来! // @author 青野 // @match *://*/* // @grant none // @license MIT // @downloadURL https://update.greasyfork.icu/scripts/557840/%E5%8F%8C%E5%87%BB%E5%85%A8%E5%B1%8F%EF%BC%88%E4%BD%BF%E7%94%A8%E6%89%8B%E6%9C%BA%E6%B5%8F%E8%A7%88%E5%99%A8%EF%BC%89.user.js // @updateURL https://update.greasyfork.icu/scripts/557840/%E5%8F%8C%E5%87%BB%E5%85%A8%E5%B1%8F%EF%BC%88%E4%BD%BF%E7%94%A8%E6%89%8B%E6%9C%BA%E6%B5%8F%E8%A7%88%E5%99%A8%EF%BC%89.meta.js // ==/UserScript== (function() { 'use strict'; let lastTapTime = 0; const doubleTapDelay = 300; // 双击间隔时间(毫秒) // 检查是否为可输入元素 function isInputElement(element) { const tagName = element.tagName.toLowerCase(); const inputTags = ['input', 'textarea', 'select']; const isContentEditable = element.isContentEditable; const isInputRole = element.getAttribute('role') === 'textbox'; return inputTags.includes(tagName) || isContentEditable || isInputRole; } // 检查是否在视频控件区域 function isVideoControls(element) { let current = element; while (current) { if (current.tagName && current.tagName.toLowerCase() === 'video') { return false; // 视频元素本身可以双击 } // 检查是否是视频控件容器 const className = current.className || ''; if (typeof className === 'string' && (className.includes('controls') || className.includes('player-controls') || className.includes('video-controls'))) { return true; } current = current.parentElement; } return false; } // 检查当前是否处于全屏状态 function isFullscreen() { return !!(document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement); } // 进入全屏 function enterFullscreen() { const elem = document.documentElement; if (elem.requestFullscreen) { elem.requestFullscreen(); } else if (elem.webkitRequestFullscreen) { elem.webkitRequestFullscreen(); } else if (elem.mozRequestFullScreen) { elem.mozRequestFullScreen(); } else if (elem.msRequestFullscreen) { elem.msRequestFullscreen(); } } // 退出全屏 function exitFullscreen() { if (document.exitFullscreen) { document.exitFullscreen(); } else if (document.webkitExitFullscreen) { document.webkitExitFullscreen(); } else if (document.mozCancelFullScreen) { document.mozCancelFullScreen(); } else if (document.msExitFullscreen) { document.msExitFullscreen(); } } // 切换全屏 function toggleFullscreen() { if (!isFullscreen()) { enterFullscreen(); } else { exitFullscreen(); } } // 双击事件处理 function handleTap(e) { const target = e.target; // 忽略输入元素 if (isInputElement(target)) { return; } // 忽略视频控件区域 if (isVideoControls(target)) { return; } const currentTime = new Date().getTime(); const tapLength = currentTime - lastTapTime; if (tapLength < doubleTapDelay && tapLength > 0) { // 双击检测成功 e.preventDefault(); toggleFullscreenWithFlag(); lastTapTime = 0; // 重置 } else { lastTapTime = currentTime; } } // 监听触摸结束事件(移动端) document.addEventListener('touchend', function(e) { // 确保只是单点触摸 if (e.changedTouches.length === 1) { handleTap(e); } }, { passive: false }); // 处理返回键:在全屏状态下,保持全屏并执行返回上一页 // 核心思路:检测非双击导致的全屏退出,自动重新进入全屏 let isDoubleTapExit = false; // 标记是否是双击主动退出全屏 // 重写 toggleFullscreen,标记双击退出 function toggleFullscreenWithFlag() { if (!isFullscreen()) { enterFullscreen(); } else { isDoubleTapExit = true; exitFullscreen(); } } // 监听全屏状态变化 function handleFullscreenChange() { if (!isFullscreen()) { // 全屏被退出了 if (isDoubleTapExit) { // 是用户双击主动退出的,不做处理 isDoubleTapExit = false; } else { // 不是双击退出的(比如按了返回键),重新进入全屏 // 使用 requestAnimationFrame 确保在下一帧执行 requestAnimationFrame(() => { enterFullscreen(); }); } } } document.addEventListener('fullscreenchange', handleFullscreenChange); document.addEventListener('webkitfullscreenchange', handleFullscreenChange); document.addEventListener('mozfullscreenchange', handleFullscreenChange); document.addEventListener('MSFullscreenChange', handleFullscreenChange); // 键盘弹出时对话框抬高处理 function handleKeyboardResize() { // 检测可能的对话框元素 const dialogSelectors = [ 'dialog', '[role="dialog"]', '[role="alertdialog"]', '.modal', '.dialog', '.popup', '[class*="modal"]', '[class*="dialog"]', '[class*="popup"]' ]; const visualViewport = window.visualViewport; if (visualViewport) { visualViewport.addEventListener('resize', function() { const keyboardHeight = window.innerHeight - visualViewport.height; dialogSelectors.forEach(selector => { const dialogs = document.querySelectorAll(selector); dialogs.forEach(dialog => { if (dialog.offsetParent !== null) { // 可见的对话框 if (keyboardHeight > 100) { // 键盘可能已弹出 dialog.style.transition = 'transform 0.3s ease'; dialog.style.transform = `translateY(-${keyboardHeight / 2}px)`; } else { dialog.style.transform = 'translateY(0)'; } } }); }); }); visualViewport.addEventListener('scroll', function() { // 保持对话框位置 const scrollTop = visualViewport.offsetTop; dialogSelectors.forEach(selector => { const dialogs = document.querySelectorAll(selector); dialogs.forEach(dialog => { if (dialog.offsetParent !== null && dialog.style.position === 'fixed') { dialog.style.top = `${scrollTop}px`; } }); }); }); } // 备用方案:监听焦点事件 document.addEventListener('focusin', function(e) { if (isInputElement(e.target)) { setTimeout(() => { dialogSelectors.forEach(selector => { const dialogs = document.querySelectorAll(selector); dialogs.forEach(dialog => { if (dialog.offsetParent !== null) { dialog.scrollIntoView({ behavior: 'smooth', block: 'center' }); } }); }); }, 300); } }); document.addEventListener('focusout', function(e) { if (isInputElement(e.target)) { setTimeout(() => { dialogSelectors.forEach(selector => { const dialogs = document.querySelectorAll(selector); dialogs.forEach(dialog => { dialog.style.transform = 'translateY(0)'; }); }); }, 100); } }); } // 初始化键盘处理 handleKeyboardResize(); console.log('🐵 双击全屏脚本已加载 v1.2 - 作者:青野'); })();