自动滚动

给网页添加自动向上、向下滚动的按钮,对于看文章,看小说,看漫画等场景下使用极为舒适

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name        自动滚动
// @author      Kaiter-Plus
// @description 给网页添加自动向上、向下滚动的按钮,对于看文章,看小说,看漫画等场景下使用极为舒适
// @namespace   https://gitee.com/Kaiter-Plus/TampermonkeyScript/tree/master/AutoScroll
// @include     *://*
// @grant       none
// @version     1.01
// @license     BSD-3-Clause
// @noframes
// @grant       GM_addStyle
// @grant       GM_getValue
// @grant       GM_setValue
// @grant       GM_addElement
// ==/UserScript==
;(function () {
  'use strict'

  // 默认速度
  let defaultSpeed = 5
  // 定时器id
  let currentFrameId = 0
  // 记录上一次执行的时间
  let prevTIme = 0
  // 按下的位置
  const pressPosition = { top: 0, left: 0 }

  // 初始化速度
  const speed = GM_getValue('speed')
  speed ? (defaultSpeed = +speed) : GM_setValue('speed', defaultSpeed)

  // 创建一个滚动容器
  const scrollContainer = GM_addElement(document.body, 'div', {
    id: 'scroll-container',
    class: 'scroll-container'
  })
  scrollContainer.addEventListener('mousedown', press)

  // 创建自动向上的按钮
  const scrollUp = GM_addElement(scrollContainer, 'div', {
    id: 'scroll-up',
    class: 'scroll-up'
  })
  scrollUp.addEventListener('mouseover', () => {
    autoScroll(-1)
  })
  scrollUp.addEventListener('mouseout', stopScroll)

  // 创建速度显示
  const scrollSpeed = GM_addElement(scrollContainer, 'div', {
    id: 'scroll-speed',
    class: 'scroll-speed',
    textContent: speed
  })
  scrollSpeed.addEventListener('wheel', settingSpeed)

  // 创建自动向下的按钮
  const scrollDown = GM_addElement(scrollContainer, 'div', {
    id: 'scroll-down',
    class: 'scroll-down'
  })
  scrollDown.addEventListener('mouseover', () => {
    autoScroll(1)
  })
  scrollDown.addEventListener('mouseout', stopScroll)

  // 自动滚动
  function autoScroll(direction) {
    scroll(direction)
  }

  // 滚动
  function scroll(direction) {
    currentFrameId = window.requestAnimationFrame(time => {
      if (!prevTIme) prevTIme = time
      const elapsed = (time - prevTIme) / 1000
      // 每 50ms 执行一次
      window.scrollBy(0, defaultSpeed * 10 * direction * elapsed)
      prevTIme = time
      scroll(direction)
    })
  }

  // 停止滚动
  function stopScroll() {
    prevTIme = 0
    window.cancelAnimationFrame(currentFrameId)
  }

  // 设置滚动速度
  function settingSpeed(e) {
    e.preventDefault()
    if (e.deltaY < 0) defaultSpeed += 1
    else defaultSpeed -= 1
    scrollSpeed.textContent = defaultSpeed
    GM_setValue('speed', defaultSpeed)
  }

  // 按下事件
  function press(e) {
    // 设置只有在速度显示区域才能拖动
    if (e.target.id === 'scroll-speed') {
      // 记录位置
      pressPosition.top = e.clientY - e.currentTarget.offsetTop
      pressPosition.left = e.clientX - e.currentTarget.offsetLeft
      // 修改样式显示
      scrollSpeed.style.cursor = 'move'
      // 开始监听移动事件
      document.addEventListener('mousemove', move)
      document.addEventListener('mouseup', release)
    }
  }

  // 移动事件
  function move(e) {
    const top = e.clientY - pressPosition.top
    const left = e.clientX - pressPosition.left
    scrollContainer.style.right = `unset`
    scrollContainer.style.top = `${top}px`
    scrollContainer.style.left = `${left}px`
  }

  // 抬起事件
  function release(e) {
    // 修改样式显示
    scrollSpeed.style.cursor = 's-resize'
    // 清除事件
    document.removeEventListener('mousemove', move)
    document.removeEventListener('mouseup', release)
  }

  // 添加自定义样式
  GM_addStyle(`
    .scroll-container {
      position: fixed;
      top: 50%;
      right: 10px;
      z-index: 99999;
      text-align: center;
      transform: translateY(-50%);
      border-radius: 20px;
      overflow: hidden;
      background-color: rgba(204, 204, 204, 0.4);
      line-height: 40px;
      color: rgba(60, 60, 67, .92);
    }
    .scroll-up,
    .scroll-down {
      width: 40px;
      height: 40px;
      text-align: center;
    }
    .scroll-up::after,
    .scroll-down::after {
      content: '';
      display: inline-block;
      width: 16px;
      height: 16px;
      font-size: 16px;
      box-sizing: border-box;
      border-width: 2px;
      border-style: solid;
    }
    .scroll-up::after {
      transform: rotate(-45deg);
      border-color: rgba(60, 60, 67, .92) rgba(60, 60, 67, .92) transparent transparent;
      margin-top: 14.3425px;
    }
    .scroll-down::after {
      transform: rotate(-45deg);
      border-color: transparent transparent rgba(60, 60, 67, .92) rgba(60, 60, 67, .92);
      margin-top: 8.685px;
    }
    .scroll-up:hover,
    .scroll-down:hover {
      background-color: rgba(204, 204, 204, 0.8);
    }
    
    .scroll-speed {
      font-size: 18px;
      user-select: none;
      cursor: s-resize;
    }    
  `)
})()