原生js实现瀑布流及微信小程序中使用左右两列实现瀑布流

两列实现瀑布流

Posted by Silence on August 3, 2017

使用css实现瀑布流并不实用,因为潮汕市实现的瀑布流都是以列来排列的,这里记录下用js实现瀑布流,以及微信小程序中使用左右两列来实现瀑布流

效果图

io

原生js实现瀑布流

  • html文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<div id="root">
    <div class="item">
        <div class="itemImg">
            <img src="../images/1.jpeg" alt="" />
        </div>
    </div>
    <div class="item">
        <div class="itemImg">
            <img src="../images/3.jpeg" alt="" />
        </div>
    </div>
    <div class="item">
        <div class="itemImg">
            <img src="../images/2.jpg" alt="" />
        </div>
    </div>
</div>
  • 图片可以自己找点替换下就可以了

  • css文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
*{
    margin: 0;
    padding: 0;
}
#root{
    position: relative;
}
.item{
    float: left;
    padding: 5px;
}
/* 添加阴影的时候,加上border会显得更加有点悬浮感 */
.itemImg{
    padding: 5px;
    border: 1px solid #ccc;
    box-shadow: 0 0 5px #ccc;
    border-radius: 5px;
}
.itemImg img{
    width: 230px;
    height: auto;
}
  • js文件
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
151
152
153
154
window.onload = function () {

    /* 计算图片列数及获取最小高度图片 */
    generateImg('root', 'item');

    /* 对窗口大小改变进行监听,大小改变则重新布局 */
    window.addEventListener('resize', function() {
        generateImg('root', 'item')
    });

    /* 图片对象 */
    let imgData = {
        images: [
            {
                "src":"23.png"
            },
            {
                "src":"22.png"
            },
            {
                "src":"2.jpg"
            },
            {
                "src":"4.jpg"
            },
            {
                "src":"7.jpg"
            }
        ]
    };
    /* 对滚动监听 */
    window.addEventListener('scroll', function() {
        if(checkIsScroll()) {
            let rootElement = document.getElementById('root');
            /* 利用documentFragment来创建 */
            // let documentFragment = document.createDocumentFragment();
            let length = imgData.images.length;

            /* 循环创建图片组 */
            for(let i = 0; i < length; i++) {
                let itemElement = document.createElement('div');
                itemElement.className = 'item';
                rootElement.appendChild(itemElement);
                let itemImgElement = document.createElement('div');
                itemImgElement.className = 'itemImg';
                itemElement.appendChild(itemImgElement);
                let itemImg = document.createElement('img');
                itemImg.style.cssText = 'opacity: 0; transform:scale(0)';
                itemImg.src = "../images/" + imgData.images[i].src;
                itemImgElement.appendChild(itemImg);
                //  documentFragment.appendChild(itemElement);

                /* 在1秒后让图片显示出来 */
                (function(img){
                    setTimeout(function(){
                        img.style.cssText="opacity:1;transform:scale(1)";
                    },1000);
                })(itemImg);
            }
            // rootElement.appendChild(documentFragment);
            generateImg('root', 'item');
        }
    });
};

/* 计算图片列数及获取最小高度图片 */
function generateImg(parent, content) {
    /* 获取父元素及其所以节点内容 */
    let parentElement = document.getElementById(parent);
    let childContent = getChildElement(parentElement, content);

    /* 获取图片宽度 */
    let imgWidth = childContent[0].offsetWidth;
    /* 获取一行图片形成的列数 */
    let imgColumn = Math.floor(document.documentElement.clientWidth / imgWidth);
    /* 重新设置父级容器的宽度 */
    parentElement.style.cssText = 'width:' + imgColumn * imgWidth + 'px;margin:0 auto';

    /* 存储每个图片的高度,以此来找到最小图片高 */
    let imgHeightArray = [];
    let length = childContent.length;
    for(let i = 0; i < length; i++) {
        /* i<imgColumn统计每一行的图片高度 */
        if(i < imgColumn) {
            /* 防止用户改变窗口大小时,内容样式错乱 */
            childContent[i].style.cssText = '';
            imgHeightArray.push(childContent[i].offsetHeight);
        } else {
            /* 如果不是这一行的,则找到最小值和最小值的索引值 */
            let minHeight = getMinImgHeight(imgHeightArray);
            let minHeightIndex = getMinHeightIndex(imgHeightArray, minHeight);
            /* 对这个图片设置位置 */
            childContent[i].style.position = 'absolute';
            childContent[i].style.top = minHeight + 'px';
            childContent[i].style.left = childContent[minHeightIndex].offsetLeft + 'px';
            /* 更换此时的最小高度 */
            imgHeightArray[minHeightIndex] = childContent[i].offsetHeight + minHeight;
        }
    }
}

/* 检测滚动是否达到了可视区 */
function checkIsScroll() {
    /* 获取root根节点 */
    let parentElement = document.getElementById('root');
    /* 获取父元素下的类名为box的元素节点 */
    let childContent = getChildElement(parentElement, 'item');

    /* 获取最后一个元素的高度 */
    let lastElementHeight = childContent[childContent.length - 1].offsetTop;
    /* 获取滚动的距离 */
    let scrollTopSpace = document.documentElement.scrollTop || document.body.scrollTop;
    /* 获取可视区的距离 */
    let clientHeight = document.documentElement.clientHeight || document.body.clientHeight;

    if(lastElementHeight > scrollTopSpace + clientHeight) {
        return true;
    }
}
/* 获取子节点的所有内容 */
function getChildElement(parentElement, content) {
    /* 存储元素信息 */
    let elementArray = [];
    /* 获取父元素下的所有节点信息 */
    let allElement = parentElement.getElementsByTagName('*');
    let length = allElement.length;
    for (let i = 0; i < length; i++) {
        /* 找到对应的类名 */
        if (allElement[i].className === content) {
            elementArray.push(allElement[i]);
        }
    }
    return elementArray;
}

