js实现瀑布流效果V2.0版本
来源:互联网 发布:java 对称加密 编辑:程序博客网 时间:2024/04/24 09:39
之前写过一篇用js实现瀑布流效果的文章,可以称为V1.0版本,有兴趣的可以看看:html5实现瀑布流效果。今天既然跟大家分享的是2.0版本,当前是为了解决1.0版本中存在的bug。
1.0版本中实现两列瀑布流的基本思路就是父级元素采用position:relative;相对定位的方式,子元素采用position:absolute;绝对定位的方式,因为子元素可能带有图片,也可能不带图片。这又需要分情况处理,带图片的,由于图片加载速度较慢,需要使用img标签的load事件判断当前子元素的图片已经加载完成后,才能加载下一个子元素,否则子元素会相互重叠在一起。子元素不带图片就没后面那么多的麻烦事,直接使用for循环将一页子元素全部顺序加载完就完事了。效果图如下。
子元素带图片的:
子元素不带图片的:
使用上面所说的思路,来做上面两个单页面项目,没有暴露出明显问题。但是我在另一个心愿漂流瓶项目中,这个思路就受到了挑战,暴露出了一些新的问题。
先上图:
如上图所示,这个页面底部工具栏有3个按钮,将主页分成了心愿区、帮助区和我的3个区域,这3个区域都需要使用瀑布流排布列表项。这样的话,就会暴露出1.0版本瀑布流排布方法的几个bug。
1.第一个bug:先看下面的代码
/** * 添加心愿列表,瀑布流效果,支持有图片显示和无图片显示 * @param playerList 元素列表 * @param index 列表项页内序号 * @param boxHeightArr 瀑布流左右两列的总高度数组 * @param currentPage 当前所在页 * @param parent 加载元素的父级元素 */function addWish(playerList, index, boxHeightArr, currentPage, parent){ var template = ""; var html = ""; var childrenBoxIndex = $(parent).find(".listBox").length - (currentPage - 1) * 10; if (childrenBoxIndex < playerList.length){ template = '<div class="listBox">'; template += ' <div class="innerBox1">'; template += ' <div class="innerBox2">'; template += ' <a href="/wishDriftBottle/html5/detailedWish.html?id={id}">'; // 在detailedWish.html通过id获取心愿信息 template += ' <div class="idAndName">'; template += ' <img class="officialPic officialPic{wishNo}" style="display: none;" src="/wishDriftBottle/imgs/sourceImgs/official.png">'; template += ' <span class="idSpan">{wishNo}号 {fullname}</span>'; template += ' <img class="status publishing{wishNo}" style="display: none;" src="/wishDriftBottle/imgs/sourceImgs/publishing.png">'; template += ' <img class="status finished{wishNo}" style="display: none;" src="/wishDriftBottle/imgs/sourceImgs/finished.png">'; template += ' </div>'; template += ' <div class="imgAndContent imgAndContent{wishNo}"> </div>'; template += ' <div class="vote">'; template += ' <span class="helpText">已获得{votesNum}人帮助</span>'; template += ' </div>'; template += ' </a>'; template += ' </div>'; template += ' </div>'; template += '</div>'; var wishNo = parseInt(playerList[index].wishNo); playerList[index].wishNo = wishNo; html = template.formatString(playerList[index]); $(parent).append(html); boxLocation(boxHeightArr, (currentPage - 1)*10 + index, parent); // 计算当前列表元素的坐标(绝对定位) $(parent)[0].style.height = Math.max.apply(null, boxHeightArr) + "px"; // 为了列表元素和加载提示不重合,需要实时更新players的高度 var wish = playerList[index]; var createType = wish.createType; if (createType == 1){ $(".officialPic" + wishNo).show(); } var status = wish.status; if (status == 1){ $(".publishing" + wishNo).show(); } else if (status == 2){ $(".finished" + wishNo).show(); } var wishImgUrls = wish.urls; if (wishImgUrls != null){ // 当前心愿有图片,显示图片 template = '<img class="wishImg wishImg{wishNo}">'; // 将img元素插入imgAndContent template += '<div class="imgTitle">{title}</div>'; html = template.formatString(playerList[index]); $(".imgAndContent" + wishNo).html(html); var wishImgUrl0 = wishImgUrls[0]; var url = wishImgUrl0.url; var wishImgName = ".wishImg" + wishNo; $(wishImgName).attr('src', imagesPrefix + url + "?imageView2/2/w/300"); $(wishImgName).load(function(){ refreshBoxHeightArr(boxHeightArr, (currentPage - 1)*10 + index, parent); // 当前图片加载完后,更新boxHeightArr[] $(parent)[0].style.height = Math.max.apply(null, boxHeightArr) + "px"; // 为了列表元素和加载提示不重合,需要实时更新players的高度 return addWish(playerList, ++index, boxHeightArr, currentPage, parent); // 自调用,加载完一张图片后,再加载下一张图片,防止图片重叠 }); } else{ // 当前心愿无图片,显示心愿详情 template = '<span class="content content{wishNo}"></span>'; // 将span(心愿内容)插入imgAndContent html = template.formatString(playerList[index]); $(".imgAndContent" + wishNo).html(html); $(".content" + wishNo).text(wish.title); refreshBoxHeightArr(boxHeightArr, (currentPage - 1)*10 + index, parent); $(parent)[0].style.height = Math.max.apply(null, boxHeightArr) + "px"; // 为了列表元素和加载提示不重合,需要实时更新players的高度 return addWish(playerList, ++index, boxHeightArr, currentPage, parent); // 自调用,加载完一张图片后,再加载下一张图片,防止图片重叠 } } return;}
这是加载心愿列表的函数,在实际开发项目的过程中,我发现在页面“我的”一栏下,会出现列表项加载完后,有几个列表项被重复加载的问题,这个问题困扰了我好久,最终经过调试分析发现是$(wishImgName).load(function(){});捣的鬼,因为图片加载较慢,addWish()函数执行完后,index参数已经被释放,所以load事件触发时,取到的列表项序号index就是个错误的,导致重复加载。
解决办法:load事件中,要根据实际DOM的数量计算当前列表项的index序号。
2.第二个bug
按照1.0中的思路,大部分情况下瀑布流加载都是没有问题的,但是偶尔还是有瀑布流排布出错的问题,这个让我很苦恼。经过分析,毕竟计算每个子元素绝对位置的方式不是太稳定,因为每个子元素都需要计算相对父级元素的位置,代码如下:
ccontent[index].style.position = "absolute"; ccontent[index].style.left = ccontent[minIndex].offsetLeft + "px"; ccontent[index].style.top = boxHeightArr[minIndex] + "px";
而且后面的子元素的位置计算都依赖于之前所有已经加载的子元素,一旦有一个子元素的位置计算错误,会导致后面的所有子元素位置全部错乱。一句话总结:这样方法稳定性太差。
所以,需要使用全新的方法来解决这个bug,如果列表项占满一行,根本不用担心列表项重叠的问题,因为div使用的是浮动布局,按照这种思路,完全可以把页面平分成两栏,根据两栏子元素的总高度,决定把下一子元素放在左边或者右边,这样就完美解决了这个bug。
最终,经过优化重构过的代码如下:
/** * 添加心愿列表,瀑布流效果,支持有图片显示和无图片显示 * @param playerList 元素列表 * @param pageIndex 元素页内序号 * @param boxHeightArr 瀑布流左右两列的总高度数组 * @param currentPage 当前所在页 * @param parent 加载元素的父级元素 */function addWish(playerList, pageIndex, boxHeightArr, currentPage, parent){ var template, minheight, minIndex, wish, wishNo, wishImgUrls; template = ""; if (pageIndex < playerList.length){ wish = playerList[pageIndex]; wishNo = parseInt(wish.wishNo); playerList[pageIndex].wishNo = wishNo; wishImgUrls = wish.urls; template = '<div class="listBox">'; template += ' <div class="innerBox1">'; template += ' <div class="innerBox2">'; template += ' <a href="../html5/detailedWish.html?id='+ wish.id +'">'; // 在detailedWish.html通过id获取心愿信息 template += ' <div class="idAndName">'; if (wish.createType === 1) { template += ' <img class="officialPic" src="../imgs/sourceImgs/official.png">'; } template += ' <span class="idSpan" id="idSpan_'+ wishNo +'">'+ wishNo +'号 '+ wish.fullname +'</span>'; if (wish.status === 1) { template += ' <img class="status" src="../imgs/sourceImgs/publishing.png">'; } else { template += ' <img class="status" src="../imgs/sourceImgs/finished.png">'; } template += ' </div>'; template += ' <div class="imgAndContent">'; if (wishImgUrls != null) { template += ' <img class="wishImg" id="wishImg_'+ wishNo +'">'; template += ' <div class="imgTitle">'+ wish.title +'</div>'; } else { template += ' <span class="content">'+ wish.title +'</span>'; } template += ' </div>'; template += ' <div class="vote">'; template += ' <span class="helpText">已获得'+ wish.votesNum +'人帮助</span>'; template += ' </div>'; template += ' </a>'; template += ' </div>'; template += ' </div>'; template += '</div>'; minheight = Math.min.apply(null, boxHeightArr); minIndex = getminheightLocation(boxHeightArr, minheight); if ($(parent).find("#idSpan_" + wishNo).length === 0) { // 使用page取列表项时,服务端可能返回重复的列表项,需剔除 $(parent).find(".lists_" + minIndex).append(template); } if (wishImgUrls != null){ // 当前心愿有图片,显示图片 $(parent).find("#wishImg_" + wishNo).attr("src", imagesPrefix + wishImgUrls[0].url + "?imageView2/2/w/300"); $(parent).find("#wishImg_" + wishNo).load(function(){ // 主页中可能有多个class为wishImgName的img,需指定父级元素,保证唯一性 var allIndex = $(parent).find(".listBox").length - 1; var pageIndexTmp = allIndex - (currentPage -1)*10; refreshBoxHeightArr(boxHeightArr, allIndex, parent); // 由于图片加载速度较慢,局部变量pageIndex可能被释放,此处只能使用重新计算的元素总排序allIndex return addWish(playerList, ++pageIndexTmp, boxHeightArr, currentPage, parent); // 自调用,加载完一张图片后,再加载下一张图片,防止图片重叠 }); } else{ // 当前心愿无图片,显示心愿详情 refreshBoxHeightArr(boxHeightArr, (currentPage - 1)*10 + pageIndex, parent); return addWish(playerList, ++pageIndex, boxHeightArr, currentPage, parent); // 自调用,加载完一张图片后,再加载下一张图片,防止图片重叠 } } else { if ($(parent).attr("class") === "all-wish-lists") { allWishIsLoading = true; // 图片load事件会导致一页列表未加载完就退出addWish(),allWishIsLoading变量需要置于此处 } else if ($(parent).attr("class") === "myPublishWishList") { myPublishWishIsLoading = true; } else if ($(parent).attr("class") === "mySponsorHelpList"){ mySponsorHelpIsLoading = true; } else { findIsLoading = true; } return; }}
- js实现瀑布流效果V2.0版本
- js实现瀑布流效果
- js实现瀑布流效果
- js实现瀑布流排序加载效果
- 原生JS实现瀑布流效果
- JS实现的瀑布流效果
- js 瀑布流效果
- JS 瀑布流效果
- js的瀑布流效果
- 原生JS实现瀑布流及加载效果
- 利用JS实现简单的瀑布流效果
- js实现瀑布流效果(使用绝对定位)
- iOS转前端之JS实现瀑布流效果
- js实现瀑布流
- js实现瀑布流
- JS 实现瀑布流
- JS实现瀑布流
- JS 实现瀑布流
- 环形字符串比较-环状序列3.6circular sequence
- 队列和栈
- C++头文件的工作原理
- .net core使用MySQL笔记
- 关于盘口形态
- js实现瀑布流效果V2.0版本
- python3 生成可执行文件
- php的异常跳转的分析
- ORACLE in与exists语句的区别
- tomcat配置问题--j2ee学习
- Oracle启动过程突然连接失败
- container_of宏
- HTTP 状态响应码
- 在ubuntu下安装opencv配合qt工作及其中问题的解决