jquery.scrollspy.js 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. (function (root, factory) {
  2. if (typeof define === 'function' && define.amd) {
  3. // AMD. Register as an anonymous module unless amdModuleId is set
  4. define([], function () {
  5. return (factory());
  6. });
  7. } else if (typeof exports === 'object') {
  8. // Node. Does not work with strict CommonJS, but
  9. // only CommonJS-like environments that support module.exports,
  10. // like Node.
  11. module.exports = factory();
  12. } else {
  13. factory();
  14. }
  15. }(this, function () {
  16. function ScrollSpy (wrapper, opt) {
  17. var doc = document;
  18. this.wrapper = wrapper || doc.querySelector(opt.wrapper);
  19. this.nav = this.wrapper.querySelectorAll(opt.nav);
  20. this.contents = [];
  21. this.win = window;
  22. this.body = doc.body;
  23. this.winH = this.win.innerHeight;
  24. this.className = opt.className;
  25. this.callback = opt.callback;
  26. this.init();
  27. }
  28. ScrollSpy.prototype.init = function () {
  29. this.contents = this.getContents();
  30. this.attachEvent();
  31. };
  32. ScrollSpy.prototype.getContents = function () {
  33. var targetList = [];
  34. for (var i = 0, max = this.nav.length; i < max; i++) {
  35. var href = this.nav[i].href;
  36. targetList.push(document.getElementById(href.split('#')[1]));
  37. }
  38. return targetList;
  39. };
  40. ScrollSpy.prototype.attachEvent = function () {
  41. this.win.addEventListener('load', (function () {
  42. this.spy(this.callback);
  43. }).bind(this));
  44. var scrollingTimer;
  45. this.win.addEventListener('scroll', (function () {
  46. if (scrollingTimer) {
  47. clearTimeout(scrollingTimer);
  48. }
  49. var _this = this;
  50. scrollingTimer = setTimeout(function () {
  51. _this.spy(_this.callback);
  52. }, 10);
  53. }).bind(this));
  54. var resizingTimer;
  55. this.win.addEventListener('resize', (function () {
  56. if (resizingTimer) {
  57. clearTimeout(resizingTimer);
  58. }
  59. var _this = this;
  60. resizingTimer = setTimeout(function () {
  61. _this.spy(_this.callback);
  62. }, 10);
  63. }).bind(this));
  64. };
  65. ScrollSpy.prototype.spy = function (cb) {
  66. var elems = this.getElemsViewState();
  67. this.markNav(elems);
  68. if (typeof cb === 'function') {
  69. cb(elems);
  70. }
  71. };
  72. ScrollSpy.prototype.getElemsViewState = function () {
  73. var elemsInView = [],
  74. elemsOutView = [],
  75. viewStatusList = [];
  76. for (var i = 0, max = this.contents.length; i < max; i++) {
  77. var currentContent = this.contents[i],
  78. isInView = this.isInView(currentContent);
  79. if (isInView) {
  80. elemsInView.push(currentContent);
  81. } else {
  82. elemsOutView.push(currentContent);
  83. }
  84. viewStatusList.push(isInView);
  85. }
  86. return {
  87. inView: elemsInView,
  88. outView: elemsOutView,
  89. viewStatusList: viewStatusList
  90. };
  91. };
  92. ScrollSpy.prototype.isInView = function (el) {
  93. var winH = this.winH,
  94. scrollTop = this.body.scrollTop,
  95. scrollBottom = scrollTop + winH,
  96. elTop = el.offsetTop,
  97. elBottom = elTop + el.offsetHeight;
  98. return (elTop < scrollBottom) && (elBottom > scrollTop);
  99. };
  100. ScrollSpy.prototype.markNav = function (elems) {
  101. var navItems = this.nav,
  102. isAlreadyMarked = false;
  103. for (var i = 0, max = navItems.length; i < max; i++) {
  104. if (elems.viewStatusList[i] && !isAlreadyMarked) {
  105. isAlreadyMarked = true;
  106. navItems[i].classList.add(this.className);
  107. } else {
  108. navItems[i].classList.remove(this.className);
  109. }
  110. }
  111. };
  112. (function ($) {
  113. $.fn.scrollSpy = function (options) {
  114. return this.each(function () {
  115. $(this).data('scrollspy', new ScrollSpy(this, options));
  116. });
  117. };
  118. })(jQuery);
  119. }));