QuickSearch

按 `'/'` 键快速聚焦并滚动到搜索输入框处。

  1. // ==UserScript==
  2. // @name QuickSearch
  3. // @name:zh-CN QuickSearch
  4. // @namespace https://github.com/zitup
  5. // @version 1.0.3
  6. // @description Use '/' to quickly focus on the search input
  7. // @description:zh-cn 按 `'/'` 键快速聚焦并滚动到搜索输入框处。
  8. // @author zitup
  9. // @homepage https://github.com/zitup/quick-search
  10. // @include *
  11. // @exclude https://www.google.com/*
  12. // @exclude https://www.google.com.hk/*
  13. // @exclude https://github.com/*
  14. // @exclude https://developer.mozilla.org/*
  15. // @icon https://www.google.com/s2/favicons?domain=w3.org
  16. // @grant none
  17. // @license MIT
  18. // ==/UserScript==
  19.  
  20. (function() {
  21. 'use strict';
  22.  
  23. // 监听键盘输入 '/' 搜索
  24. document.addEventListener('keydown', (e) => {
  25. if (
  26. e.key === '/' &&
  27. !e.metaKey &&
  28. !e.ctrlKey &&
  29. !["TEXTAREA", "INPUT"].includes(e.target.tagName)
  30. ) {
  31. main()
  32. }
  33. })
  34.  
  35. function main() {
  36. // 选择第一个 type 为 search 或存在 autofocus 且在页面显示的
  37. const autofocusOrSearch = document.querySelector('input[autofocus],input[type=search]')
  38. if (autofocusOrSearch && isVisible(autofocusOrSearch)) {
  39. focusAndScrollIntoView(autofocusOrSearch)
  40. return
  41. }
  42.  
  43. // 选择第一个 id/class 中包含[search]关键词且在页面显示的
  44. const idOrClassContainSearch = document.querySelectorAll('input[id*=search],input[class*=search]')
  45. if (idOrClassContainSearch.length) {
  46. const element = findInNodeList(idOrClassContainSearch)
  47. if (element) {
  48. focusAndScrollIntoView(element)
  49. return
  50. }
  51. }
  52.  
  53. // 选择第一个 placeholder 中包含[search/搜索]关键词且在页面显示的
  54. const placeholderContainSearch = document.querySelectorAll('input[placeholder*=search],input[placeholder*=搜索]')
  55. if (placeholderContainSearch.length) {
  56. const element = findInNodeList(placeholderContainSearch)
  57. if (element) {
  58. focusAndScrollIntoView(element)
  59. return
  60. }
  61. }
  62.  
  63. // 选择第一个在页面显示的
  64. const textInputTypes = ['hidden', 'button', 'checkbox', 'color', 'file', 'image', 'radio', 'range', 'reset', 'submit']
  65. const selector = textInputTypes.map(t => `[type=${t}]`).join(',')
  66. const firstInput = document.querySelector(`input:not(${selector})`)
  67. if (firstInput && isVisible(firstInput)) {
  68. focusAndScrollIntoView(firstInput)
  69. return
  70. }
  71. }
  72.  
  73. // 判断 NodeList 中是否有可用的
  74. function findInNodeList(list) {
  75. return [].find.call(list, (item) => isVisible(item))
  76. }
  77.  
  78. // 判断元素是否可见
  79. function isVisible(element) {
  80. const style = getComputedStyle(element)
  81. return (
  82. !!element.getClientRects().length &&
  83. style.visibility !== 'hidden' &&
  84. style.width !== 0 &&
  85. style.height !== 0 &&
  86. style.opacity !== 0
  87. )
  88. }
  89.  
  90. // 聚焦元素并滚动到视野
  91. function focusAndScrollIntoView(element) {
  92. event.preventDefault();
  93. const pos = element.value.length;
  94. element.setSelectionRange(pos, pos)
  95. element.focus()
  96. window.scrollTo({top: element.getBoundingClientRect().top + window.pageYOffset - 100, behavior: 'smooth'});
  97. }
  98. })();

QingJ © 2025

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