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;    }}



       

0 0
原创粉丝点击