uniapp实现微信-H5-瀑布流与单全选功能

1,171 阅读1分钟

一、项目描述

  • 使用框架uniapp,需要兼容微信小程序H5
  • 实现功能相册瀑布流多选-全选功能 实现效果:

image.png

实现思路

1.函数说明:传入一个数组,循环获取图片高度,会根据把原数组拆分成两个数组,放在两列,
1.计算单列累计高度,对比高度值的大小,实现瀑布流的布局,
1.由于获取图片高度需要一定的时间,所以使用async await 阻塞for 循环的进程,
1.每获取到一个图片的高度就赋值渲染到页面上,实现加载出一个图片就先渲染上去,达成图片懒加载的效果

代码实现

1.封装waterFall页面组件

  • HTML:
//通过使用scroll-view实现
<scroll-view
   style="height: 490px; overflow: hidden;"
   scroll-y="true"
   class="scroll-Y"
   @scrolltolower="loadMoreImages"
>
   // 内容主体
   <view class="main">
   //相册左半部
      <div class="view Left">
         <div class="content" v-for="(item, index) in firstList" :key="index">
            <div class="img-content">
                <image v-if="item.small_img" :src="item.small_img" class="image"
                    mode="widthFix" :data-index="index" data-type="1"/>
                    
            <div v-if="select" 
              :class="['select-ele',{ selected: selectList.includes(item) },]"
              @click="selected(item)"
            >
        <div class="checkbox iconfont"></div>
     </div> 
   </div>
  </div>
</div>
//相册右侧
<div class="view Right">
    <div
    	class="content"
    	v-for="(item, index) in secondList"
    	:key="index"
    >
    	<div class="img-content">
    		<image
    		   v-if="item.small_img"
    		   :src="item.small_img"
    		   class="image"
    		   mode="widthFix"
    		   :data-index="index"
    		   data-type="2"
    		/>
	<div
	    v-if="select"
	    :class="['select-ele',{ selected: selectList.includes(item) },]"
	    @click="selected(item)"
	>
	<div class="checkbox iconfont"></div>
     </div>
   </div>
  </div>
</div>
    <div class="footer" v-if="select">
    <div class="all-check" @click="selectAll">
    <div:class="['checkbox iconfont',{ selected: allSelected },]"></div>
    <span>全选</span>
    </div>
    <div class="func-btn" @click="cancel">取消</div>
    <div class="func-btn confirm" @click="confirm">确认</div>
</div>
</view>
</scroll-view>
  • 2.多选/全选实现思路
    • 1.通过设置Css样式动态绑定点击相册的每一项
    • 1.调用@click="selected(item)"方法获取点击相册数据
    • 2.调用@click="selectAll" 方法获取相册全部数据
  • Js:
