main.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. /**
  2. * Utils
  3. */
  4. // Load and run script via AJAX
  5. //
  6. const loadScript = (source, beforeEl, async = true, defer = true) => {
  7. return new Promise((resolve, reject) => {
  8. let script = document.createElement('script');
  9. const prior = beforeEl || document.getElementsByTagName('script')[0];
  10. script.async = async;
  11. script.defer = defer;
  12. function onloadHander(_, isAbort) {
  13. if (isAbort || !script.readyState || /loaded|complete/.test(script.readyState)) {
  14. script.onload = null;
  15. script.onreadystatechange = null;
  16. script = undefined;
  17. if (isAbort) {
  18. reject();
  19. } else {
  20. resolve();
  21. }
  22. }
  23. }
  24. script.onload = onloadHander;
  25. script.onreadystatechange = onloadHander;
  26. script.src = source;
  27. prior.parentNode.insertBefore(script, prior);
  28. });
  29. }
  30. // Throttle
  31. //
  32. const throttle = (callback, limit) => {
  33. let timeoutHandler = null;
  34. return () => {
  35. if (timeoutHandler == null) {
  36. timeoutHandler = setTimeout(() => {
  37. callback();
  38. timeoutHandler = null;
  39. }, limit);
  40. }
  41. };
  42. };
  43. // addEventListener Helper
  44. //
  45. const listen = (ele, e, callback) => {
  46. if (document.querySelector(ele) !== null) {
  47. document.querySelector(ele).addEventListener(e, callback);
  48. }
  49. }
  50. /**
  51. * Functions
  52. */
  53. // Auto Hide Header
  54. //
  55. let header = document.getElementById('site-header');
  56. let lastScrollPosition = window.pageYOffset;
  57. const autoHideHeader = () => {
  58. let currentScrollPosition = window.pageYOffset;
  59. if (currentScrollPosition > lastScrollPosition) {
  60. header.classList.remove('slideInUp');
  61. header.classList.add('slideOutDown');
  62. } else {
  63. header.classList.remove('slideOutDown');
  64. header.classList.add('slideInUp');
  65. }
  66. lastScrollPosition = currentScrollPosition;
  67. }
  68. // Mobile Menu Toggle
  69. //
  70. let mobileMenuVisible = false;
  71. const toggleMobileMenu = () => {
  72. let mobileMenu = document.getElementById('mobile-menu');
  73. if (mobileMenuVisible == false) {
  74. mobileMenu.style.animationName = 'bounceInRight';
  75. mobileMenu.style.webkitAnimationName = 'bounceInRight';
  76. mobileMenu.style.display = 'block';
  77. mobileMenuVisible = true;
  78. } else {
  79. mobileMenu.style.animationName = 'bounceOutRight';
  80. mobileMenu.style.webkitAnimationName = 'bounceOutRight'
  81. mobileMenuVisible = false;
  82. }
  83. }
  84. // Featured Image Toggle
  85. //
  86. const showImg = () => {
  87. document.querySelector('.bg-img').classList.add('show-bg-img');
  88. }
  89. const hideImg = () => {
  90. document.querySelector('.bg-img').classList.remove('show-bg-img');
  91. }
  92. // ToC Toggle
  93. //
  94. const toggleToc = () => {
  95. document.getElementById('toc').classList.toggle('show-toc');
  96. }
  97. //Load Comments
  98. //
  99. let commentsLoaded = false;
  100. let comments = document.getElementById('comments');
  101. let commentsLoader = document.getElementById('comments-loader');
  102. const avJsUrl = '//cdn.jsdelivr.net/npm/leancloud-storage@3.11.1/dist/av-min.js';
  103. const valineJsUrl = 'https://cdn.jsdelivr.net/npm/valine@1.3.4/dist/Valine.min.js';
  104. const loadComments = () => {
  105. loadScript(avJsUrl).then(() => {
  106. loadScript(valineJsUrl).then(() => {
  107. new Valine({
  108. el: '#comments',
  109. appId: 'QfBLso0johYg7AXtV9ODU6FC-gzGzoHsz',
  110. appKey: 'J1tpEEsENa48aLVsPdvwMP14',
  111. placeholder: '说点什么吧'
  112. });
  113. commentsLoader.style.display = 'none';
  114. }, () => {
  115. console.log('Failed to Load Valine.min.js');
  116. });
  117. }, () => {
  118. console.log('Failed to Load av-min.js');
  119. });
  120. }
  121. if (header !== null) {
  122. listen('#menu-btn', "click", toggleMobileMenu);
  123. listen('#toc-btn', "click", toggleToc);
  124. listen('#img-btn', "click", showImg);
  125. listen('.bg-img', "click", hideImg);
  126. // Load comments if the window is not scrollable
  127. if ((comments !== null) && (comments.offsetTop < window.innerHeight)) {
  128. commentsLoader.style.display = 'block';
  129. loadComments();
  130. commentsLoaded = true;
  131. }
  132. window.addEventListener('scroll', throttle(() => {
  133. autoHideHeader();
  134. if (mobileMenuVisible == true) {
  135. toggleMobileMenu();
  136. }
  137. if ((comments !== null) && (commentsLoaded == false)) {
  138. if (window.pageYOffset + window.innerHeight > comments.offsetTop) {
  139. commentsLoader.style.display = 'block';
  140. loadComments();
  141. commentsLoaded = true;
  142. }
  143. }
  144. }, 250));
  145. }