Mobile WebTool

手机网页工具:全屏切换、页面缩放

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey, Greasemonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да инсталирате разширение, като например Tampermonkey .

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Userscripts.

За да инсталирате скрипта, трябва да инсталирате разширение като Tampermonkey.

За да инсталирате този скрипт, трябва да имате инсталиран скриптов мениджър.

(Вече имам скриптов мениджър, искам да го инсталирам!)

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

(Вече имам инсталиран мениджър на стиловете, искам да го инсталирам!)

// ==UserScript==
// @name         Mobile WebTool
// @namespace    howardzhangdqs
// @version      1.0.0
// @author       HowardZhangdqs
// @description  手机网页工具:全屏切换、页面缩放
// @license      WTFPL
// @icon         https://vitejs.dev/logo.svg
// @match        *://*/*
// @run-at       document-idle
// ==/UserScript==

(function () {
  'use strict';

  const styles = ":host{all:initial;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif}.mwt-container{position:fixed;top:8px;left:8px;z-index:2147483647;user-select:none;-webkit-user-select:none;transition:opacity .3s}.mwt-btn{width:38px;height:38px;border-radius:10px;border:none;background:#0000008c;color:#fff;display:flex;align-items:center;justify-content:center;cursor:pointer;box-shadow:0 2px 8px #0000004d;transition:background .2s,transform .15s;-webkit-tap-highlight-color:transparent;padding:0;line-height:1}.mwt-btn svg{width:20px;height:20px}.mwt-btn:active{background:#000000bf;transform:scale(.92)}.mwt-menu{margin-top:6px;background:#1e1e1eeb;backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);border-radius:10px;padding:4px 0;min-width:120px;box-shadow:0 4px 16px #0006;overflow:hidden;opacity:0;transform:translateY(-8px) scale(.95);transition:opacity .2s,transform .2s;pointer-events:none}.mwt-menu.mwt-open{opacity:1;transform:translateY(0) scale(1);pointer-events:auto}.mwt-zoom-display{padding:6px 14px;text-align:center;font-size:12px;color:#ffffff80;border-bottom:1px solid rgba(255,255,255,.08);font-variant-numeric:tabular-nums}.mwt-menu-item{display:flex;align-items:center;gap:8px;width:100%;padding:9px 14px;border:none;background:none;color:#fff;font-size:14px;cursor:pointer;text-align:left;transition:background .15s;-webkit-tap-highlight-color:transparent;font-family:inherit}.mwt-menu-item:active{background:#ffffff1a}.mwt-menu-item+.mwt-menu-item{border-top:1px solid rgba(255,255,255,.06)}.mwt-menu-icon{width:18px;height:18px;flex-shrink:0;display:flex;align-items:center;justify-content:center}.mwt-menu-icon svg{width:100%;height:100%}";
  const svgTool = '<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"><path d="M686-132 444-376q-20 8-40.5 12t-43.5 4q-100 0-170-70t-70-170q0-36 10-68.5t28-61.5l146 146 72-72-146-146q29-18 61.5-28t68.5-10q100 0 170 70t70 170q0 23-4 43.5T584-516l244 242q12 12 12 29t-12 29l-84 84q-12 12-29 12t-29-12Zm29-85 27-27-256-256q18-20 26-46.5t8-53.5q0-60-38.5-104.5T386-758l74 74q12 12 12 28t-12 28L332-500q-12 12-28 12t-28-12l-74-74q9 57 53.5 95.5T360-440q26 0 52-8t47-25l256 256ZM472-488Z"/></svg>';
  const svgFullscreen = '<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"><path d="M800-600v-120H680v-80h120q33 0 56.5 23.5T880-720v120h-80Zm-720 0v-120q0-33 23.5-56.5T160-800h120v80H160v120H80Zm600 440v-80h120v-120h80v120q0 33-23.5 56.5T800-160H680Zm-520 0q-33 0-56.5-23.5T80-240v-120h80v120h120v80H160Zm80-160v-320h480v320H240Zm80-80h320v-160H320v160Zm0 0v-160 160Z"/></svg>';
  const svgZoomIn = '<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"><path d="M784-120 532-372q-30 24-69 38t-83 14q-109 0-184.5-75.5T120-580q0-109 75.5-184.5T380-840q109 0 184.5 75.5T640-580q0 44-14 83t-38 69l252 252-56 56ZM380-400q75 0 127.5-52.5T560-580q0-75-52.5-127.5T380-760q-75 0-127.5 52.5T200-580q0 75 52.5 127.5T380-400Zm-40-60v-80h-80v-80h80v-80h80v80h80v80h-80v80h-80Z"/></svg>';
  const svgZoomOut = '<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"><path d="M784-120 532-372q-30 24-69 38t-83 14q-109 0-184.5-75.5T120-580q0-109 75.5-184.5T380-840q109 0 184.5 75.5T640-580q0 44-14 83t-38 69l252 252-56 56ZM380-400q75 0 127.5-52.5T560-580q0-75-52.5-127.5T380-760q-75 0-127.5 52.5T200-580q0 75 52.5 127.5T380-400ZM280-540v-80h200v80H280Z"/></svg>';
  const svgReset = '<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"><path d="M440-122q-121-15-200.5-105.5T160-440q0-66 26-126.5T260-672l57 57q-38 34-57.5 79T240-440q0 88 56 155.5T440-202v80Zm80 0v-80q87-16 143.5-83T720-440q0-100-70-170t-170-70h-3l44 44-56 56-140-140 140-140 56 56-44 44h3q134 0 227 93t93 227q0 121-79.5 211.5T520-122Z"/></svg>';
  const ZOOM_STEP = 10;
  const ZOOM_MIN = 30;
  const ZOOM_MAX = 200;
  const AUTO_HIDE_MS = 1e4;
  (() => {
    let currentZoom = 100;
    let menuOpen = false;
    let hideTimer;
    const host = document.createElement("div");
    host.id = "mwt-root";
    document.body.appendChild(host);
    const shadow = host.attachShadow({ mode: "closed" });
    const styleEl = document.createElement("style");
    styleEl.textContent = styles;
    shadow.appendChild(styleEl);
    const container = document.createElement("div");
    container.className = "mwt-container";
    shadow.appendChild(container);
    const btn = document.createElement("button");
    btn.className = "mwt-btn";
    btn.innerHTML = svgTool;
    container.appendChild(btn);
    const menu = document.createElement("div");
    menu.className = "mwt-menu";
    container.appendChild(menu);
    const zoomDisplay = document.createElement("div");
    zoomDisplay.className = "mwt-zoom-display";
    zoomDisplay.textContent = `${currentZoom}%`;
    menu.appendChild(zoomDisplay);
    function createMenuItem(icon, label, onClick) {
      const item = document.createElement("button");
      item.className = "mwt-menu-item";
      item.innerHTML = `<span class="mwt-menu-icon">${icon}</span><span>${label}</span>`;
      item.addEventListener("click", (e) => {
        e.stopPropagation();
        resetHideTimer();
        onClick();
      });
      menu.appendChild(item);
      return item;
    }
    const fullscreenItem = createMenuItem(svgFullscreen, "全屏", toggleFullscreen);
    createMenuItem(svgZoomIn, "放大", zoomIn);
    createMenuItem(svgZoomOut, "缩小", zoomOut);
    createMenuItem(svgReset, "重置缩放", zoomReset);
    function resetHideTimer() {
      clearTimeout(hideTimer);
      hideTimer = setTimeout(() => {
        container.style.opacity = "0";
        container.style.pointerEvents = "none";
        setTimeout(() => host.remove(), 300);
      }, AUTO_HIDE_MS);
    }
    resetHideTimer();
    function updateZoomDisplay() {
      zoomDisplay.textContent = `${currentZoom}%`;
      document.documentElement.style.zoom = `${currentZoom}%`;
    }
    function toggleFullscreen() {
      if (document.fullscreenElement) {
        document.exitFullscreen();
      } else {
        document.documentElement.requestFullscreen();
      }
      toggleMenu();
    }
    function updateFullscreenIcon() {
      fullscreenItem.querySelector(".mwt-menu-icon").innerHTML = svgFullscreen;
    }
    function zoomIn() {
      currentZoom = Math.min(currentZoom + ZOOM_STEP, ZOOM_MAX);
      updateZoomDisplay();
    }
    function zoomOut() {
      currentZoom = Math.max(currentZoom - ZOOM_STEP, ZOOM_MIN);
      updateZoomDisplay();
    }
    function zoomReset() {
      currentZoom = 100;
      updateZoomDisplay();
    }
    function toggleMenu() {
      menuOpen = !menuOpen;
      menu.classList.toggle("mwt-open", menuOpen);
    }
    btn.addEventListener("click", (e) => {
      e.stopPropagation();
      toggleMenu();
      resetHideTimer();
    });
    document.addEventListener("click", () => {
      if (menuOpen) {
        menuOpen = false;
        menu.classList.remove("mwt-open");
      }
    });
    document.addEventListener("fullscreenchange", () => {
      updateFullscreenIcon();
    });
  })();

})();