Greasy Fork

来自缓存

Greasy Fork is available in English.

手机可拖动折叠回到顶部|修复版

可拖动、默认折叠、记忆位置状态、修复坐标BUG、防误触

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         手机可拖动折叠回到顶部|修复版
// @namespace    http://tampermonkey.net/
// @version      2.0
// @description  可拖动、默认折叠、记忆位置状态、修复坐标BUG、防误触
// @match        *://*/*
// @grant        none
// @run-at       document-end
// ==/UserScript==
(function() {
    'use strict';

    const STORAGE_KEY = "back_top_float_data";
    // 防重复注入
    if (document.querySelector("#dragFloatWrap")) return;

    // ===== 修复1:增加JSON解析容错 try/catch =====
    let saveData;
    try {
        const local = localStorage.getItem(STORAGE_KEY);
        saveData = local ? JSON.parse(local) : null;
    } catch (e) {
        saveData = null;
    }

    // 默认配置
    const defaultData = {
        right: 16,
        bottom: 100,
        isFold: true
    };
    saveData = Object.assign({}, defaultData, saveData);

    // 外层容器
    const wrap = document.createElement("div");
    wrap.id = "dragFloatWrap";
    wrap.style.cssText = `
        position: fixed;
        right: ${saveData.right}px;
        bottom: ${saveData.bottom}px;
        z-index: 999999;
        user-select: none;
        touch-action: none;
        box-sizing: border-box;
    `;

    // 折叠开关按钮
    const foldBtn = document.createElement("div");
    foldBtn.style.cssText = `
        width: 40px;
        height: 40px;
        line-height: 40px;
        text-align: center;
        background: #1677ff;
        color: #fff;
        border-radius: 50%;
        font-size: 18px;
        box-shadow: 0 2px 8px rgba(0,0,0,0.2);
        box-sizing: border-box;
    `;

    // 功能区容器
    const contentBox = document.createElement("div");
    contentBox.style.cssText = `
        position: absolute;
        bottom: 50px;
        right: 0;
        display: none;
        box-sizing: border-box;
    `;

    // 回到顶部按钮
    const topBtn = document.createElement("div");
    topBtn.style.cssText = `
        width: 46px;
        height: 46px;
        line-height: 46px;
        text-align: center;
        background: #22c55e;
        color: #fff;
        border-radius: 50%;
        font-size: 20px;
        margin-bottom: 8px;
        box-shadow: 0 2px 8px rgba(0,0,0,0.2);
        box-sizing: border-box;
    `;
    topBtn.innerText = "↑";

    // 结构挂载
    contentBox.appendChild(topBtn);
    wrap.appendChild(contentBox);
    wrap.appendChild(foldBtn);
    document.body.appendChild(wrap);

    // 初始化折叠状态
    function initFoldState() {
        if (saveData.isFold) {
            contentBox.style.display = "none";
            foldBtn.innerText = "☰";
        } else {
            contentBox.style.display = "block";
            foldBtn.innerText = "✕";
        }
    }
    initFoldState();

    // 折叠切换 + 保存状态
    foldBtn.addEventListener("click", (e) => {
        e.stopPropagation();
        saveData.isFold = !saveData.isFold;
        initFoldState();
        localStorage.setItem(STORAGE_KEY, JSON.stringify(saveData));
    });

    // 回到顶部
    topBtn.addEventListener("click", (e) => {
        e.stopPropagation();
        window.scrollTo({
            top: 0,
            behavior: "smooth"
        });
    });

    // ===== 修复2:标准坐标 + 拖动阈值防误触 =====
    let isDrag = false;
    let startX = 0, startY = 0;
    let initRight = 0, initBottom = 0;
    const MOVE_THRESHOLD = 8; // 移动阈值,小于则判定为点击

    wrap.addEventListener("touchstart", (e) => {
        const rect = wrap.getBoundingClientRect();
        startX = e.touches[0].clientX;
        startY = e.touches[0].clientY;
        initRight = rect.right;
        initBottom = document.documentElement.clientHeight - rect.bottom;
        isDrag = false;
    });

    wrap.addEventListener("touchmove", (e) => {
        const dx = startX - e.touches[0].clientX;
        const dy = startY - e.touches[0].clientY;
        // 超过阈值判定为拖动
        if (Math.abs(dx) > MOVE_THRESHOLD || Math.abs(dy) > MOVE_THRESHOLD) {
            isDrag = true;
        }
        wrap.style.right = `${initRight + dx}px`;
        wrap.style.bottom = `${initBottom - dy}px`;
    });

    wrap.addEventListener("touchend", () => {
        // 拖动结束才保存位置
        if (isDrag) {
            const rect = wrap.getBoundingClientRect();
            saveData.right = document.documentElement.clientWidth - rect.right;
            saveData.bottom = document.documentElement.clientHeight - rect.bottom;
            localStorage.setItem(STORAGE_KEY, JSON.stringify(saveData));
        }
        isDrag = false;
    });
})();