AutoScroll

全平台自动滚动

  1. // ==UserScript==
  2. // @name AutoScroll
  3. // @author Yiero
  4. // @description 全平台自动滚动
  5. // @version 1.0.0
  6. // @namespace https://github.com/AliubYiero/TamperMonkeyScripts
  7. // @match https://*/*
  8. // @icon https://*/favicon.ico
  9. // @license GPL
  10. // @grant GM_addStyle
  11. // @grant GM_registerMenuCommand
  12. // @grant GM_unregisterMenuCommand
  13. // @grant GM_setValue
  14. // @grant GM_getValue
  15. // @grant GM_deleteValue
  16. // @grant GM_listValues
  17. // @updateUrl https://raw.githubusercontent.com/AliubYiero/TamperMonkeyScripts/master/dist/AutoScroll.js
  18. // @downloadUrl https://raw.githubusercontent.com/AliubYiero/TamperMonkeyScripts/master/dist/AutoScroll.js
  19. // ==/UserScript==
  20.  
  21. var __defProp = Object.defineProperty;
  22. var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
  23. var __publicField = (obj, key, value) => {
  24. __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
  25. return value;
  26. };
  27. const registerMenu = (title, callback) => {
  28. return GM_registerMenuCommand(title, function() {
  29. callback();
  30. });
  31. };
  32. const unregisterMenu = (menuId) => {
  33. GM_unregisterMenuCommand(menuId);
  34. };
  35. const createElement = (elementConfig) => {
  36. const { tagName, className, id, innerHTML, innerText } = elementConfig;
  37. const element = document.createElement(tagName);
  38. if (className && typeof className === "string") {
  39. element.classList.add(className);
  40. } else if (className && Array.isArray(className)) {
  41. element.classList.add(...className);
  42. }
  43. if (id) {
  44. element.id = id;
  45. }
  46. if (innerHTML) {
  47. element.innerHTML = innerHTML;
  48. }
  49. if (innerText) {
  50. element.innerText = innerText;
  51. }
  52. for (let elementConfigKey in elementConfig) {
  53. if (["tagName", "className", "id", "innerHTML", "innerText"].indexOf(elementConfigKey) !== -1) {
  54. continue;
  55. }
  56. element.setAttribute(elementConfigKey, elementConfig[elementConfigKey]);
  57. }
  58. return element;
  59. };
  60. const addElementToDocument = (element, cssString, fatherElement = document.body) => {
  61. fatherElement.append(element);
  62. GM_addStyle(cssString);
  63. };
  64. const tupleToObject = (keyArray, valueArray) => {
  65. return keyArray.reduce((obj, key, index) => {
  66. obj[key] = valueArray[index];
  67. return obj;
  68. }, {});
  69. };
  70. class GMStorage {
  71. constructor(key) {
  72. __publicField(this, "key");
  73. this.key = key;
  74. }
  75. /** 设置/更新键 */
  76. static set(key, value) {
  77. GM_setValue(key, value);
  78. }
  79. /** 获取值 */
  80. static get(key, defaultValue = null) {
  81. return GM_getValue(key, defaultValue);
  82. }
  83. /** 移除键 */
  84. static remove(key) {
  85. GM_deleteValue(key);
  86. }
  87. /** 设置/更新键 */
  88. set(value) {
  89. GM_setValue(this.key, value);
  90. }
  91. /** 批量设置/更新键 */
  92. setList(keyValueObject) {
  93. for (let key in keyValueObject) {
  94. const value = keyValueObject[key];
  95. GMStorage.set(key, value);
  96. }
  97. }
  98. /** 获取值 */
  99. get(defaultValue = null) {
  100. return GM_getValue(this.key, defaultValue);
  101. }
  102. /** 批量获取值 */
  103. getList(keys, defaultValue = null) {
  104. const values = [];
  105. keys.forEach((key) => {
  106. values.push(GMStorage.get(key, defaultValue));
  107. });
  108. return values;
  109. }
  110. /** 移除键 */
  111. remove() {
  112. GM_deleteValue(this.key);
  113. }
  114. /**
  115. * 返回所有键
  116. * */
  117. keys() {
  118. return GM_listValues();
  119. }
  120. /** 返回所有值 */
  121. values() {
  122. const values = [];
  123. const keys = this.keys();
  124. keys.forEach((key) => {
  125. values.push(GMStorage.get(key));
  126. });
  127. return values;
  128. }
  129. /** 返回所有键值对对象 */
  130. getAll() {
  131. const keys = this.keys();
  132. const values = this.values();
  133. return tupleToObject(keys, values);
  134. }
  135. /** 清除所有储存 */
  136. clear() {
  137. const keys = this.keys();
  138. keys.forEach((key) => {
  139. GMStorage.remove(key);
  140. });
  141. }
  142. }
  143. class Prompt {
  144. constructor(title, confirmCallback, mountedCallback = () => {
  145. }) {
  146. __publicField(this, "title");
  147. __publicField(this, "confirmCallback");
  148. __publicField(this, "mountedCallback");
  149. __publicField(this, "promptElement");
  150. this.title = title;
  151. this.confirmCallback = confirmCallback;
  152. this.mountedCallback = mountedCallback;
  153. this.createElement();
  154. }
  155. // 隐藏
  156. hide() {
  157. document.querySelector(".custom-prompt__container").classList.add("hide");
  158. }
  159. // 展示元素
  160. show() {
  161. document.querySelector(".custom-prompt__container").classList.remove("hide");
  162. }
  163. createElement() {
  164. this.promptElement = createElement({
  165. tagName: "section",
  166. className: ["custom-prompt__container", "hide"],
  167. innerHTML: `
  168. <header>
  169. <h3 class="custom-prompt__title">${this.title}</h3>
  170. </header>
  171. <main>
  172. <input class="custom-prompt__input" type="text">
  173. </main>
  174. <footer class="custom-prompt__confirm-btn">
  175. <button>确认</button>
  176. <button>取消</button>
  177. </footer>
  178. `
  179. });
  180. const cssString = `
  181. .custom-prompt__container{width:400px;height:125px;background:#f8f8f8;border-radius:15px;box-sizing:border-box;padding:20px;box-shadow:2px 2px #a6a6a6;display:flex;justify-content:center;flex-flow:column;position:fixed;top:10px;left:50%;transform:translateX(-50%);z-index:10002}h3.custom-prompt__title{margin:10px -0px}input.custom-prompt__input{width:360px;border:#a6a6a6 2px solid;border-radius:5px;box-sizing:border-box;padding:5px 10px}.custom-prompt__confirm-btn{margin-top:10px;align-self:flex-end}.custom-prompt__confirm-btn>button{padding:3px;border-radius:5px;border:2px #a6a6a6 solid}.custom-prompt__confirm-btn>button:hover{border:2px cornflowerblue solid;color:cornflowerblue}.custom-prompt__container.hide{display:none}
  182. `;
  183. const htmlElements = {
  184. confirmBtn: this.promptElement.querySelector(".custom-prompt__confirm-btn > button:first-of-type"),
  185. cancelBtn: this.promptElement.querySelector(".custom-prompt__confirm-btn > button:last-of-type"),
  186. userInputContainer: this.promptElement.querySelector(".custom-prompt__input")
  187. };
  188. this.mountedCallback(this.promptElement);
  189. htmlElements.confirmBtn.addEventListener("click", () => {
  190. this.confirmCallback(htmlElements.userInputContainer.value, this.promptElement);
  191. this.hide();
  192. });
  193. htmlElements.cancelBtn.addEventListener("click", this.hide);
  194. document.addEventListener("click", (e) => {
  195. if (this.promptElement && !this.promptElement.contains(e.target)) {
  196. this.hide();
  197. }
  198. });
  199. addElementToDocument(this.promptElement, cssString);
  200. }
  201. }
  202. class Config {
  203. constructor() {
  204. }
  205. // 读取是否滚动(滚动状态)
  206. get isScroll() {
  207. return this.isScrollStorage.get(false);
  208. }
  209. // 写入是否滚动(滚动状态)
  210. set isScroll(newScrollStatus) {
  211. this.isScrollStorage.set(newScrollStatus);
  212. }
  213. // 读取滚动速度(一次滚动多少像素)
  214. get scrollSpeed() {
  215. return this.scrollSpeedStorage.get(5);
  216. }
  217. // 写入滚动速度
  218. set scrollSpeed(newSpeed) {
  219. this.scrollSpeedStorage.set(newSpeed);
  220. }
  221. // 滚动储存
  222. get isScrollStorage() {
  223. return new GMStorage("isScroll");
  224. }
  225. // 注册(不可用)滚动速度储存
  226. get scrollSpeedStorage() {
  227. return new GMStorage("scrollSpeed");
  228. }
  229. }
  230. const config = new Config();
  231. class AutoScroll {
  232. constructor() {
  233. __publicField(this, "timer");
  234. }
  235. open() {
  236. this.timer = setInterval(() => {
  237. /* @__PURE__ */ (() => {
  238. })("滚动", config.scrollSpeed);
  239. scrollBy({
  240. top: config.scrollSpeed,
  241. behavior: "smooth"
  242. });
  243. }, 16);
  244. }
  245. close() {
  246. clearInterval(this.timer);
  247. }
  248. }
  249. const autoScroll = new AutoScroll();
  250. (async () => {
  251. const prompt = new Prompt("输入滚动速度 (数字越大滚动速度越快) ", (value) => {
  252. if (isNaN(+value)) {
  253. return;
  254. }
  255. config.scrollSpeed = +value;
  256. }, (element) => {
  257. element.value = String(config.scrollSpeed);
  258. });
  259. registerMenu("定义滚动速度", () => {
  260. prompt.show();
  261. });
  262. config.isScroll = false;
  263. openMenu();
  264. function openMenu() {
  265. const openMenuId = registerMenu("[自动滚动] 开启", () => {
  266. autoScroll.open();
  267. unregisterMenu(openMenuId);
  268. const closeMenuId = registerMenu("[自动滚动] 关闭", () => {
  269. autoScroll.close();
  270. unregisterMenu(closeMenuId);
  271. openMenu();
  272. });
  273. });
  274. }
  275. })();

QingJ © 2025

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