滚动条-新

为网页添加滚动条。

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name        滚动条-新
// @namespace   https://greasyfork.org/zh-CN/users/954189
// @version     1.2
// @description 为网页添加滚动条。
// @author      chatgpt
// @run-at      document-end
// @license     MIT
// @match       *://*/*
// ==/UserScript==

(function() {
  'use strict';

  // 创建滚动条 DOM 元素
  const theScrollBar = document.createElement("div");

  // 设置滚动条的 ID 和文本
  theScrollBar.id = "theScrollBar";
  theScrollBar.innerHTML = "▲<br>▼";

  // 设置滚动条样式
  theScrollBar.setAttribute(
    "style",
    "font-size:1.5vw ;width:6vw ;line-height:5vw ;display: block;text-align:center ;background-color:rgba(255,255,255) ;opacity: 0 ;box-shadow:0px 1px 5px rgba(0,0,0,0.2) ;color:#000 ;position:fixed ;top: -14vw;right:-10vw ;z-index:9999999 ;transition: opacity 0.4s ease-in-out,right 0.4s; border-radius:1vw "
  );

  // 将滚动条元素添加到页面中
  document.body.appendChild(theScrollBar);

  // 存储网页高度和上次滚动位置
  let webHeight = null;
  let lastScrollTop = null;

  // 更新滚动条位置的函数
  function updateScrollBar() {
    // 获取当前的滚动位置
    const scrollTop = window.scrollY;

    // 如果滚动位置改变了,重新计算滚动条位置
    if (scrollTop !== lastScrollTop) {
      const scrollBarTop =
        (scrollTop / webHeight) * (window.innerHeight - theScrollBar.clientHeight);
      if (scrollBarTop < 0) {
        theScrollBar.style.top = "0";
      } else if (scrollBarTop + theScrollBar.clientHeight > window.innerHeight) {
        theScrollBar.style.top = `${window.innerHeight - theScrollBar.clientHeight}px`;
        webHeight = document.documentElement.scrollHeight - window.innerHeight;
      } else {
        theScrollBar.style.top = `${scrollBarTop}px`;
      }
      lastScrollTop = scrollTop;
    }

    // 使用 requestAnimationFrame 函数,优化渲染性能
    window.requestAnimationFrame(updateScrollBar);
  }

  // 添加 touchstart 事件监听器,当用户在手机上开始触摸屏幕时触发
  window.addEventListener("touchstart", function() {
    //如果网页高度过低,不需要添加滚动条
    if (document.documentElement.scrollHeight <= window.innerHeight * 2) {
      return;
    }

    // 获取网页高度,并开始更新滚动条位置
    webHeight = document.documentElement.scrollHeight - window.innerHeight;
    updateScrollBar();
  });

  // 定义一些与触摸事件相关的变量
  let startOffset = null;

  // 滚动条开始滚动时触发的函数
  function startScroll(event) {
    event.preventDefault();
    event.stopPropagation();
    startOffset = event.changedTouches[0].clientY - parseInt(theScrollBar.style.top);
  }

  // 滚动条正在滚动时触发的函数
  function scrolling(event) {
    event.preventDefault();
    event.stopPropagation();
    // 计算当前滚动条的位置和滑动距离,并更新滚动位置和滚动条位置
    const currentY = event.changedTouches[0].clientY;
    const scrollBarTop = currentY - startOffset;
    if (scrollBarTop < 0) {
      theScrollBar.style.top = "0px";
    } else if (scrollBarTop > window.innerHeight - theScrollBar.clientHeight) {
      theScrollBar.style.top = `${window.innerHeight - theScrollBar.clientHeight}px`;
      webHeight = document.documentElement.scrollHeight - window.innerHeight;
    } else {
      theScrollBar.style.top = `${scrollBarTop}px`;
    }
    const scrollTop =
      (scrollBarTop / (window.innerHeight - theScrollBar.clientHeight)) * webHeight;
    window.scrollTo(window.scrollX, scrollTop);
  }

  // 为滚动条添加触摸事件监听器
  theScrollBar.addEventListener("touchstart", startScroll, { passive: false });
  theScrollBar.addEventListener("touchmove", scrolling, { passive: false });

  // 停止滚动1秒后隐藏
  let timer;
  window.addEventListener("scroll", function() {
    clearTimeout(timer);
    theScrollBar.style.right = "2vw";
    theScrollBar.style.opacity = "0.8";
    timer = setTimeout(() => {
      theScrollBar.style.right = "-10vw";
      theScrollBar.style.opacity = "0";
    }, 1000);
  });

  // 定义触顶/底反弹动画的函数
  function bounceAnimation() {
    // 获取当前滚动条的位置
    const scrollTop = window.scrollY;

    // 获取滚动条的高度
    const scrollBarHeight = theScrollBar.clientHeight;

    // 获取滚动速度
    const scrollSpeed = Math.abs(scrollTop - lastScrollTop);

    // 设置滚动速度阈值
    const threshold = 7;

    // 如果滚动条触顶,且滚动速度超过阈值,执行反弹动画
    if (scrollTop === 0 && scrollSpeed > threshold) {
      theScrollBar.style.animation = "bounce-down 0.4s";
      setTimeout(() => {
        theScrollBar.style.animation = "";
      }, 500);
    }

    // 如果滚动条触底,且滚动速度超过阈值,执行反弹动画
    if (scrollTop + window.innerHeight >= document.documentElement.scrollHeight && scrollSpeed > threshold) {
      theScrollBar.style.animation = "bounce-up 0.4s";
      setTimeout(() => {
        theScrollBar.style.animation = "";
      }, 500);
    }
  }

  // 添加触顶/底反弹动画的事件监听器
  window.addEventListener("scroll", bounceAnimation);

  // CSS样式
  const styles = `
  @keyframes bounce-down {
    0% {
      transform: translateY(0);
    }
    30% {
      transform: translateY(10px);
    }
    100% {
      transform: translateY(0);
    } 
  }
  @keyframes bounce-up {
    0% {
      transform: translateY(0);
    }
     30% {
      transform: translateY(-10px);
    }
    100% {
      transform: translateY(0);
    }
  }
  `;

  // 创建样式元素并将样式添加到头部
  const styleElement = document.createElement("style");
  styleElement.innerHTML = styles;
  document.head.appendChild(styleElement);


})();