小窗预览

使用修饰键拖拽链接时在弹出窗口中打开链接,并在打开前提供预览,使用 Edge 的预读技术。同时在小窗口打开时在背后添加亚克力效果。

当前为 2024-08-24 提交的版本,查看 最新版本

// ==UserScript==
// @name         小窗预览
// @version      2.5
// @description  使用修饰键拖拽链接时在弹出窗口中打开链接,并在打开前提供预览,使用 Edge 的预读技术。同时在小窗口打开时在背后添加亚克力效果。
// @author       hiisme
// @match        *://*/*
// @grant        GM_registerMenuCommand
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_info
// @namespace    https://gf.qytechs.cn/users/217852
// ==/UserScript==

(function () {
  'use strict';

  const state = {
    isDragging: false,
    linkToPreload: null,
    popupWindow: null,
    acrylicOverlay: null,
  };

  const config = {
    windowWidth: GM_getValue('windowWidth', 870),
    windowHeight: GM_getValue('windowHeight', 530),
    screenLeft: (window.screen.width - GM_getValue('windowWidth', 870)) / 2,
    screenTop: (window.screen.height - GM_getValue('windowHeight', 530)) / 3,
    blurIntensity: GM_getValue('blurIntensity', 5),
    blurEnabled: GM_getValue('blurEnabled', true),
    closeOnMouseClick: GM_getValue('closeOnMouseClick', true),
    closeOnScroll: GM_getValue('closeOnScroll', true),
    modifierKey: GM_getValue('modifierKey', 'Shift'), // 新增修饰键设置
  };

  function delay(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
  }

  async function preloadLink(link, attributes = {}) {
    const preloadElement = document.createElement('link');
    preloadElement.rel = 'preload';
    preloadElement.href = link;
    preloadElement.as = '*/*';
    Object.assign(preloadElement, attributes);
    document.head.appendChild(preloadElement);
    await delay(1);
  }

  function createAcrylicOverlay() {
    const acrylicOverlay = document.createElement('div');
    acrylicOverlay.style.position = 'fixed';
    acrylicOverlay.style.top = '0';
    acrylicOverlay.style.left = '0';
    acrylicOverlay.style.width = '100%';
    acrylicOverlay.style.height = '100%';
    acrylicOverlay.style.zIndex = '9999';
    acrylicOverlay.style.backdropFilter = config.blurEnabled ? `blur(${config.blurIntensity}px)` : 'none';
    if (config.closeOnMouseClick) {
      acrylicOverlay.addEventListener('click', handleAcrylicOverlayClick);
    }
    document.body.appendChild(acrylicOverlay);
    return acrylicOverlay;
  }

  function handleAcrylicOverlayClick(event) {
    if (event.target === state.acrylicOverlay) {
      closePopupWindow();
    }
  }

  function removeAcrylicOverlay() {
    if (state.acrylicOverlay) {
      document.body.removeChild(state.acrylicOverlay);
      state.acrylicOverlay = null;
    }
  }

  function openPopupWindow(link) {
    if (!state.popupWindow || state.popupWindow.closed) {
      state.acrylicOverlay = createAcrylicOverlay();
      state.popupWindow = window.open(link, '_blank', `width=${config.windowWidth},height=${config.windowHeight},left=${config.screenLeft},top=${config.screenTop}`);
    }
  }

  function closePopupWindow() {
    if (state.popupWindow && !state.popupWindow.closed) {
      state.popupWindow.close();
      state.popupWindow = null;
      removeAcrylicOverlay();
      if (state.linkToPreload) {
        removePreloadedLink(state.linkToPreload);
      }
      window.removeEventListener('scroll', closePopupOnScroll);
    }
  }

  function removePreloadedLink(link) {
    const preloadElement = document.querySelector(`link[href="${link}"]`);
    if (preloadElement) {
      document.head.removeChild(preloadElement);
    }
  }

  function closePopupOnScroll() {
    if (state.popupWindow && !state.popupWindow.closed) {
      closePopupWindow();
    }
  }

  function registerMenuCommand(label, action) {
    return GM_registerMenuCommand(label, () => {
      action();
      updateMenuCommands();
    });
  }

  const menuCommands = [
    { label: `切换模糊效果 (${config.blurEnabled ? '开' : '关'})`, action: toggleBlurEffect },
    { label: `设置模糊强度 (${config.blurIntensity})`, action: setBlurIntensity },
    { label: `切换点击关闭小窗 (${config.closeOnMouseClick ? '开' : '关'})`, action: toggleCloseOnMouseClick },
    { label: `切换滚动关闭小窗 (${config.closeOnScroll ? '开' : '关'})`, action: toggleCloseOnScroll },
    { label: `设置小窗宽度 (${config.windowWidth})`, action: () => { setWindowSize('width'); } },
    { label: `设置小窗高度 (${config.windowHeight})`, action: () => { setWindowSize('height'); } },
    { label: `设置修饰键 (${config.modifierKey})`, action: setModifierKey } // 新增菜单选项
  ];

  function toggleBlurEffect() {
    config.blurEnabled = !config.blurEnabled;
    GM_setValue('blurEnabled', config.blurEnabled);
  }

  function setBlurIntensity() {
    const intensity = prompt('输入模糊强度(0-10):', config.blurIntensity);
    if (intensity !== null) {
      config.blurIntensity = parseInt(intensity, 10);
      GM_setValue('blurIntensity', config.blurIntensity);
    }
  }

  function toggleCloseOnMouseClick() {
    config.closeOnMouseClick = !config.closeOnMouseClick;
    GM_setValue('closeOnMouseClick', config.closeOnMouseClick);
  }

  function toggleCloseOnScroll() {
    config.closeOnScroll = !config.closeOnScroll;
    handleScrollCommand();
    GM_setValue('closeOnScroll', config.closeOnScroll);
  }

  function handleScrollCommand() {
    if (config.closeOnScroll) {
      window.addEventListener('scroll', closePopupOnScroll, { once: true });
    } else {
      window.removeEventListener('scroll', closePopupOnScroll);
    }
  }

  function setWindowSize(dimension) {
    const size = prompt(`输入小窗口${dimension}(像素):`, config[dimension === 'width' ? 'windowWidth' : 'windowHeight']);
    if (size !== null) {
      config[dimension === 'width' ? 'windowWidth' : 'windowHeight'] = parseInt(size, 10);
      GM_setValue(dimension === 'width' ? 'windowWidth' : 'windowHeight', config[dimension === 'width' ? 'windowWidth' : 'windowHeight']);
      if (state.popupWindow && !state.popupWindow.closed) {
        state.popupWindow.resizeTo(config.windowWidth, config.windowHeight);
      }
    }
  }

  function setModifierKey() {
    const key = prompt('输入修饰键(Shift、Ctrl、Alt 等):', config.modifierKey);
    if (key !== null) {
      config.modifierKey = key;
      GM_setValue('modifierKey', config.modifierKey);
    }
  }

  function updateMenuCommands() {
    menuCommands.forEach((command) => {
      const menuCommand = registerMenuCommand(command.label, command.action);
      GM_info[`menuCommand${toTitleCase(command.label)}`] = menuCommand;
    });
  }

  function toTitleCase(str) {
    return str.replace(/\w\S*/g, (txt) => { return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase(); });
  }

  updateMenuCommands();

  document.body.addEventListener('dragstart', async (event) => {
    const linkElement = event.target.tagName === 'A' ? event.target : event.target.closest('a');
    const isModifierPressed = event[`${config.modifierKey.toLowerCase()}Key`]; // 检查修饰键是否按下
    if (linkElement && isModifierPressed) {
      const link = linkElement.href;
      state.isDragging = true;
      state.linkToPreload = link;
      await preloadLink(state.linkToPreload, { importance: 'high' });
      if (config.closeOnScroll) {
        window.addEventListener('scroll', closePopupOnScroll, { once: true });
      }
    }
  });

  document.body.addEventListener('dragend', () => {
    if (state.isDragging && state.linkToPreload) {
      state.isDragging = false;
      openPopupWindow(state.linkToPreload);
      state.linkToPreload = null;
    }
  });

  document.body.addEventListener('wheel', () => {
    if (config.closeOnScroll) {
      closePopupWindow();
    }
  });

  document.body.addEventListener('click', (event) => {
    if (event.target === state.acrylicOverlay) {
      removeAcrylicOverlay();
    }
  });

})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址