Jquery瀑布流插件
瀑布流布局在目前貌似很火爆,具体的分析、原理、用到的知识等等可以看看以下几位牛人写的东西。
因为自己用jquery比较多,便萌生了把瀑布流做成插件的想法,图片就借用迅雷UED上的那些美图吧。
先看看Demo
把代码放出来吧
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 | ;( function ($){ var //参数 setting={ column_width:204, //列宽 column_className: 'waterfall_column' , //列的类名 column_space:10, //列间距 cell_selector: '.cell' , //要排列的砖块的选择器,限定在瀑布流的容器内 img_selector: 'img' , //要加载的图片的选择器 auto_imgHeight: true , //是否需要自动计算图片的高度 fadein: true , //是否渐显载入 fadein_speed:600, //渐显速率,单位毫秒 insert_type:1, //砖块插入方式,1为插入最短那列,2为按序轮流插入 getResource: function (index){ } //获取动态资源函数,必须返回一个砖块元素集合,传入参数为加载的次数 }, // waterfall=$.waterfall={}, $container= null ; //容器 waterfall.load_index=0, //加载次数 $.fn.extend({ waterfall: function (opt){ opt=opt||{}; setting=$.extend(setting,opt); $container=waterfall.$container=$( this ); waterfall.$columns=creatColumn(); render($( this ).find(setting.cell_selector).detach(), false ); //重排已存在元素时强制不渐显 waterfall._scrollTimer2= null ; $(window).bind( 'scroll' , function (){ clearTimeout(waterfall._scrollTimer2); waterfall._scrollTimer2=setTimeout(onScroll,300); }); waterfall._scrollTimer3= null ; $(window).bind( 'resize' , function (){ clearTimeout(waterfall._scrollTimer3); waterfall._scrollTimer3=setTimeout(onResize,300); }); } }); function creatColumn(){ //创建列 waterfall.column_num=calculateColumns(); //列数 //循环创建列 var html= '' ; for ( var i=0;i<waterfall.column_num;i++){ html+= '<div class="' +setting.column_className+ '" style="width:' +setting.column_width+ 'px; display:inline-block; *display:inline;zoom:1; margin-left:' +setting.column_space/2+ 'px;margin-right:' +setting.column_space/2+ 'px; vertical-align:top; overflow:hidden"></div>' ; } $container.prepend(html); //插入列 return $( '.' +setting.column_className,$container); //列集合 } function calculateColumns(){ //计算需要的列数 var num=Math.floor(($container.innerWidth())/(setting.column_width+setting.column_space)); if (num<1){ num=1; } //保证至少有一列 return num; } function render(elements,fadein){ //渲染元素 if (!$(elements).length) return ; //没有元素 var $columns = waterfall.$columns; $(elements).each( function (i){ if (!setting.auto_imgHeight||setting.insert_type==2){ //如果给出了图片高度,或者是按顺序插入,则不必等图片加载完就能计算列的高度了 if (setting.insert_type==1){ insert($(elements).eq(i),setting.fadein&&fadein); //插入元素 } else if (setting.insert_type==2){ insert2($(elements).eq(i),i,setting.fadein&&fadein); //插入元素 } return true ; //continue } if ($( this )[0].nodeName.toLowerCase()== 'img' ||$( this ).find(setting.img_selector).length>0){ //本身是图片或含有图片 var image= new Image; var src=$( this )[0].nodeName.toLowerCase()== 'img' ?$( this ).attr( 'src' ):$( this ).find(setting.img_selector).attr( 'src' ); image.onload= function (){ //图片加载后才能自动计算出尺寸 image.onreadystatechange= null ; if (setting.insert_type==1){ insert($(elements).eq(i),setting.fadein&&fadein); //插入元素 } else if (setting.insert_type==2){ insert2($(elements).eq(i),i,setting.fadein&&fadein); //插入元素 } image= null ; } image.onreadystatechange= function (){ //处理IE等浏览器的缓存问题:图片缓存后不会再触发onload事件 if (image.readyState == "complete" ){ image.onload= null ; if (setting.insert_type==1){ insert($(elements).eq(i),setting.fadein&&fadein); //插入元素 } else if (setting.insert_type==2){ insert2($(elements).eq(i),i,setting.fadein&&fadein); //插入元素 } image= null ; } } image.src=src; } else { //不用考虑图片加载 if (setting.insert_type==1){ insert($(elements).eq(i),setting.fadein&&fadein); //插入元素 } else if (setting.insert_type==2){ insert2($(elements).eq(i),i,setting.fadein&&fadein); //插入元素 } } }); } function public_render(elem){ //异步数据渲染接口函数 render(elem, true ); } function insert($element,fadein){ //把元素插入最短列 if (fadein){ //渐显 $element.css( 'opacity' ,0).appendTo(waterfall.$columns.eq(calculateLowest())).fadeTo(setting.fadein_speed,1); } else { //不渐显 $element.appendTo(waterfall.$columns.eq(calculateLowest())); } } function insert2($element,i,fadein){ //按序轮流插入元素 if (fadein){ //渐显 $element.css( 'opacity' ,0).appendTo(waterfall.$columns.eq(i%waterfall.column_num)).fadeTo(setting.fadein_speed,1); } else { //不渐显 $element.appendTo(waterfall.$columns.eq(i%waterfall.column_num)); } } function calculateLowest(){ //计算最短的那列的索引 var min=waterfall.$columns.eq(0).outerHeight(),min_key=0; waterfall.$columns.each( function (i){ if ($( this ).outerHeight()<min){ min=$( this ).outerHeight(); min_key=i; } }); return min_key; } function getElements(){ //获取资源 $.waterfall.load_index++; return setting.getResource($.waterfall.load_index,public_render); } waterfall._scrollTimer= null ; //延迟滚动加载计时器 function onScroll(){ //滚动加载 clearTimeout(waterfall._scrollTimer); waterfall._scrollTimer=setTimeout( function (){ var $lowest_column=waterfall.$columns.eq(calculateLowest()); //最短列 var bottom=$lowest_column.offset().top+$lowest_column.outerHeight(); //最短列底部距离浏览器窗口顶部的距离 var scrollTop=document.documentElement.scrollTop||document.body.scrollTop||0; //滚动条距离 var windowHeight=document.documentElement.clientHeight||document.body.clientHeight||0; //窗口高度 if (scrollTop>=bottom-windowHeight){ render(getElements(), true ); } },100); } function onResize(){ //窗口缩放时重新排列 if (calculateColumns()==waterfall.column_num) return ; //列数未改变,不需要重排 var $cells=waterfall.$container.find(setting.cell_selector); waterfall.$columns.remove(); waterfall.$columns=creatColumn(); render($cells, false ); //重排已有元素时强制不渐显 } })(jQuery); |
貌似把代码贴进来格式有点乱了,哎先不管了。上面的代码要是看不清可以在demo页直接查看源文件。
插件使用方法:
1 | $(selector).waterfall(opt); //其中selector为瀑布流容器的选择器,opt为配置参数对象 |
所需的html结构:html结构可以就是一个空容器元素,如<div id=”container”></div>,里面的砖块元素通过动态加载进来。当然也可以预先放一些砖块进去,如demo页中的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | < div id="container"> </ div > |
下面详细说下配置参数对象opt的各属性的作用及其默认值。
column_width:204 //瀑布流是由列组成的,该参数规定了每列的宽度,该参数会直接影响到瀑布流的列数
column_className:'waterfall_column' //列的类名,便于自定义样式
column_space:10 //列与列之间的间距
cell_selector:'.cell' //要排列的砖块的选择器,限定在瀑布流的容器内,即插件是通过这个选择器来获取砖块元素的,并且是在瀑布流的容器内来查找这个选择器匹配的元素。
img_selector:'img' //要加载的图片的选择器。如果你的瀑布流要加载的砖块元素的主题内容是大小不固定的图片,则该参数就是这些图片的选择器,插件需要获取这些图片来进行计算。
auto_imgHeight:true //是否需要自动计算图片的高度,如果图片的大小是固定的,则把该参数设为false吧
fadein:true //是否渐显载入
fadein_speed:600 //渐显速率,单位毫秒
insert_type:1 //砖块插入方式,1为插入最短那列,2为按序轮流插入
getResource:function(index,render){ } //获取动态资源函数,必须返回一个砖块元素集合,传入的第一个参数index为已加载的次数,第二个参数为渲染函数,它可以接受一个砖头元素集合作为参数,如果是使用ajax加载数据,则得到数据后要手动调用该函数来进行渲染 。每次到达瀑布流底部时会自动触发该函数来加载更多资源。
吐槽时间:
瀑布流加载的内容一般都宽度相同,高度不同的图片,如果能预先知道图片的高度,那就简单多了,但如果不能,则必须等到图片加载后才能计算出图片的高度,这是瀑布流最烦人的地方,也正是因为这样,如果是那些不知道高度的图片,则插入的顺序可能会有些混乱,而且每次刷新顺序都不同,因为每张图片加载完成的先后顺序并不是固定的,也许这次这个快一点,下次那个快一点。所以如果图片高度事先不知道,则整个砖块的高度也会不知道,必须等砖块里的图片加载完成后才能算出砖块的高度。如果是这样但又想保证砖块的插入顺序,则建议使用按顺序轮流插入的方式插入砖块,即把insert_type参数设为2。因为是插件,所以要考虑使用简便,但使用起来越简便,插件内部就会越复杂,漏洞、bug也会增多,所以我会继续完善这个插件。
本插件支持IE6+、chrome、firefox、opera、safari等主流浏览器。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· .NET周刊【3月第1期 2025-03-02】
· [AI/GPT/综述] AI Agent的设计模式综述
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!