├── .gitignore ├── FUNDING.yml ├── README.md └── jquery-lazyloadanything.js /.gitignore: -------------------------------------------------------------------------------- 1 | bower_components/ 2 | node_modules/ 3 | .DS_Store 4 | -------------------------------------------------------------------------------- /FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | patreon: canebaycomputers -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | jquery-lazyloadanything 2 | ======================= 3 | 4 | Trigger events when elements come into view - binds events to the vertical and horizontal scroll listener. This plugin was designed to go beyond just lazy loading images. It basically triggers events whenever specified elements become visible in the view pane via scrolling in either direction. You can dynamically load any kind of content or do any type of jQuery or Javascript executing you wish. The triggering elements are determined by the jQuery selector and are accessible during event firing. Plugin can be applied to multiple selectors on the same page. 5 | 6 | Basic Image Loading Syntax 7 | ------------ 8 | This example is showing how the image source url is stored in the `data-src` attribute and loads into the `src` attribute when the user scrolls into view of the image. Of course, the selector will most likely be more specific. 9 | 10 | $('img').lazyloadanything({ 11 | 'onLoad': function(e, LLobj) { 12 | var $img = LLobj.$element; 13 | var src = $img.attr('data-src'); 14 | $img.attr('src', src); 15 | } 16 | }); 17 | 18 | Element with Class Loaded in Viewport 19 | ------------- 20 | This example shows how to turn the background of elements red when it is lazy loaded into the viewport. 21 | 22 | $('.red-bg-onload').lazyloadanything({ 23 | 'onLoad': function(e, LLobj) { 24 | LLobj.$element.css('background-color', 'red'); 25 | } 26 | }); 27 | 28 | Each [onLoad](#onload) call passes the [LLobj](#llobj) variable which is a Lazy Load object that contains 4 properties and two methods. 29 | 30 | LLobj 31 | ----- 32 | Lazy Load object 33 | 34 | ### LLobj.top 35 | The element's top Y position from top of the document body if [cache](#cache) is turned on. 36 | 37 | ### LLobj.bottom 38 | The element's bottom Y position from top of the document body if [cache](#cache) is turned on. 39 | 40 | ### LLobj.loaded 41 | Boolean flag signifying whether the [onLoad](#onload) event has already triggered for the corresponding element. This keeps the element from triggering again if scrolling over multiple times however this can be overridden with the plugin [settings](#settings). 42 | 43 | ### LLobj.$element 44 | The jQuery object derived from the element. 45 | 46 | ### LLobj.getTop() 47 | Returns the element's top Y position from top of the document body. 48 | 49 | ### LLobj.getBottom() 50 | Returns the element's bottom Y position from top of the document body. 51 | 52 | Settings 53 | -------- 54 | ### `auto` 55 | 56 | Default: `true` 57 | 58 | Boolean value that allows the element to trigger the [onLoad](#onload) event automatically when scrolled into view. If set to `false`, the `$.fn.lazyloadanywhere('load')` method can be called to force trigger all applicable, in view, elements to call the [onLoad](#onload) function. This will not force load any elements whose [LLobj](#llobj) object's loaded property is already set to true, to override this see [repeatLoad](#repeatload). 59 | 60 | ### `cache` 61 | 62 | Default: `false` 63 | 64 | If set to `true`, the [LLobj](#llobj) objects' top and bottom properties will be set on plugin initialization. This is helpful if you apply the plugin to a lot of elements. Setting it to `true` may speed up the script however those elements' position, size and visibility must not change. If they change you must call the `$.fn.lazyloadanywhere('destroy')` method and reinitialize the plugin. 65 | 66 | ### `timeout` 67 | 68 | Default: `1000` 69 | 70 | Timeout in seconds before any loading events trigger. Helpful when user is scrolling quickly through the page. 71 | 72 | ### `includeMargin` 73 | 74 | Default: `false` 75 | 76 | Boolean setting which specifies whether the elements' margin is considered as being part of the viewable element and will trigger the [onLoad](#onload) event. 77 | 78 | ### `repeatLoad` 79 | 80 | Default: `false` 81 | 82 | Boolean setting which allows the [onLoad](#onload) event to always trigger regardless of the [LLobj](#llobj) objects' [loaded](#llobjloaded) property. In other words, it will not just fire once but each time the element comes into view. 83 | 84 | ### `onLoadingStart` 85 | 86 | Default: `function(e, LLobjs, indexes) { return true }` 87 | 88 | Event that is triggered before any [LLobj](#llobj) objects are triggered. Returning boolean `false` will cancel any [LLobj](#llobj) objects from loading. 89 | 90 | Arguments: 91 | + `e` The window scroll event. 92 | + `LLobjs` Array of **All** of the [LLobj](#llobj) objects from the initial jQuery selector initialization. 93 | + `indexes` Array of indexes corresponding to the above `LLobjs` array that will be triggered. 94 | 95 | ### `onLoad` 96 | 97 | Default: `function(e, LLobj) { return true }` 98 | 99 | Event that is triggered when the element comes into view, ie. when the element appears in the browser view pane. Returning boolean `false` will cancel any of the following load events. 100 | 101 | Arguments: 102 | + `e` The window scroll event. 103 | + `LLobj` The triggering [LLobj](#llobj) object. 104 | 105 | ### `onLoadComplete` 106 | 107 | Default: `function(e, LLobjs, indexes) { return true }` 108 | 109 | Event that is triggered after [LLobj](#llobj) objects are triggered. 110 | 111 | Arguments: 112 | + `e` The window scroll event. 113 | + `LLobjs` Array of **All** of the [LLobj](#llobj) objects from the initial jQuery selector initialization. 114 | + `indexes` Array of indexes corresponding to the above `LLobjs` array that have triggered. 115 | 116 | Methods 117 | ------- 118 | ### `destroy` 119 | 120 | Usage: `$.fn.lazyloadanything('destroy')` 121 | 122 | Will remove **All** Lazy Load events including any multiple plugin initializations/selectors. If you add Lazy Load functionality to one jQuery selector and add some other functionality to another jQuery selector one method call to destroy will stop/unbind all scroll listening, ie. functionality. 123 | 124 | ### `load` 125 | 126 | Usage: `$.fn.lazyloadanything('load')` 127 | 128 | Will force load any applicable (in-view) elements. This is helpful to dynamically load content when page is first loaded since it takes scrolling to activate the events. This method works well with the [auto](#auto) setting set to `false`. 129 | 130 | Requirements and Compatability 131 | ------------ 132 | 133 | jQuery >= 1.8 134 | 135 | Seems to work in all modern browsers. 136 | 137 | I haven't taken the time to test multiple browser and jQuery versions but this is a simple plugin and I'm sure will work fine under many different environment arrangements. 138 | 139 | Let me know otherwise. 140 | 141 | Take care, God bless. 142 | -------------------------------------------------------------------------------- /jquery-lazyloadanything.js: -------------------------------------------------------------------------------- 1 | /*! 2 | jQuery LazyLoadAnything - 2013-03-04 3 | (c) 2013 Shawn Welch http://shrimpwagon.wordpress.com/jquery-lazyloadanything 4 | license: http://www.opensource.org/licenses/mit-license.php 5 | */ 6 | (function( $ ) { 7 | 8 | // Element to listen to scroll event 9 | var $listenTo; 10 | 11 | // Force load flag 12 | var force_load_flag = false; 13 | 14 | // Plugin methods 15 | var methods = { 16 | 17 | 'init': function(options) { 18 | 19 | var defaults = { 20 | 'auto': true, 21 | 'cache': false, 22 | 'timeout': 1000, 23 | 'includeMargin': false, 24 | 'viewportMargin': 0, 25 | 'repeatLoad': false, 26 | 'listenTo': window, 27 | 'onLoadingStart': function(e, llelements, indexes) { 28 | return true; 29 | }, 30 | 'onLoad': function(e, llelement) { 31 | return true; 32 | }, 33 | 'onLoadingComplete': function(e, llelements, indexes) { 34 | return true; 35 | } 36 | 37 | } 38 | 39 | var settings = $.extend({}, defaults, options); 40 | $listenTo = $(settings.listenTo); 41 | var timeout = 0; 42 | var llelements = []; 43 | var $selector = this; 44 | 45 | // Scroll listener 46 | $listenTo.bind('scroll.lla', function(e) { 47 | 48 | // Check for manually/auto load 49 | if(!force_load_flag && !settings.auto) return false; 50 | force_load_flag = false; 51 | 52 | // Clear timeout if scrolling continues 53 | clearTimeout(timeout); 54 | 55 | // Set the timeout for onLoad 56 | timeout = setTimeout(function() { 57 | 58 | /* 59 | x1, y1 o----------------------o x2, y1 60 | | | 61 | | | 62 | | | 63 | | | 64 | | | 65 | | | 66 | | | 67 | | | 68 | x1, y2 o----------------------o x2, y2 69 | */ 70 | 71 | var viewport_left = $listenTo.scrollLeft(); 72 | var viewport_top = $listenTo.scrollTop(); 73 | var viewport_width = $listenTo.innerWidth(); 74 | var viewport_height = $listenTo.innerHeight(); 75 | var viewport_x1 = viewport_left - settings.viewportMargin; 76 | var viewport_x2 = viewport_left + viewport_width + settings.viewportMargin; 77 | var viewport_y1 = viewport_top - settings.viewportMargin; 78 | var viewport_y2 = viewport_top + viewport_height + settings.viewportMargin; 79 | 80 | var load_elements = []; 81 | var i, llelem_top, llelem_bottom; 82 | 83 | // Cycle through llelements and check if they are within viewpane 84 | for(i = 0; i < llelements.length; i++) { 85 | 86 | // Get top and bottom of llelem 87 | var llelem_x1 = llelements[i].getLeft(); 88 | var llelem_x2 = llelements[i].getRight(); 89 | var llelem_y1 = llelements[i].getTop(); 90 | var llelem_y2 = llelements[i].getBottom(); 91 | 92 | if(llelements[i].$element.is(':visible')) 93 | { 94 | if((viewport_x1 < llelem_x2) && (viewport_x2 > llelem_x1) && (viewport_y1 < llelem_y2) && (viewport_y2 > llelem_y1)) { 95 | 96 | // Grab index of llelements that will be loaded 97 | if(settings.repeatLoad || !llelements[i].loaded) load_elements.push(i); 98 | 99 | } 100 | } 101 | } 102 | 103 | // Call onLoadingStart event 104 | if(settings.onLoadingStart.call(undefined, e, llelements, load_elements)) { 105 | 106 | // Cycle through array of indexes that will be loaded 107 | for(i = 0; i < load_elements.length; i++) { 108 | 109 | // Set loaded flag 110 | llelements[load_elements[i]].loaded = true; 111 | 112 | // Call the individual element onLoad 113 | if(settings.onLoad.call(undefined, e, llelements[load_elements[i]]) === false) break; 114 | 115 | } 116 | 117 | // Call onLoadingComplete event 118 | settings.onLoadingComplete.call(undefined, e, llelements, load_elements); 119 | 120 | } 121 | 122 | }, settings.timeout); 123 | 124 | }); 125 | 126 | // LazyLoadElement class 127 | function LazyLoadElement($element) { 128 | 129 | var self = this; 130 | 131 | this.loaded = false; 132 | this.$element = $element; 133 | this.top = undefined; 134 | this.bottom = undefined; 135 | this.left = undefined; 136 | this.right = undefined; 137 | 138 | this.getTop = function() { 139 | if(self.top) return self.top; 140 | 141 | return self.$element.position().top; 142 | } 143 | 144 | this.getBottom = function() { 145 | if(self.bottom) return self.bottom; 146 | 147 | var top = (self.top) ? self.top : this.getTop(); 148 | return top + self.$element.outerHeight(settings.includeMargin); 149 | } 150 | 151 | this.getLeft = function() { 152 | if(self.left) return self.left; 153 | 154 | return self.$element.position().left; 155 | } 156 | 157 | this.getRight = function() { 158 | if(self.right) return self.right; 159 | 160 | var left = (self.left) ? self.left : this.getLeft(); 161 | return left + self.$element.outerWidth(settings.includeMargin); 162 | } 163 | 164 | // Cache the top and bottom of set 165 | if(settings.cache) { 166 | this.top = this.getTop(); 167 | this.bottom = this.getBottom(); 168 | this.left = this.getLeft(); 169 | this.right = this.getRight(); 170 | } 171 | 172 | } 173 | 174 | // Cycle throught the selector(s) 175 | var chain = $selector.each(function() { 176 | 177 | // Add LazyLoadElement classes to the main array 178 | llelements.push(new LazyLoadElement($(this))); 179 | 180 | }); 181 | 182 | return chain; 183 | }, 184 | 185 | 'destroy': function() { 186 | $listenTo.unbind('scroll.lla'); 187 | }, 188 | 189 | 'load': function() { 190 | force_load_flag = true; 191 | $listenTo.trigger('scroll.lla'); 192 | } 193 | 194 | } 195 | 196 | $.fn.lazyloadanything = function(method) { 197 | 198 | // Method calling logic 199 | if (methods[method]) { 200 | return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 )); 201 | 202 | } else if (typeof method === 'object' || ! method) { 203 | return methods.init.apply(this, arguments); 204 | 205 | } else { 206 | $.error('Method ' + method + ' does not exist on jQuery.lazyloadanything'); 207 | } 208 | 209 | }; 210 | 211 | })( jQuery ); 212 | --------------------------------------------------------------------------------