/* 获取图片最小高度 */
function getMinImgHeight(heightArray) {
    let length = heightArray.length;
    let minHeight = heightArray[0];
    for(let i = 0; i < length; i++) {
        minHeight = Math.min(minHeight, heightArray[i]);
    }
    return minHeight;
}

/* 获取图片最小高度的索引值 */
function getMinHeightIndex(heightArray, minHeight) {
    let length = heightArray.length;
    for(let i = 0; i < length; i++) {
        if(heightArray[i] == minHeight) {
            return i;
        }
    }
}

微信小程序中实现瀑布流

  • 效果图

io

  • wxml文件
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
<view class="cateCommodity">
  <view class="leftContainer">
    <block wx:for="" wx:key="">
      <view class="cateItem" wx:if="">
        <view class="item">
          <image src="" class="itemImg" mode="widthFix"></image>
          <view class="title"></view>
        </view>
      </view>
    </block>
  </view>
  <view class="rightContainer">
    <block wx:for="" wx:key="">
      <view class="cateItem" wx:if="">
        <view class="item">
          <image src="" class="itemImg" mode="widthFix"></image>
          <view class="title"></view>
        </view>
      </view>
    </block>
  </view>
</view>
<view class="skipTop" catchtap="skipTop" wx:if="">
  <image src="http://boweisou.oss-cn-shenzhen.aliyuncs.com/images/0/2018/11/ZBtqujbbcGjBDgjt0bbJqbTuGqq0z8.png"></image>
</view>
  • wxss文件
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
page{
  background: #f6f6f6;
}
/* 最外层 */
.cateCommodity {
  display: flex;
  padding: 20rpx 28rpx 8rpx;
  box-sizing: border-box;
  font-size: 28rpx;
}
/* 左右两个容器 */
.leftContainer{
  display: flex;
  margin-right: 22rpx;
  flex-direction: column;
}
.rightContainer{
  display: flex;
  flex-direction: column;
}
/* 图片容器 */
.cateItem {
  margin-bottom: 20rpx;
}
.item{
  padding: 20rpx 22rpx;
  width: 335rpx;
  box-sizing: border-box;
  background: #fff;
  border-radius: 6rpx;
}
.itemImg{
  margin-bottom: 14rpx;
  width: 100%;
  vertical-align: middle;
  border-radius: 6rpx;
}
.title{
  display: -webkit-box;
  overflow: hidden;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  line-height: 1.5;
}
/* 返回顶部 */
.skipTop {
  position: fixed;
  bottom: 30rpx;
  right: 20rpx;
  width: 90rpx;
  height: 90rpx;
}

.skipTop image {
  width: 100%;
  height: 100%;
  vertical-align: middle;
}

  • js文件
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
Page({
  data: {
    imageArray: [
      {
        id: 1,
        src: '../../images/avatar.jpeg',
        title: '现代新中式创意陶瓷简约摆件客厅家居玄关软装饰品家居酒柜盘子'
      },
      {
        id: 1,
        src: '../../images/avatar3.jpg',
        title: '秋冬季新款2018休闲运动服套装女士韩版金丝绒卫衣加绒加厚两件套'
      },
      {
        id: 1,
        src: '../../images/avatar4.jpeg',
        title: '女童床上用品四件套公主房1.2m床品纯棉女孩1.8儿童床单三件套1.5'
      },
      {
        id: 1,
        src: '../../images/avatar7.jpg',
        title: '婴儿床圆床蚊帐落地款宝宝椭圆床蚊帐支架款儿童床蚊帐BB床小蚊帐'
      },
      {
        id: 1,
        src: '../../images/avatar9.jpeg',
        title: '包邮动感158T速滑鞋轮滑鞋竞速鞋高端碳纤鞋 固定码 专业定制'
      },
      {
        id: 1,
        src: '../../images/logo7.jpg',
        title: 'Infanton落地婴儿床蚊帐带支架儿童床蚊帐宝宝蚊帐婴童蚊帐'
      },
      {
        id: 1,
        src: '../../images/logo6.jpg',
        title: '老A轮滑 米高seba hl碳纤版SEBA HL CARBON 平花鞋刹车鞋全能鞋'
      },
      {
        id: 1,
        src: '../../images/logo.jpeg',
        title: '洋洋法代 sandro 17秋冬 一粒扣羊毛长款大衣外套EKIN M9575H'
      },
    ],
    showTopImage: false,
  },
  onPageScroll(event) {
    /* 利用两个条件,防止重复的进行setData操作 */
    if (event.scrollTop > 300 && this.data.showTopImage == false) {
      this.setData({
        showTopImage: true
      })
    } else if (event.scrollTop < 300 && this.data.showTopImage == true) {
      this.setData({
        showTopImage: false
      })
    }
  },
  skipTop() {
    /* 返回顶部 */
    wx.pageScrollTo({
      scrollTop: 0,
      duration: 300
    });
    this.setData({
      showTopImage: false
    });
  },
  onReachBottom: function () {
    let temporaryArray = this.data.imageArray;
    temporaryArray.push(...this.data.imageArray);
    this.setData({
      imageArray: temporaryArray
    })
  },
})
  • 左右两列实现瀑布流其实就是对同一数组进行了两次渲染,只是把其中的一半给隐藏了