├── Gruntfile.js ├── README.md ├── bower.json ├── demo ├── images.json ├── images │ ├── 1.jpg │ ├── 10.jpg │ ├── 11.jpg │ ├── 12.jpg │ ├── 13.jpg │ ├── 14.jpg │ ├── 15.jpg │ ├── 16.jpg │ ├── 17.jpg │ ├── 18.jpg │ ├── 19.jpg │ ├── 2.jpg │ ├── 3.jpg │ ├── 4.jpg │ ├── 5.jpg │ ├── 6.jpg │ ├── 7.jpg │ ├── 8.jpg │ └── 9.jpg ├── index.html ├── scripts │ ├── angular-waterfall.js │ └── main.js ├── styles │ └── main.css └── views │ └── main.html ├── package.json └── src └── angular-waterfall.js /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | 3 | // Project configuration. 4 | grunt.initConfig({ 5 | pkg: grunt.file.readJSON('package.json'), 6 | clean: ['build'], 7 | uglify: { 8 | options: { 9 | banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> \n author:<%= pkg.author%>\n git:<%= pkg.repository.url %> \n*/\n' 10 | }, 11 | build: { 12 | src: 'src/<%= pkg.name %>.js', 13 | dest: 'build/<%= pkg.name %>.min.js' 14 | } 15 | }, 16 | copy: { 17 | files : { 18 | filter: 'isFile', 19 | expand:true, 20 | flatten:true, 21 | src : ["static/*.js"], 22 | dest : "build/" 23 | } 24 | } 25 | }); 26 | 27 | // Load the plugin that provides the "uglify" task. 28 | grunt.loadNpmTasks('grunt-contrib-uglify'); 29 | grunt.loadNpmTasks('grunt-contrib-copy'); 30 | grunt.loadNpmTasks('grunt-contrib-clean'); 31 | 32 | // Default task(s). 33 | grunt.registerTask('default', ['clean','uglify','copy']); 34 | 35 | }; -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # angular-waterfall 2 | a responsive waterfall plugin of angular
3 | 定列自适应瀑布流指令 4 | 5 | # options 6 | * contentWidth(optional) 外层容器宽度,不设则auto 7 | * cols(optional) 指定显示列数,默认6 8 | 9 | # example 10 | 1.模块注入 11 | ```javascript 12 | angular.module('angularWaterfallApp',["ngWaterfall","ui.router"]) 13 | ``` 14 | 15 | 2.模板 16 | 17 | ```javascript 18 | 19 | 29 | 30 | ``` 31 | 32 | 3.controller 33 | 34 | ```javascript 35 | page++; 36 | $scope.$on("waterfall:loadMore",function(){//滚动自动填充事件 37 | $scope.loadMoreData(); 38 | }) 39 | 40 | ``` 41 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-waterfall", 3 | "version": "1.0.0", 4 | "dependencies": { 5 | "angular": "^1.3.0", 6 | "angular-ui-router": "~0.2.14" 7 | }, 8 | "devDependencies": { 9 | 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /demo/images.json: -------------------------------------------------------------------------------- 1 | { 2 | "results" : [ 3 | { 4 | "title": "兵兵", 5 | "url": "images/1.jpg", 6 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 7 | }, 8 | { 9 | "title": "兵兵", 10 | "url": "images/2.jpg", 11 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 12 | }, 13 | { 14 | "title": "兵兵", 15 | "url": "images/3.jpg", 16 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 17 | }, 18 | { 19 | "title": "兵兵", 20 | "url": "images/4.jpg", 21 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 22 | }, 23 | { 24 | "title": "兵兵", 25 | "url": "images/5.jpg", 26 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 27 | }, 28 | { 29 | "title": "兵兵", 30 | "url": "images/6.jpg", 31 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 32 | }, 33 | { 34 | "title": "兵兵", 35 | "url": "images/7.jpg", 36 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 37 | }, 38 | { 39 | "title": "兵兵", 40 | "url": "images/8.jpg", 41 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 42 | }, 43 | { 44 | "title": "兵兵", 45 | "url": "images/9.jpg", 46 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 47 | }, 48 | { 49 | "title": "兵兵", 50 | "url": "images/10.jpg", 51 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 52 | }, 53 | { 54 | "title": "兵兵", 55 | "url": "images/11.jpg", 56 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 57 | }, 58 | { 59 | "title": "兵兵", 60 | "url": "images/12.jpg", 61 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 62 | }, 63 | { 64 | "title": "兵兵", 65 | "url": "images/13.jpg", 66 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 67 | }, 68 | { 69 | "title": "兵兵", 70 | "url": "images/14.jpg", 71 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 72 | }, 73 | { 74 | "title": "兵兵", 75 | "url": "images/15.jpg", 76 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 77 | }, 78 | { 79 | "title": "兵兵", 80 | "url": "images/16.jpg", 81 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 82 | }, 83 | { 84 | "title": "兵兵", 85 | "url": "images/17.jpg", 86 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 87 | }, 88 | { 89 | "title": "兵兵", 90 | "url": "images/18.jpg", 91 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 92 | }, 93 | { 94 | "title": "兵兵", 95 | "url": "images/19.jpg", 96 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 97 | }, 98 | { 99 | "title": "兵兵", 100 | "url": "images/2.jpg", 101 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 102 | }, 103 | { 104 | "title": "兵兵", 105 | "url": "images/3.jpg", 106 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 107 | }, 108 | { 109 | "title": "兵兵", 110 | "url": "images/4.jpg", 111 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 112 | }, 113 | { 114 | "title": "兵兵", 115 | "url": "images/5.jpg", 116 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 117 | }, 118 | { 119 | "title": "兵兵", 120 | "url": "images/6.jpg", 121 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 122 | }, 123 | { 124 | "title": "兵兵", 125 | "url": "images/7.jpg", 126 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 127 | }, 128 | { 129 | "title": "兵兵", 130 | "url": "images/8.jpg", 131 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 132 | }, 133 | { 134 | "title": "兵兵", 135 | "url": "images/9.jpg", 136 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 137 | }, 138 | { 139 | "title": "兵兵", 140 | "url": "images/10.jpg", 141 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 142 | }, 143 | { 144 | "title": "兵兵", 145 | "url": "images/11.jpg", 146 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 147 | }, 148 | { 149 | "title": "兵兵", 150 | "url": "images/12.jpg", 151 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 152 | }, 153 | { 154 | "title": "兵兵", 155 | "url": "images/13.jpg", 156 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 157 | }, 158 | { 159 | "title": "兵兵", 160 | "url": "images/14.jpg", 161 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 162 | }, 163 | { 164 | "title": "兵兵", 165 | "url": "images/15.jpg", 166 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 167 | }, 168 | { 169 | "title": "兵兵", 170 | "url": "images/16.jpg", 171 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 172 | }, 173 | { 174 | "title": "兵兵", 175 | "url": "images/17.jpg", 176 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 177 | }, 178 | { 179 | "title": "兵兵", 180 | "url": "images/18.jpg", 181 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 182 | }, 183 | { 184 | "title": "兵兵", 185 | "url": "images/19.jpg", 186 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 187 | }, 188 | { 189 | "title": "兵兵", 190 | "url": "images/2.jpg", 191 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 192 | }, 193 | { 194 | "title": "兵兵", 195 | "url": "images/3.jpg", 196 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 197 | }, 198 | { 199 | "title": "兵兵", 200 | "url": "images/4.jpg", 201 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 202 | }, 203 | { 204 | "title": "兵兵", 205 | "url": "images/5.jpg", 206 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 207 | }, 208 | { 209 | "title": "兵兵", 210 | "url": "images/6.jpg", 211 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 212 | }, 213 | { 214 | "title": "兵兵", 215 | "url": "images/7.jpg", 216 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 217 | }, 218 | { 219 | "title": "兵兵", 220 | "url": "images/8.jpg", 221 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 222 | }, 223 | { 224 | "title": "兵兵", 225 | "url": "images/9.jpg", 226 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 227 | }, 228 | { 229 | "title": "兵兵", 230 | "url": "images/10.jpg", 231 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 232 | }, 233 | { 234 | "title": "兵兵", 235 | "url": "images/11.jpg", 236 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 237 | }, 238 | { 239 | "title": "兵兵", 240 | "url": "images/12.jpg", 241 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 242 | }, 243 | { 244 | "title": "兵兵", 245 | "url": "images/13.jpg", 246 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 247 | }, 248 | { 249 | "title": "兵兵", 250 | "url": "images/14.jpg", 251 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 252 | }, 253 | { 254 | "title": "兵兵", 255 | "url": "images/15.jpg", 256 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 257 | }, 258 | { 259 | "title": "兵兵", 260 | "url": "images/16.jpg", 261 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 262 | }, 263 | { 264 | "title": "兵兵", 265 | "url": "images/17.jpg", 266 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 267 | }, 268 | { 269 | "title": "兵兵", 270 | "url": "images/18.jpg", 271 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 272 | }, 273 | { 274 | "title": "兵兵", 275 | "url": "images/19.jpg", 276 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 277 | }, 278 | { 279 | "title": "兵兵", 280 | "url": "images/2.jpg", 281 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 282 | }, 283 | { 284 | "title": "兵兵", 285 | "url": "images/3.jpg", 286 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 287 | }, 288 | { 289 | "title": "兵兵", 290 | "url": "images/4.jpg", 291 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 292 | }, 293 | { 294 | "title": "兵兵", 295 | "url": "images/5.jpg", 296 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 297 | }, 298 | { 299 | "title": "兵兵", 300 | "url": "images/6.jpg", 301 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 302 | }, 303 | { 304 | "title": "兵兵", 305 | "url": "images/7.jpg", 306 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 307 | }, 308 | { 309 | "title": "兵兵", 310 | "url": "images/8.jpg", 311 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 312 | }, 313 | { 314 | "title": "兵兵", 315 | "url": "images/9.jpg", 316 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 317 | }, 318 | { 319 | "title": "兵兵", 320 | "url": "images/10.jpg", 321 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 322 | }, 323 | { 324 | "title": "兵兵", 325 | "url": "images/11.jpg", 326 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 327 | }, 328 | { 329 | "title": "兵兵", 330 | "url": "images/12.jpg", 331 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 332 | }, 333 | { 334 | "title": "兵兵", 335 | "url": "images/13.jpg", 336 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 337 | }, 338 | { 339 | "title": "兵兵", 340 | "url": "images/14.jpg", 341 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 342 | }, 343 | { 344 | "title": "兵兵", 345 | "url": "images/15.jpg", 346 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 347 | }, 348 | { 349 | "title": "兵兵", 350 | "url": "images/16.jpg", 351 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 352 | }, 353 | { 354 | "title": "兵兵", 355 | "url": "images/17.jpg", 356 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 357 | }, 358 | { 359 | "title": "兵兵", 360 | "url": "images/18.jpg", 361 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 362 | }, 363 | { 364 | "title": "兵兵", 365 | "url": "images/19.jpg", 366 | "summary":"Angelababy收藏鞋子很疯狂 将接拍《" 367 | } 368 | ] 369 | } -------------------------------------------------------------------------------- /demo/images/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedwang/angular-waterfall/2a9d0f275b41c01fd4672f807cd34c5486ac1d78/demo/images/1.jpg -------------------------------------------------------------------------------- /demo/images/10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedwang/angular-waterfall/2a9d0f275b41c01fd4672f807cd34c5486ac1d78/demo/images/10.jpg -------------------------------------------------------------------------------- /demo/images/11.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedwang/angular-waterfall/2a9d0f275b41c01fd4672f807cd34c5486ac1d78/demo/images/11.jpg -------------------------------------------------------------------------------- /demo/images/12.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedwang/angular-waterfall/2a9d0f275b41c01fd4672f807cd34c5486ac1d78/demo/images/12.jpg -------------------------------------------------------------------------------- /demo/images/13.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedwang/angular-waterfall/2a9d0f275b41c01fd4672f807cd34c5486ac1d78/demo/images/13.jpg -------------------------------------------------------------------------------- /demo/images/14.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedwang/angular-waterfall/2a9d0f275b41c01fd4672f807cd34c5486ac1d78/demo/images/14.jpg -------------------------------------------------------------------------------- /demo/images/15.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedwang/angular-waterfall/2a9d0f275b41c01fd4672f807cd34c5486ac1d78/demo/images/15.jpg -------------------------------------------------------------------------------- /demo/images/16.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedwang/angular-waterfall/2a9d0f275b41c01fd4672f807cd34c5486ac1d78/demo/images/16.jpg -------------------------------------------------------------------------------- /demo/images/17.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedwang/angular-waterfall/2a9d0f275b41c01fd4672f807cd34c5486ac1d78/demo/images/17.jpg -------------------------------------------------------------------------------- /demo/images/18.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedwang/angular-waterfall/2a9d0f275b41c01fd4672f807cd34c5486ac1d78/demo/images/18.jpg -------------------------------------------------------------------------------- /demo/images/19.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedwang/angular-waterfall/2a9d0f275b41c01fd4672f807cd34c5486ac1d78/demo/images/19.jpg -------------------------------------------------------------------------------- /demo/images/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedwang/angular-waterfall/2a9d0f275b41c01fd4672f807cd34c5486ac1d78/demo/images/2.jpg -------------------------------------------------------------------------------- /demo/images/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedwang/angular-waterfall/2a9d0f275b41c01fd4672f807cd34c5486ac1d78/demo/images/3.jpg -------------------------------------------------------------------------------- /demo/images/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedwang/angular-waterfall/2a9d0f275b41c01fd4672f807cd34c5486ac1d78/demo/images/4.jpg -------------------------------------------------------------------------------- /demo/images/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedwang/angular-waterfall/2a9d0f275b41c01fd4672f807cd34c5486ac1d78/demo/images/5.jpg -------------------------------------------------------------------------------- /demo/images/6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedwang/angular-waterfall/2a9d0f275b41c01fd4672f807cd34c5486ac1d78/demo/images/6.jpg -------------------------------------------------------------------------------- /demo/images/7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedwang/angular-waterfall/2a9d0f275b41c01fd4672f807cd34c5486ac1d78/demo/images/7.jpg -------------------------------------------------------------------------------- /demo/images/8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedwang/angular-waterfall/2a9d0f275b41c01fd4672f807cd34c5486ac1d78/demo/images/8.jpg -------------------------------------------------------------------------------- /demo/images/9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zedwang/angular-waterfall/2a9d0f275b41c01fd4672f807cd34c5486ac1d78/demo/images/9.jpg -------------------------------------------------------------------------------- /demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /demo/scripts/angular-waterfall.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Zed on 2015/4/26. 3 | * @name ngWaterfall 4 | */ 5 | (function(window,angular){ 6 | 7 | angular.module('ngWaterfall',[]) 8 | .directive("repeatFinished",function($timeout){ 9 | return { 10 | restrict: "A", 11 | require: "^ngWaterfall", 12 | link: function (scope,element,attr,controller) { 13 | if (!controller.state) { 14 | element[0].style.opacity = "0"; 15 | element[0].style["-moz-opacity"] = "0"; 16 | element[0].style["filter"] = "alpha(opacity=0)"; 17 | } 18 | 19 | if (scope.$last === true) { 20 | angular.element(element).ready(function() { 21 | var img = element.find("img")[0]; 22 | var oImage = new Image(); 23 | oImage.src = img.src; 24 | oImage.onload = function () { 25 | scope.$emit("waterfall:repeatFinished"); 26 | } 27 | }); 28 | } 29 | } 30 | } 31 | }) 32 | .directive("ngInfiniteScroll",function($rootScope){ 33 | return { 34 | restrict: "AE", 35 | replace: true, 36 | link:function(scope,element,attr,controller){ 37 | element[0].style.position = "absolute"; 38 | element[0].style.left = 0; 39 | $rootScope.$on("waterfall:colData",function(ev,data){ 40 | var sorted = data.sort(function(a,b){ 41 | return a-b 42 | }); 43 | scope.max = sorted[sorted.length - 1]; 44 | element[0].style.top = scope.max + 30 + 'px'; 45 | }) 46 | } 47 | } 48 | }) 49 | .directive("ngWaterfall",function($window,$document,$rootScope,$timeout,$log){ 50 | return { 51 | restrict: "A", 52 | scope: { 53 | contentWidth : "@", 54 | cols : "@" 55 | }, 56 | controller: function($scope){ 57 | var self = this; 58 | this.state = false; 59 | $scope.$on("waterfall:loadMore",function(){ 60 | self.state = true; 61 | }) 62 | }, 63 | link: function(scope,element){ 64 | scope.minCols = scope.cols || 6; 65 | $rootScope.$on("waterfall:repeatFinished",function(){ 66 | $timeout.cancel(); 67 | waterfall(scope.minCols); 68 | 69 | }); 70 | $window.onresize = function(){ 71 | $timeout.cancel(); 72 | $timeout(function(){ 73 | waterfall(scope.minCols); 74 | },500) 75 | }; 76 | 77 | 78 | function scroll(){ 79 | var index = getMinKeyByArray(scope.oLiHeight); 80 | var short = scope.oLiHeight[index]; 81 | var clientHeight = $document[0].documentElement.clientHeight; 82 | var scrollTop = document.documentElement.scrollTop > document.body.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop; 83 | if (scrollTop + clientHeight >= short) { 84 | scope.$emit("waterfall:loadMore"); 85 | $window.onscroll = null; 86 | } 87 | } 88 | function waterfall(minCols){ 89 | scope.wrapWidth = scope.contentWidth || element[0].offsetWidth; 90 | scope.oLiHeight = [];//存每行的高度 91 | var 92 | colWidth, 93 | oLis = element.find("li"); 94 | colWidth = scope.wrapWidth/minCols; 95 | for (var m = 0; m < oLis.length; m++){ 96 | 97 | oLis[m].style.width = colWidth + "px"; 98 | oLis[m].style.opacity = "1"; 99 | oLis[m].style["-moz-opacity"] = "1"; 100 | oLis[m].style["filter"] = "alpha(opacity=100)"; 101 | } 102 | for (var i = 0; i < minCols; i++){ 103 | oLis[i].style.top = 0; 104 | oLis[i].style.left = i * colWidth + "px"; 105 | var h = parseInt(oLis[i].offsetHeight); 106 | scope.oLiHeight.push(h); 107 | } 108 | 109 | 110 | for (var k = minCols; k < oLis.length; k++){ 111 | var index = getMinKeyByArray(scope.oLiHeight); 112 | oLis[k].style.top = scope.oLiHeight[index] +"px"; 113 | oLis[k].style.left = colWidth * index +"px"; 114 | // oLis[k].style.opacity = "1"; 115 | // oLis[k].style["-moz-opacity"] = "1"; 116 | // oLis[k].style["filter"] = "alpha(opacity=100)"; 117 | scope.oLiHeight[index] = scope.oLiHeight[index] + parseInt(oLis[k].offsetHeight) 118 | 119 | } 120 | scope.$emit("waterfall:colData",scope.oLiHeight); 121 | var sorted = scope.oLiHeight.sort(function(a,b){ 122 | return a-b 123 | }); 124 | var max = sorted[sorted.length - 1]; 125 | element[0].style.height = max + 30 + "px"; 126 | $window.onscroll = scroll; 127 | } 128 | 129 | 130 | function getMinKeyByArray(arr){ 131 | var val = arr[0]; 132 | var key = 0; 133 | for (var k in arr) { 134 | if (arr[k] < val) { 135 | val = arr[k]; 136 | key = k; 137 | } 138 | } 139 | return key; 140 | 141 | } 142 | 143 | } 144 | } 145 | }) 146 | 147 | })(window,angular) -------------------------------------------------------------------------------- /demo/scripts/main.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * @ngdoc function 5 | * @name yoApp.controller:MainCtrl 6 | * @description 7 | * # MainCtrl 8 | * Controller of the yoApp 9 | */ 10 | angular.module('angularWaterfallApp',["ngWaterfall","ui.router"]) 11 | .config([ '$stateProvider', '$urlRouterProvider', 12 | function ($stateProvider, $urlRouterProvider) { 13 | $stateProvider.state("home",{ 14 | url: "/home", 15 | templateUrl: "views/main.html", 16 | controller: "MainCtrl" 17 | }) 18 | $urlRouterProvider.otherwise("/home"); 19 | 20 | }]) 21 | .factory("myService",function($http){ 22 | return { 23 | getImages : function(cb){ 24 | $http({ method : "GET", url: 'images.json'}). 25 | success(function(data, status) { 26 | cb(data,status); 27 | }). 28 | error(function(data, status) { 29 | }); 30 | } 31 | } 32 | }) 33 | .controller('MainCtrl', function ($scope,$rootScope,$state,$location,$timeout,myService) { 34 | var page = 1; 35 | var pageSize = 20; 36 | 37 | 38 | myService.getImages(function(data){ 39 | $scope.images = []; 40 | $scope.results = data.results.slice(0,page*pageSize); 41 | for (var i = 0; i < $scope.results.length; i++) { 42 | $scope.images.push($scope.results[i]); 43 | } 44 | }) 45 | $scope.text = "点我加载更多" 46 | $scope.loadMore = true; 47 | $scope.loadMoreData = function(){ 48 | $scope.text = "加载中,请稍后···"; 49 | $timeout(function(){ 50 | page++; 51 | myService.getImages(function(data){ 52 | $scope.images = []; 53 | $scope.results = data.results.slice(0,page*pageSize); 54 | if ($scope.results.length == 73) { 55 | $scope.text = "内容已经全部加载完毕" 56 | } 57 | for (var i = 0; i < $scope.results.length; i++) { 58 | $scope.images.push($scope.results[i]); 59 | } 60 | }) 61 | $scope.text = "点我加载更多···" 62 | },1500); 63 | }; 64 | // $scope.$on("waterfall:loadMore",function(){//滚动自动填充事件 65 | // $scope.loadMoreData(); 66 | // }) 67 | }) 68 | 69 | -------------------------------------------------------------------------------- /demo/styles/main.css: -------------------------------------------------------------------------------- 1 | /* Space out content a bit */ 2 | body { 3 | margin: 0; 4 | padding: 0; 5 | } 6 | 7 | .container { 8 | width: 90%; 9 | margin: 0 auto; 10 | } 11 | .header { 12 | border-bottom: 1px solid #cccccc; 13 | padding: 10px 0; 14 | text-align: center; 15 | height: 25px; 16 | line-height: 25px; 17 | } 18 | .waterfall-list { 19 | /*width: 1024px;*/ 20 | margin: 0; 21 | padding: 0; 22 | list-style: none; 23 | position: relative; 24 | } 25 | .waterfall-list li { 26 | position: absolute; 27 | left: 0; 28 | top: 0; 29 | -webkit-box-sizing: border-box; 30 | -moz-box-sizing: border-box; 31 | box-sizing: border-box; 32 | padding: 5px; 33 | overflow: hidden; 34 | 35 | } 36 | .waterfall-list li:after { 37 | clear: both; 38 | } 39 | .waterfall-list li .data-block { 40 | border: 1px solid #cccccc; 41 | border-radius: 5px; 42 | padding: 5px; 43 | 44 | } 45 | .waterfall-list li p { 46 | font-size: 12px; 47 | color: rgba(61, 61, 61, 0.93); 48 | } 49 | .clear { 50 | clear: both; 51 | } 52 | .waterfall-list li img { 53 | width: 100%; 54 | height: 100%; 55 | } 56 | .loadMore { 57 | cursor: pointer; 58 | width: 100%; 59 | height: 30px; 60 | line-height: 30px; 61 | text-align: center; 62 | border: 1px solid #cccccc; 63 | border-radius: 5px; 64 | } 65 | -------------------------------------------------------------------------------- /demo/views/main.html: -------------------------------------------------------------------------------- 1 |
2 |

