├── 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 |
20 | -
21 |
22 |

23 |
{{image.title}}
24 |
{{image.summary}}
25 |
26 |
27 | {{text}}
28 |
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 |
3 |
4 |
5 | -
6 |
7 |

8 |
{{image.title}}
9 |
{{image.summary}}
10 |
11 |
12 | {{text}}
13 |
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)
--------------------------------------------------------------------------------