1.在线预览

在这里插入图片描述

2 文档结构

<el-container id="index">
    <!-- 点击图片详情弹窗 --><!-- :open="opmethod" -->
    <el-dialog :visible.sync="dialogVisible" :fullscreen="true" custom-class="el-dialog-aa" top="0"
    :show-close="false" @open="opmethod">
      <pic-detail ref="detailWin" :picId="picId" @closedialog="closedialog"></pic-detail>
    </el-dialog>
    <!-- 公共搜索头部,管理页面不显示 -->
    <el-header>
      <common-header @clickSearch='search'></common-header>
    </el-header>
    <!-- 主体瀑布流区域,无限滚动 -->
    <div class="v-waterfall-content" ref="abc" v-infinite-scroll="getMoreData" infinite-scroll-disabled="disabled"
      infinite-scroll-distance="10" style="overflow:auto">
      <div v-for="img in waterfallList" :key="img.key" class="v-waterfall-item"
      :style="{top:img.top+'px',left:img.left+'px',width:imageWidth+'px',height:img.height}">
        <!-- 图片卡片 -->
        <el-card shadow="hover" :body-style="{'padding':'0px','border-radius':'10px'}" @click.native="openDialog(img.id)">
          <!-- 图片懒加载 -->
          <el-image :src='img.src' class='image' :key='img.src' lazy>
            <!-- 加载前占位 -->
            <div slot="placeholder" class="image-slot">
              <div :style="{height:img.height+'px',width:imageWidth + 'px',backgroundColor:img.colour}"></div>
            </div>
            <!-- 加载失败占位 -->
            <div slot="error" class="image-slot">
              <div :style="{height:img.height+'px',width:imageWidth + 'px',backgroundColor:img.colour}"></div>
            </div>
          </el-image>
        </el-card>
      </div>
    </div>
  </el-container>

页面布局和UI全部使用的elementUI,很多代码都是抄人家的案例。
使用到的组件有:无限滚动,图片懒加载,图片占位,卡片,图片详情Dialog

3.重点 JS

