Greasy Fork

页面下拉刷新 1.30

页面顶部下拉展示动画,包含刷新功能。改进自原代码作者:路灯下的豆子不结籽

// ==UserScript==
// @name    页面下拉刷新 1.30
// @namespace    https://example.com
// @version    1.30
// @description 页面顶部下拉展示动画,包含刷新功能。改进自原代码作者:路灯下的豆子不结籽
// @match    *://*/*
// @exclude https://greasyfork.org/*
// @grant    none
// @license MIT
// ==/UserScript==
(function () {
    'use strict';
    // 设置下拉的比例,这里设为 10%
    const pullDownRatio = 0.1; 
    // 用于记录触摸开始时手指在 Y 轴上的坐标
    let startY = 0; 
    // 标记是否处于触摸拖动状态,初始为 false
    let isDragging = false; 
    // 设置下挪和回弹动画的持续时间,单位为秒,固定为 0.3 秒
    const animationDuration = 0.3; 
    // 设置动画的缓动函数,这里使用 'ease' 使动画更自然平滑
    const easeFunction = 'ease'; 
    // 用于记录当前下拉的距离
    let currentDistance = 0;

    // 获取页面的 body 元素,后续用于操作页面的位移来实现动画效果
    const body = document.querySelector('body'); 

    // 计算下拉的阈值(基于页面高度的比例)
    const threshold = window.innerHeight * pullDownRatio; 

    // 开始下拉动画的函数
    function startPullDownAnimation() {
        // 明确设置 transform 的初始值为 translateY(0),确保动画起始状态正确
        body.style.transform = 'translateY(0)';
        // 设置页面 body 的过渡动画属性,包括持续时间和缓动函数
        body.style.transition = `transform ${animationDuration}s ${easeFunction}`; 
        // 将页面 body 向下平移计算出的阈值距离,实现下拉动画效果
        body.style.transform = `translateY(${threshold}px)`; 
    }

    // 开始回弹动画的函数
    function startReboundAnimation() {
        // 明确设置 transform 的目标值为 translateY(0),确保动画结束状态正确
        body.style.transform = `translateY(${threshold}px)`;
        // 设置页面 body 的过渡动画属性,包括持续时间和缓动函数
        body.style.transition = `transform ${animationDuration}s ${easeFunction}`; 
        // 将页面 body 移回初始位置(Y 轴位移为 0),实现回弹动画效果
        body.style.transform = 'translateY(0)'; 
    }

    // 监听触摸开始事件
    document.addEventListener('touchstart', function (e) {
        // 判断页面是否在最顶部(滚动条 Y 轴位置为 0)
        if (window.scrollY === 0) {
            // 记录触摸开始时手指的 Y 坐标
            startY = e.touches[0].clientY; 
            // 标记进入触摸拖动状态
            isDragging = true; 
            // 开始拖动时取消过渡动画,使拖动操作更流畅
            body.style.transition = 'none'; 
            // 在控制台打印日志,显示触摸开始时记录的 Y 坐标
            console.log('touchstart: startY set to', startY); 
        }
    });

    // 监听触摸移动事件
    document.addEventListener('touchmove', function (e) {
        // 判断页面是否在最顶部(滚动条 Y 轴位置为 0)
        if (window.scrollY === 0 && isDragging) {
            // 获取当前触摸点的 Y 坐标
            const currentY = e.touches[0].clientY; 
            // 计算触摸点移动的距离
            currentDistance = currentY - startY; 

            // 如果移动距离大于 0,则直接控制页面的位移
            if (currentDistance > 0) {
                // 直接设置页面的位移
                body.style.transform = `translateY(${currentDistance}px)`;
            }

            // 当移动距离超过阈值时,直接触发回弹动画
            if (currentDistance > threshold) {
                startReboundAnimation();
                // 监听回弹动画结束事件,在动画结束后刷新页面
                body.addEventListener('transitionend', function onTransitionEnd() {
                    // 移除事件监听器,避免重复执行
                    body.removeEventListener('transitionend', onTransitionEnd);
                    // 执行页面刷新
                    console.log('Reloading page...');
                    location.reload();
                }, { once: true });
                // 重置拖动状态
                isDragging = false;
                // 重置当前下拉距离
                currentDistance = 0;
            }
        }
    });

    // 监听触摸结束事件
    document.addEventListener('touchend', function () {
        if (isDragging) {
            // 如果下拉距离超过阈值,触发回弹动画
            if (currentDistance > threshold) {
                startReboundAnimation();
                // 监听回弹动画结束事件,在动画结束后刷新页面
                body.addEventListener('transitionend', function onTransitionEnd() {
                    // 移除事件监听器,避免重复执行
                    body.removeEventListener('transitionend', onTransitionEnd);
                    // 执行页面刷新
                    console.log('Reloading page...');
                    location.reload();
                }, { once: true });
            } else {
                // 如果下拉距离未超过阈值,也执行回弹动画使页面回到初始位置
                startReboundAnimation();
            }
        }
        // 重置触摸开始时记录的 Y 坐标为 0
        startY = 0; 
        // 重置拖动状态
        isDragging = false;
        // 重置当前下拉距离
        currentDistance = 0;
    });

    // 监听触摸取消事件
    document.addEventListener('touchcancel', function () {
        if (isDragging) {
            // 执行回弹动画函数,使页面回到初始位置
            startReboundAnimation();
            // 监听回弹动画结束事件,在动画结束后刷新页面
            body.addEventListener('transitionend', function onTransitionEnd() {
                // 移除事件监听器,避免重复执行
                body.removeEventListener('transitionend', onTransitionEnd);
                // 执行页面刷新
                console.log('Reloading page...');
                location.reload();
            }, { once: true });
            // 重置触摸开始时记录的 Y 坐标为 0
            startY = 0; 
            // 重置拖动状态
            isDragging = false;
            // 重置当前下拉距离
            currentDistance = 0;
        }
    });
})();