知乎新版添加快捷键1024

为新版知乎添加快捷键

  1. // ==UserScript==
  2. // @name 知乎新版添加快捷键1024
  3. // @namespace zhangolve@gmail.com
  4. // @version 1.62
  5. // @description 为新版知乎添加快捷键
  6. // @author zhangolve
  7. // @match *://www.zhihu.com/*
  8. // @license MIT
  9. // ==/UserScript==
  10.  
  11. /*
  12. todo
  13. 单个问题页面,查看更多
  14. 按住I键,向下滚动 一点点
  15. 按住O键,向上滚动 一点点
  16. 收起评论
  17. 无须快捷键 空格键,向下滚动,但是是滚动一屏的距离,我希望的并不是滚动一屏啊!
  18. ENTER 当前项目打开看详情
  19. let,const 统一,lint
  20. 快捷键 说明
  21. ESC 从写评论状态切换为继续浏览其他答案
  22. j / k 上一个/下一个答案
  23. / 搜索
  24. c 显示评论
  25. v 赞同
  26. d 反对
  27. t 感谢
  28. w 阅读全文/收起
  29. g+n 查看通知/关闭通知
  30. g+p 查看个人首页
  31. g+s 去往设置页面
  32. 1/2/3 切换 推荐/关注/热榜
  33.  
  34. 可以做成chrome ex,?呼出快捷键说明栏
  35. */
  36.  
  37. (function () {
  38. let selectId = 0;
  39. let gFlag = false;
  40. let listItems;
  41. let mainTag; // 问题列表
  42. let answerClass;
  43. function setSelectId(value) {
  44. const newId = Number(value);
  45. if (Number.isNaN(newId)) return;
  46. selectId = newId;
  47. }
  48.  
  49. function parents(element) {
  50. const parent = element.parentNode;
  51. if (!parent || !listItems) {
  52. return NaN;
  53. }
  54. if (!parent.className || !parent.className.includes(answerClass)) {
  55. return parents(parent);
  56. }
  57. const id = Array.from(listItems).findIndex(elm => elm === parent);
  58. if (id === -1) {
  59. return NaN;
  60. }
  61. return id;
  62. }
  63. function setAnswersitems() {
  64. const items = document.querySelectorAll(`.${answerClass}`);
  65. listItems = items || [];
  66. }
  67. function mouseoverEvent(e) {
  68. mainTag.removeEventListener('mouseover', mouseoverEvent, true);
  69. const element = e.target;
  70. setSelectId(parents(element));
  71. setTimeout(() => {
  72. mainTag.addEventListener('mouseover', mouseoverEvent, true);
  73. }, 500);
  74. }
  75. function addEvent() {
  76. const observer = new MutationObserver(setAnswersitems);
  77. if (mainTag) {
  78. mainTag.removeEventListener('mouseover', mouseoverEvent, true);
  79. observer.disconnect();
  80. }
  81. const { href } = window.location;
  82. if (/^(http|https):\/\/www.zhihu.com(\/|\/follow)?$/.test(href)) { // 匹配主页
  83. mainTag = document.querySelector('.Topstory-content');
  84. answerClass = 'TopstoryItem';
  85. } else if (/^(http|https):\/\/www.zhihu.com\/question\/(\d)+\/answer\/*/.test(href)) { // 匹配单个问题页面
  86. mainTag = document.querySelector('.MoreAnswers');
  87. answerClass = 'List-item';
  88. } else if (/^(http|https):\/\/www.zhihu.com\/search\/*/.test(href)) { // 匹配搜索页面
  89. mainTag = document.querySelector('.SearchMain').parentElement;
  90. answerClass = 'List-item';
  91. }
  92. if (mainTag) {
  93. mainTag.addEventListener('mouseover', mouseoverEvent, true);
  94. observer.observe(mainTag, { attributes: true, childList: true, subtree: true });
  95. }
  96. }
  97. function findAnswers(count) {
  98. if (!listItems) {
  99. setAnswersitems();
  100. }
  101. return listItems[count];
  102. }
  103.  
  104. function answersCount() {
  105. if (!listItems) {
  106. setAnswersitems();
  107. }
  108. return listItems.length - 1;
  109. }
  110.  
  111. function getElementTop(element) {
  112. let actualTop = element.offsetTop;
  113. let current = element.offsetParent;
  114. while (current !== null) {
  115. actualTop += current.offsetTop;
  116. current = current.offsetParent;
  117. }
  118. return actualTop;
  119. }
  120. // 设置位置
  121. function setLocation(id) {
  122. const element = findAnswers(id);
  123. const elementTop = getElementTop(element);
  124. window.scrollTo(0, elementTop - 70);
  125. }
  126.  
  127. // 设置边框样式
  128. function setBorderStyle(currentId, previousId) {
  129. const currentElement = findAnswers(currentId);
  130. const previousItem = findAnswers(previousId);
  131. if (currentElement) {
  132. currentElement.style.border = '3px solid #3284ff';
  133. }
  134. if (previousItem) {
  135. previousItem.style.border = '';
  136. }
  137. }
  138.  
  139. // 到下一个项目
  140. function goNextItem() {
  141. const length = answersCount();
  142. if (selectId !== length) {
  143. setBorderStyle(selectId + 1, selectId);
  144. setSelectId(selectId + 1);
  145. }
  146. setLocation(selectId);
  147. }
  148.  
  149. // 到上一个项目
  150. function goPreviousItem() {
  151. if (selectId !== 0) {
  152. setBorderStyle(selectId - 1, selectId);
  153. setSelectId(selectId - 1);
  154. }
  155. setLocation(selectId);
  156. }
  157.  
  158. // 查看答案详情或者折叠详情
  159. function moreOrFold() {
  160. const answers = findAnswers(selectId);
  161. const contentMoreBtn = answers.querySelector('.ContentItem-more');
  162. const contentFoldBtn = answers.querySelector('.ContentItem-rightButton');
  163. const actionBtn = contentMoreBtn || contentFoldBtn;
  164. actionBtn.click();
  165. }
  166.  
  167. // 赞同
  168. function voteButtonUp() {
  169. const answers = findAnswers(selectId);
  170. const voteButton = answers.getElementsByClassName('VoteButton--up')[0];
  171. voteButton.click();
  172. }
  173.  
  174. // 反对
  175. function voteButtonDown() {
  176. const answers = findAnswers(selectId);
  177. const voteButton = answers.getElementsByClassName('VoteButton--down')[0];
  178. voteButton.click();
  179. }
  180.  
  181. // 搜索
  182. function search() {
  183. const searchInput = document.querySelector('.SearchBar-input input');
  184. searchInput.focus();
  185. }
  186.  
  187. // 打开评论
  188. function openComment() {
  189. const answers = findAnswers(selectId);
  190. const comment = answers.getElementsByClassName('ContentItem-actions')[0].childNodes[1];
  191. comment.click();
  192. }
  193.  
  194. // 感谢
  195. function thank() {
  196. const answers = findAnswers(selectId);
  197. const thinkButton = answers.getElementsByClassName('ContentItem-actions')[0].childNodes[4];
  198. thinkButton.click();
  199. }
  200.  
  201. // 切换tab
  202. function switchTab(index) {
  203. const tabs = document.querySelector('.Tabs').children;
  204. tabs[index].firstChild.click();
  205. selectId = 0;
  206. }
  207.  
  208. // gohome 返回首页
  209. function goHome() {
  210. window.location.href = '/';
  211. }
  212.  
  213. // 查看最新提醒通知
  214. function seeNotification() {
  215. // 如果有关闭通知的按钮,则点击之,使通知关闭。否则,创建之。
  216. let closeNoti = document.querySelector('#closeNoti');
  217. if (closeNoti) {
  218. closeNoti.click();
  219. setTimeout(() => {
  220. document.body.removeChild(closeNoti);
  221. }, 300);
  222. } else {
  223. closeNoti = document.createElement('button');
  224. closeNoti.setAttribute('id', 'closeNoti');
  225. closeNoti.style.position = 'fixed';
  226. closeNoti.style.top = '-1000px';
  227. document.body.appendChild(closeNoti);
  228. const PushNotifications = document.querySelector('.PushNotifications-icon');
  229. PushNotifications.click();
  230. }
  231. }
  232.  
  233. // 去往设置页面
  234. function goSetting() {
  235. window.location.href = '/settings/account';
  236. }
  237.  
  238. function escapeHandler() {
  239. if (document.hasFocus) {
  240. const focusTab = document.createElement('div');
  241. focusTab.setAttribute('tabindex', '0');
  242. focusTab.style.position = 'fixed';
  243. focusTab.style.top = '-1000px';
  244. document.body.appendChild(focusTab);
  245. focusTab.focus();
  246. }
  247. }
  248.  
  249. function hotkey(event) {
  250. if (event.altKey || event.ctrlKey) return;
  251.  
  252. const element = event.target;
  253. if (element.tagName === 'INPUT'
  254. || element.tagName === 'TEXTAREA'
  255. || element.className === 'public-DraftEditor-content') {
  256. return;
  257. }
  258.  
  259. if (event.key === 'g') {
  260. gFlag = true;
  261. } else if (gFlag) {
  262. switch (event.key) {
  263. case 'n':
  264. seeNotification();
  265. break;
  266. case 'h':
  267. goHome();
  268. break;
  269. case 's':
  270. goSetting();
  271. break;
  272. default:
  273. break;
  274. }
  275. } else {
  276. gFlag = false;
  277. }
  278.  
  279. if (event.keyCode === 27) {
  280. event.preventDefault();
  281. escapeHandler();
  282. return;
  283. }
  284. switch (event.key) {
  285. case '1':
  286. switchTab(0);
  287. break;
  288. case '2':
  289. switchTab(1);
  290. break;
  291. case '3':
  292. switchTab(2);
  293. break;
  294. case 'j':
  295. goNextItem();
  296. break;
  297. case 'k':
  298. goPreviousItem();
  299. break;
  300. case '/':
  301. search();
  302. break;
  303. case '?':
  304. break;
  305. case 'o':
  306. break;
  307. case 'c':
  308. openComment();
  309. break;
  310. case 'v':
  311. voteButtonUp();
  312. break;
  313. case 'd':
  314. voteButtonDown();
  315. break;
  316. case 't':
  317. thank();
  318. break;
  319. case 'w':
  320. moreOrFold();
  321. break;
  322. default:
  323. break;
  324. }
  325. }
  326. function init() {
  327. document.onkeydown = hotkey;
  328. addEvent();
  329. }
  330. // 初始化监听
  331. init();
  332. }());

QingJ © 2025

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