<script>
  import { myPhotos } from "@/api/api";
  export default {
  	props: {
  		select: {
  			type: Boolean,
  			default: false,
  		},
  	},
  	data() {
		return {
			showImg: false,
			dataList: [], // 数据源
			firstList: [], // 第一列数组
			secondList: [], // 第二列数组
			windowWidth: 0, // 页面视图宽度
			windowHeight: 0, // 视图高度
			imgMargin: 0, // 图片边距: 单位px
			imgWidth: 0, // 图片宽度: 单位px
			pageSize: 8,
			scrollHeight: "0",
			last: false,
			page: 1,
			like: true,
			i: 0,
			photoParams: {
				type: 4, // 1购买 2打赏 3点赞 4有我的图片
				page: 1,
				size: 10,
			},
			selectList: [],
		};
	},
    mounted() {
            // 我是在组件中获取数据,逻辑需求不同,可以选择传进
            this.getGoodthingList();
    },
    created() {
            // 后期获取滚动条的长度-小伙伴们可以删除
            this.init();
            this.initScrollHeight();
    },
    //通过计算获取所有图片数据
    computed: {
            allSelected: {
                    get() {
                            return this.selectList.length >= this.dataList.length;
                    },
                    set(val) {
                            if (val) {
                                    console.log(val);
                                    this.selectList = [...this.dataList];
                            } else {
                                    this.selectList = [];
                            }
                    },
            },
    },

    methods: {
            //获取多选数据
            selected(item) {
                    const index = this.selectList.findIndex(
                            (i) => i.id === item.id
                    );
                    if (index >= 0) {
                            this.selectList.splice(index, 1);
                            this.selectList = [...this.selectList];
                    } else {
                            this.selectList.push(item);
                    }
            },
            selectAll() {
                    this.allSelected = !this.allSelected;
            },
            cancel() {
                    this.selectList = [];
                    this.$emit("parentBtnSelect", false);
                    this.$emit("cancel");
            },
            confirm() {
                    if (!this.selectList.length) {
                            uni.showToast({ title: "请选择图片", icon: "none" });
                            return;
                    }
                    console.log(this.selectList, "this.selectList");
                    this.$emit("confirm", this.selectList);
                    this.selectList = [];
                    this.$emit("parentBtnSelect", false);
            },
            init() {
                    this.dataList = [];
                    this.firstList = [];
                    this.secondList = [];
                    this.last = false;
                    this.imgMargin = 0; // 图片边距: 单位px
                    this.pageSize = 8;
                    this.page = 1;
                    this.i = 0;
                    // debugger
            },
            initScrollHeight() {
                    let _self = this;
                    uni.getSystemInfo({
                            success: function(res) {
                                    _self.scrollHeight = res.windowHeight + "px" / 2;
                            },
                    });
            },
            // 获取数据
            getGoodthingList() {
                    myPhotos(this.photoParams).then((res) => {
                            if (res.data.code == 1) {
                                    if (res.data.result.pics == null) {
                                            return uni.showToast({
                                                    title: "非常抱歉没有找到相关信息",
                                                    icon: "none",
                                            });
                                    }
                                    this.photoParams.page++;
                                    uni.hideLoading();
                                    this.last = res.data.success || false;
                                    //拼接获取数据
                                    this.dataList = [
                                            ...this.dataList,
                                            ...res.data.result.pics,
                                    ];
                                    this.setDataList(res.data.result.pics,"small_img");
                            }
                    });
            },
        //计算图片的长宽
        async setDataList(
                arr = data,
                attributeName,
                otherHeight = 100,
                minHeight = 10,
                maxHeight = 1000
        ) {
                var arr1 = [],
                    arr2 = [],
                    imgMargin = 0, //图片边距
                    height1 = 0, //第一组图片累计高度
                    height2 = 0; //第二组图片累计高度
                // var getSystemInfo = await wx.getSystemInfo()
                for (let i = 0; i < arr.length; i++) {
                       try {
                             let heightData = await uni.getImageInfo({src: "https:" + arr[i][attributeName],
                           });
                            let ImgHeight =
                            heightData.length == 1? minHeight: heightData[1].height; 
                           //如果长度等于1,就是图片有问题,这时候设置一个默认高度,如果长度等于                                          2,下标1就有图片高度
                             let imgWidth =
				heightData.length == 1? minHeight: heightData[1].width;                                 //如果长度等于1,就是图片有问题,

                             let height = ImgHeight;
                             if (height < minHeight) height = minHeight;
                             if (height > maxHeight) height = maxHeight;

                             if (height1 <= height2) {
                                     height1 += height;
                                     this.firstList.push(arr[i]);
                             } else {
                                     height2 += height;
                                     this.secondList.push(arr[i]);
                             }
                            // console.log('arr2',height1,height2,arr1,arr2);
			     } catch (err) {
				console.log("getImageInfo-err", err);
				}
			      }
			},
			// 加载更多图片
			loadMoreImages: function() {
				if (!this.last) {
					uni.showLoading({
						title: "加载中...",
					});
					this.getGoodthingList();
				} else {
					this.getGoodthingList();
				}
				uni.hideLoading();
			},
		},
	};
</script>
  • CSS
<style scoped lang="scss">
	.page {
		width: 100%;
	}

	.main {
		width: 100%;
		.view {
			width: 50%;
			display: inline-block !important;
			position: relative;
			vertical-align: top;
			padding: 5rpx;
			box-sizing: border-box;

			.content {
				border-radius: 4px;
				margin-bottom: 6rpx;
				box-sizing: border-box;
				.img-content {
					position: relative;
					.image {
						width: 100%;
						height: 100%;
						border-top-right-radius: 4px;
						border-top-left-radius: 4px;
						box-sizing: border-box;
						display: block;
					}
				}
			}
			.select-ele {
				position: absolute;
				left: 0;
				top: 0;
				width: 100%;
				height: 100%;
				&.selected {
					background-color: rgba(255, 255, 255, 0.3);
					.checkbox {
						display: flex;
						align-items: center;
						justify-content: center;
						background-color: #2147f1;
						border-color: #2147f1;
						&::before {
							content: "\e62d";
							font-size: 20rpx;
							color: #fff;
						}
					}
				}
				.checkbox {
					position: absolute;
					right: 18rpx;
					top: 18rpx;
					width: 36rpx;
					height: 36rpx;
					border-radius: 4rpx;
					border: 2rpx solid #ffffff;
				}
			}
		}
		.footer {
			position: fixed;
			left: 0;
			bottom: 0;
			display: flex;
			align-items: center;
			justify-content: flex-end;
			width: 100%;
			height: 100rpx;
			background-color: #fff;
			z-index: 22;
			.all-check {
				position: absolute;
				left: 30rpx;
				display: flex;
				align-items: center;
				font-size: 26rpx;
				font-weight: 400;
				color: #666666;
				line-height: 39rpx;
				.checkbox {
					width: 36rpx;
					height: 36rpx;
					margin-right: 14rpx;
					border-radius: 4rpx;
					border: 2rpx solid #bababa;
					&.selected {
						display: flex;
						align-items: center;
						justify-content: center;
						background-color: #2147f1;
						border-color: #2147f1;
						&::before {
							content: "\e62d";
							font-size: 20rpx;
							color: #fff;
						}
					}
				}
			}
			.func-btn {
				width: 220rpx;
				height: 70rpx;
				margin-right: 30rpx;
				font-size: 30rpx;
				font-weight: 500;
				color: #666666;
				line-height: 70rpx;
				text-align: center;
				background: #ececec;
				border-radius: 35rpx;
				&.confirm {
					color: #fff;
					background: #dd4e4e;
				}
			}
		}
	}
</style>