angular-waterfall

3 | 4 | 14 |
15 | 16 | 17 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-waterfall", 3 | "version": "1.0.0", 4 | "dependencies": {}, 5 | "devDependencies": { 6 | "grunt": "^0.4.1", 7 | "grunt-contrib-clean": "^0.5.0", 8 | "grunt-contrib-copy": "^0.5.0", 9 | "grunt-contrib-uglify": "^0.4.0" 10 | }, 11 | "engines": { 12 | "node": ">=0.10.0" 13 | }, 14 | "scripts": { 15 | "test": "grunt test" 16 | }, 17 | "author": "Zed" 18 | } -------------------------------------------------------------------------------- /src/angular-waterfall.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Zed on 2015/4/26. 3 | * @name ngWaterfall 4 | */ 5 | (function(window,angular){ 6 | 7 | angular.module('ngWaterfall',[]) 8 | .directive("repeatFinished",function($timeout){ 9 | return { 10 | restrict: "A", 11 | require: "^ngWaterfall", 12 | link: function (scope,element,attr,controller) { 13 | if (!controller.state) { 14 | element[0].style.opacity = "0"; 15 | element[0].style["-moz-opacity"] = "0"; 16 | element[0].style["filter"] = "alpha(opacity=0)"; 17 | } 18 | 19 | if (scope.$last === true) { 20 | angular.element(element).ready(function() { 21 | var img = element.find("img")[0]; 22 | var oImage = new Image(); 23 | oImage.src = img.src; 24 | oImage.onload = function () { 25 | scope.$emit("waterfall:repeatFinished"); 26 | } 27 | }); 28 | } 29 | } 30 | } 31 | }) 32 | .directive("ngInfiniteScroll",function($rootScope){ 33 | return { 34 | restrict: "AE", 35 | replace: true, 36 | link:function(scope,element,attr,controller){ 37 | element[0].style.position = "absolute"; 38 | element[0].style.left = 0; 39 | $rootScope.$on("waterfall:colData",function(ev,data){ 40 | var sorted = data.sort(function(a,b){ 41 | return a-b 42 | }); 43 | scope.max = sorted[sorted.length - 1]; 44 | element[0].style.top = scope.max + 30 + 'px'; 45 | }) 46 | } 47 | } 48 | }) 49 | .directive("ngWaterfall",function($window,$document,$rootScope,$timeout,$log){ 50 | return { 51 | restrict: "A", 52 | scope: { 53 | contentWidth : "@", 54 | cols : "@" 55 | }, 56 | controller: function($scope){ 57 | var self = this; 58 | this.state = false; 59 | $scope.$on("waterfall:loadMore",function(){ 60 | self.state = true; 61 | }) 62 | }, 63 | link: function(scope,element){ 64 | scope.minCols = scope.cols || 6; 65 | $rootScope.$on("waterfall:repeatFinished",function(){ 66 | $timeout.cancel(); 67 | waterfall(scope.minCols); 68 | 69 | }); 70 | $window.onresize = function(){ 71 | $timeout.cancel(); 72 | $timeout(function(){ 73 | waterfall(scope.minCols); 74 | },500) 75 | }; 76 | 77 | 78 | function scroll(){ 79 | var index = getMinKeyByArray(scope.oLiHeight); 80 | var short = scope.oLiHeight[index]; 81 | var clientHeight = $document[0].documentElement.clientHeight; 82 | var scrollTop = document.documentElement.scrollTop > document.body.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop; 83 | if (scrollTop + clientHeight >= short) { 84 | scope.$emit("waterfall:loadMore"); 85 | $window.onscroll = null; 86 | } 87 | } 88 | function waterfall(minCols){ 89 | scope.wrapWidth = scope.contentWidth || element[0].offsetWidth; 90 | scope.oLiHeight = [];//存每行的高度 91 | var 92 | colWidth, 93 | oLis = element.find("li"); 94 | colWidth = scope.wrapWidth/minCols; 95 | for (var m = 0; m < oLis.length; m++){ 96 | 97 | oLis[m].style.width = colWidth + "px"; 98 | oLis[m].style.opacity = "1"; 99 | oLis[m].style["-moz-opacity"] = "1"; 100 | oLis[m].style["filter"] = "alpha(opacity=100)"; 101 | } 102 | for (var i = 0; i < minCols; i++){ 103 | oLis[i].style.top = 0; 104 | oLis[i].style.left = i * colWidth + "px"; 105 | var h = parseInt(oLis[i].offsetHeight); 106 | scope.oLiHeight.push(h); 107 | } 108 | 109 | 110 | for (var k = minCols; k < oLis.length; k++){ 111 | var index = getMinKeyByArray(scope.oLiHeight); 112 | oLis[k].style.top = scope.oLiHeight[index] +"px"; 113 | oLis[k].style.left = colWidth * index +"px"; 114 | // oLis[k].style.opacity = "1"; 115 | // oLis[k].style["-moz-opacity"] = "1"; 116 | // oLis[k].style["filter"] = "alpha(opacity=100)"; 117 | scope.oLiHeight[index] = scope.oLiHeight[index] + parseInt(oLis[k].offsetHeight) 118 | 119 | } 120 | scope.$emit("waterfall:colData",scope.oLiHeight); 121 | var sorted = scope.oLiHeight.sort(function(a,b){ 122 | return a-b 123 | }); 124 | var max = sorted[sorted.length - 1]; 125 | element[0].style.height = max + 30 + "px"; 126 | $window.onscroll = scroll; 127 | } 128 | 129 | 130 | function getMinKeyByArray(arr){ 131 | var val = arr[0]; 132 | var key = 0; 133 | for (var k in arr) { 134 | if (arr[k] < val) { 135 | val = arr[k]; 136 | key = k; 137 | } 138 | } 139 | return key; 140 | 141 | } 142 | 143 | } 144 | } 145 | }) 146 | 147 | })(window,angular) --------------------------------------------------------------------------------