jquery.lazyload.js 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. (function($, window, document, undefined) {
  2. var $window = $(window);
  3. $.fn.lazyload = function(options) {
  4. var elements = this;
  5. var $container;
  6. var settings = {
  7. threshold : 0,
  8. failure_limit : 0,
  9. event : "scroll",
  10. effect : "show",
  11. container : window,
  12. data_attribute : "original",
  13. skip_invisible : true,
  14. appear : null,
  15. load : null,
  16. placeholder : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC"
  17. };
  18. function update() {
  19. var counter = 0;
  20. elements.each(function() {
  21. var $this = $(this);
  22. if (settings.skip_invisible && !$this.is(":visible")) {
  23. return;
  24. }
  25. if ($.abovethetop(this, settings) ||
  26. $.leftofbegin(this, settings)) {
  27. /* Nothing. */
  28. } else if (!$.belowthefold(this, settings) &&
  29. !$.rightoffold(this, settings)) {
  30. $this.trigger("appear");
  31. /* if we found an image we'll load, reset the counter */
  32. counter = 0;
  33. } else {
  34. if (++counter > settings.failure_limit) {
  35. return false;
  36. }
  37. }
  38. });
  39. }
  40. if(options) {
  41. /* Maintain BC for a couple of versions. */
  42. if (undefined !== options.failurelimit) {
  43. options.failure_limit = options.failurelimit;
  44. delete options.failurelimit;
  45. }
  46. if (undefined !== options.effectspeed) {
  47. options.effect_speed = options.effectspeed;
  48. delete options.effectspeed;
  49. }
  50. $.extend(settings, options);
  51. }
  52. /* Cache container as jQuery as object. */
  53. $container = (settings.container === undefined ||
  54. settings.container === window) ? $window : $(settings.container);
  55. /* Fire one scroll event per scroll. Not one scroll event per image. */
  56. if (0 === settings.event.indexOf("scroll")) {
  57. $container.bind(settings.event, function() {
  58. return update();
  59. });
  60. }
  61. this.each(function() {
  62. var self = this;
  63. var $self = $(self);
  64. self.loaded = false;
  65. /* If no src attribute given use data:uri. */
  66. if ($self.attr("src") === undefined || $self.attr("src") === false) {
  67. if ($self.is("img")) {
  68. $self.attr("src", settings.placeholder);
  69. }
  70. }
  71. /* When appear is triggered load original image. */
  72. $self.one("appear", function() {
  73. if (!this.loaded) {
  74. if (settings.appear) {
  75. var elements_left = elements.length;
  76. settings.appear.call(self, elements_left, settings);
  77. }
  78. $("<img />")
  79. .bind("load", function() {
  80. var original = $self.attr("data-" + settings.data_attribute);
  81. $self.hide();
  82. if ($self.is("img")) {
  83. $self.attr("src", original);
  84. } else {
  85. $self.css("background-image", "url('" + original + "')");
  86. }
  87. $self[settings.effect](settings.effect_speed);
  88. self.loaded = true;
  89. /* Remove image from array so it is not looped next time. */
  90. var temp = $.grep(elements, function(element) {
  91. return !element.loaded;
  92. });
  93. elements = $(temp);
  94. if (settings.load) {
  95. var elements_left = elements.length;
  96. settings.load.call(self, elements_left, settings);
  97. }
  98. })
  99. .attr("src", $self.attr("data-" + settings.data_attribute));
  100. }
  101. });
  102. /* When wanted event is triggered load original image */
  103. /* by triggering appear. */
  104. if (0 !== settings.event.indexOf("scroll")) {
  105. $self.bind(settings.event, function() {
  106. if (!self.loaded) {
  107. $self.trigger("appear");
  108. }
  109. });
  110. }
  111. });
  112. /* Check if something appears when window is resized. */
  113. $window.bind("resize", function() {
  114. update();
  115. });
  116. /* With IOS5 force loading images when navigating with back button. */
  117. /* Non optimal workaround. */
  118. if ((/(?:iphone|ipod|ipad).*os 5/gi).test(navigator.appVersion)) {
  119. $window.bind("pageshow", function(event) {
  120. if (event.originalEvent && event.originalEvent.persisted) {
  121. elements.each(function() {
  122. $(this).trigger("appear");
  123. });
  124. }
  125. });
  126. }
  127. /* Force initial check if images should appear. */
  128. $(document).ready(function() {
  129. update();
  130. });
  131. return this;
  132. };
  133. /* Convenience methods in jQuery namespace. */
  134. /* Use as $.belowthefold(element, {threshold : 100, container : window}) */
  135. $.belowthefold = function(element, settings) {
  136. var fold;
  137. if (settings.container === undefined || settings.container === window) {
  138. fold = (window.innerHeight ? window.innerHeight : $window.height()) + $window.scrollTop();
  139. } else {
  140. fold = $(settings.container).offset().top + $(settings.container).height();
  141. }
  142. return fold <= $(element).offset().top - settings.threshold;
  143. };
  144. $.rightoffold = function(element, settings) {
  145. var fold;
  146. if (settings.container === undefined || settings.container === window) {
  147. fold = $window.width() + $window.scrollLeft();
  148. } else {
  149. fold = $(settings.container).offset().left + $(settings.container).width();
  150. }
  151. return fold <= $(element).offset().left - settings.threshold;
  152. };
  153. $.abovethetop = function(element, settings) {
  154. var fold;
  155. if (settings.container === undefined || settings.container === window) {
  156. fold = $window.scrollTop();
  157. } else {
  158. fold = $(settings.container).offset().top;
  159. }
  160. return fold >= $(element).offset().top + settings.threshold + $(element).height();
  161. };
  162. $.leftofbegin = function(element, settings) {
  163. var fold;
  164. if (settings.container === undefined || settings.container === window) {
  165. fold = $window.scrollLeft();
  166. } else {
  167. fold = $(settings.container).offset().left;
  168. }
  169. return fold >= $(element).offset().left + settings.threshold + $(element).width();
  170. };
  171. $.inviewport = function(element, settings) {
  172. return !$.rightoffold(element, settings) && !$.leftofbegin(element, settings) &&
  173. !$.belowthefold(element, settings) && !$.abovethetop(element, settings);
  174. };
  175. /* Custom selectors for your convenience. */
  176. /* Use as $("img:below-the-fold").something() or */
  177. /* $("img").filter(":below-the-fold").something() which is faster */
  178. $.extend($.expr[":"], {
  179. "below-the-fold" : function(a) { return $.belowthefold(a, {threshold : 0}); },
  180. "above-the-top" : function(a) { return !$.belowthefold(a, {threshold : 0}); },
  181. "right-of-screen": function(a) { return $.rightoffold(a, {threshold : 0}); },
  182. "left-of-screen" : function(a) { return !$.rightoffold(a, {threshold : 0}); },
  183. "in-viewport" : function(a) { return $.inviewport(a, {threshold : 0}); },
  184. /* Maintain BC for couple of versions. */
  185. "above-the-fold" : function(a) { return !$.belowthefold(a, {threshold : 0}); },
  186. "right-of-fold" : function(a) { return $.rightoffold(a, {threshold : 0}); },
  187. "left-of-fold" : function(a) { return !$.rightoffold(a, {threshold : 0}); }
  188. });
  189. })(jQuery, window, document);