我帮你加上空格嗷~

在英文和其他文字之间,添加一个空格,让排版变得更舒适,也更利于阅读,

  1. // ==UserScript==
  2. // @name 我帮你加上空格嗷~
  3. // @namespace Maybe you forgot a space.
  4. // @match *://*/*
  5. // @grant none
  6. // @author 稻米鼠
  7. // @version 0.0.5
  8. // @author -
  9. // @description 在英文和其他文字之间,添加一个空格,让排版变得更舒适,也更利于阅读,
  10. // ==/UserScript==
  11.  
  12. window.addEventListener('load', async function(){
  13. /**
  14. * observer 配置
  15. * @property { boolean } childList - 观察目标子节点的变化,比如添加或者删除目标子节点,不包括修改子节点以及子节点后代的变化
  16. * @property { boolean } subtree - 目标以及目标的后代改变都会观察
  17. * @property { boolean } attributes - 观察目标属性的改变
  18. * @property { boolean } characterData - 观察目标数据的改变
  19. * @property { boolean } attributeOldValue - 默认为 true,表示需要记录改变前的目标属性值,设置了 attributeOldValue 可以省略 attributes 设置
  20. * @property { boolean } characterDataOldValue - 默认为 true,表示需要记录改变前的目标数据值,设置了 characterDataOldValue 可以省略 characterData 设置
  21. * @property { array } attributeFilter - 如果不是所有的属性改变都需要被观察,并且 attributes 设置为 true 或者被忽略,那么设置一个需要观察的属性本地名称(不需要命名空间)的列表
  22. */
  23. const config = {
  24. attributeOldValue: false,
  25. characterData: true,
  26. childList: true,
  27. subtree: true,
  28. };
  29. /**
  30. * 遍历元素的全部祖先元素,判断是否应该对此元素进行进一步处理
  31. * @param {*} el 要测试段元素
  32. */
  33. const nodeTester = el=>{
  34. if(/^body$/i.test(el.tagName)){
  35. return true
  36. }else if(
  37. /^(style|script|pre|code)$/i.test(el.tagName)
  38. || /^true$/i.test(el.contentEditable)
  39. ){
  40. return false
  41. }else{
  42. return nodeTester(el.parentNode)
  43. }
  44. }
  45. /**
  46. * 递归处理元素和子元素
  47. *
  48. * @param { object } el 页面元素
  49. * @returns
  50. */
  51. const addSpace = async el=>{
  52. // 如果 这是一个文本节点,则对内容进行替换
  53. // [英文 和 标点]与其他内容之间,加上空格
  54. if( el.nodeType === Node.TEXT_NODE ){
  55. el.textContent = el.textContent
  56. .replace(/([^\s\w\p{P}])([\w\p{P}]+)/gu, (match, p1, p2) =>
  57. /[a-zA-Z0-9]/.test(p2) ? p1 + ' ' + p2 : match
  58. )
  59. .replace(/([\w\p{P}]+)([^\s\w\p{P}])/gu, (match, p1, p2) =>
  60. /[a-zA-Z0-9]/.test(p1) ? p1 + ' ' + p2 : match
  61. );
  62. }else if(
  63. el.nodeType === Node.ELEMENT_NODE
  64. && nodeTester(el)
  65. ){
  66. // 如果这是一个元素节点,并且不是特殊元素,则对它的子元素进行遍历
  67. for await (e of el.childNodes){
  68. await addSpace(e)
  69. }
  70. }
  71. return Promise.resolve()
  72. }
  73. // 页面加载完成后处理整个页面
  74. await addSpace(document.body)
  75. // 声明用以监控页面的 observer 对象
  76. let observer
  77. /**
  78. * 当页面发生变化时,处理记录元素变化的数组
  79. *
  80. * @param { array } record MutationRecord
  81. * @returns
  82. */
  83. const pageChangeWatcher = async record =>{
  84. // 先停止对页面变化的监控,避免陷入死循环
  85. observer.disconnect()
  86. // 发生变化的元素合集
  87. const els = record
  88. // 改变的类型为 characterData,并且不是 body 元素的话
  89. .filter(
  90. (e) =>
  91. /^characterData$/i.test(e.type) && !/^body$/i.test(e.target.tagName)
  92. )
  93. .map((e) => e.target) // 把发生改变的元素放入合集
  94. // 改变的类型为 childList,则把新增的元素放入合集
  95. record.filter( e=>/^childList$/i.test(e.type)).forEach(e=>{
  96. e.addedNodes.forEach(node=>els.push(node))
  97. })
  98. // 遍历合集中所有元素
  99. for await (e of els){
  100. if(nodeTester(e)) await addSpace(e)
  101. }
  102. // 页面处理完成之后重新监控页面变化
  103. if(observer) observer.observe(document.body, config);
  104. }
  105. // 监控页面变化
  106. observer = new MutationObserver(pageChangeWatcher);
  107. observer.observe(document.body, config);
  108. })

QingJ © 2025

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