import CommonHeader from '../components/CommonHeader.vue';
  import PicDetail from './pic/PicDetail.vue';

  const imgurl = 'http://103.45.251.27:8888/img/';
  export default {
    name: 'v-waterfall',
    components: {
      CommonHeader,
      PicDetail
    },
    data() {
      return {
        //存放计算好的数据
        waterfallList: [],
        //每一列的宽度
        imageWidth: 200,
        //多少列
        waterfallImgCol: 5,
        //右边距
        waterfallImgRight: 20,
        //下边距
        waterfallImgBottom: 10,
        //存放瀑布流各个列的高度
        waterfallColHeight: [],
        imgList: [],
        //整体左偏移量,左右相同
        colLeft: 0,
        currentPage: 1,
        //是否还有数据
        noMore: false,
        //搜索内容
        searchKey: '',
        //图片详情弹窗可见
        dialogVisible: false,
        //点击的图片ID
        picId:'',
        //随机占位色卡的颜色
        suijicolour: ['#b4ffe3','#66CDAA','#acc2e6','#d7b0d8','#95abe6','#ffc47b','#b6d288','#f49586','#bcaf7a'],
      };
    },
    created() {
      //初始就加载数据
      this.getMoreData();
    },
    mounted() {
      //计算可视区域能够容纳的最大列数,向下取整
      let fullWidth = this.$refs.abc.clientWidth;
      if (fullWidth > 1500) {
        this.imageWidth = 240;
      } else if (fullWidth < 800) {
        this.imageWidth = 170;
      }
      let maxColNum = Math.floor(fullWidth / (this.imageWidth + this.waterfallImgRight));
      console.log('可视宽度:' + fullWidth + ',列数:' + maxColNum);
      if (maxColNum == 0) {
        maxColNum = 1;
      }
      let contentWhith = (this.imageWidth + this.waterfallImgRight) * maxColNum;
      if ((fullWidth - contentWhith) < (this.imageWidth * 0.8)) {
        maxColNum--;
        contentWhith = (this.imageWidth + this.waterfallImgRight) * maxColNum;
      }
      console.log('计算列数:' + maxColNum);
      this.waterfallImgCol = maxColNum;
      //获取左边距
      this.colLeft = (fullWidth - contentWhith) / 2;
      console.log('总宽度:' + fullWidth + ',内容宽度:' + contentWhith + '左偏移:' + this.colLeft);
      //初始化偏移高度数组
      this.waterfallColHeight = new Array(this.waterfallImgCol);
      for (let i = 0; i < this.waterfallColHeight.length; i++) {
        this.waterfallColHeight[i] = 0;
      }
    },
    methods: {
      //搜索,从其他组件传值放到$store中的
      search() {
        //点击查询重置页数和瀑布流每列高度
        this.currentPage = 1;
        for (let i = 0; i < this.waterfallColHeight.length; i++) {
          this.waterfallColHeight[i] = 0;
        }
        this.waterfallList = [];
        this.getMoreData();
      },
      // 获取数据
      getMoreData() {
        //表单数据
        let param = {
          pageNo: this.currentPage++,
          pageSize: 10,
          orderBy: 'updateTime desc'
        };
        let search = this.$store.state.searchText;
        console.log('查询参数:' + search);
        if (search.trim().length > 0) {
          param.title = search.trim();
        }
        console.log('查询参数:' + JSON.stringify(param));
        // if(param.pageNo>10){this.noMore=true;return;}
        this.$axios.get('/api/pic/query', {
          params: param
        }).then(response => {
          // console.log('获取数据', response.data);
          if (response.data.success) {
            if (response.data.data.rows.length == 0) {
              this.noMore = true;
            } else {
              this.imgPreloading(response.data.data.rows);
              this.noMore = false;
            }
          } else {
            this.$message.error(response.data.msg);
            this.noMore = true;
          }
        }, response => {
          this.$message.error('错误');
          this.noMore = true;
        });
      },
      //图片预加载
      imgPreloading(moreList) {
        let listLen = this.waterfallList.length;
        for (let i = 0; i < moreList.length; i++) {
          if(moreList[i].imgUrl.indexOf('http') > 0){
            continue;
          }
          let aImg = new Image();
          //图片渲染列表,先把高宽和占位颜色赋值直接push到waterfallList,图片的实际url等图片加载上了在赋值
          let imgData = {};
          imgData.height = this.imageWidth / moreList[i].width * moreList[i].height;
          // console.log('第' + i + '张图片的高度是:'+imgData.height );
          imgData.id = moreList[i].id;
          //获取随机占位背景色
          imgData.colour=this.suijicolour[i%9];
          this.waterfallList.push(imgData);
          aImg.onload = (e) => {
              aImg.src = imgurl + moreList[i].imgUrl;
          };
          this.rankImg(imgData);
          imgData.src = imgurl + moreList[i].imgUrl;
        }
      },
      //瀑布流布局核心,计算高度和左偏移
      rankImg(imgData) {
        let {
          imageWidth,
          waterfallImgRight,
          waterfallImgBottom,
          waterfallColHeight,
          waterfallImgCol,
          colLeft
        } = this;
        //找出当前最短列的索引
        let minIndex = waterfallColHeight.indexOf(Math.min.apply(null, waterfallColHeight));
        //获取最短列底部高度,既下一张图片的顶部高度
        imgData.top = waterfallColHeight[minIndex];
        //计算左侧偏移,最短列索引*(右边距+列宽度)
        imgData.left = minIndex * (waterfallImgRight + imageWidth) + colLeft;
        //改变当前列高度
        waterfallColHeight[minIndex] += imgData.height + waterfallImgBottom;
        // console.log(imgData.key + ":" + JSON.stringify(imgData));
        // console.log(waterfallColHeight);
      },
      //打开图片详情
      openDialog(picId){
        this.picId = picId;
        this.dialogVisible = true;
        // this.$refs.detailWin.getInfo();
      },
      opmethod(){
        //打开详情页的回调,延迟加载详情页的数据,避免子组件的方法没找到
        setTimeout(() => {
              this.$refs.detailWin.getInfo();
            }, 10);
      },
      closedialog(){
        //关闭弹窗
        this.dialogVisible = false;
      }
    },
    computed: {
      disabled() {
        return this.noMore;
      }
    }
  };

公共搜索头部和图片详情弹窗可以都删掉
执行顺序 :
created 加载数据,
mounted 根据浏览器宽度计算好瀑布流的列数,左右间距
imgPreloading()拿到后端返回的数据,根据图片宽和高设置好占位色卡提前加载,等待图片onload完成赋值真实src

Logo

前往低代码交流专区

更多推荐