zoukankan      html  css  js  c++  java
  • vue2.0的瀑布流组件-使用说明

    做一个小项目,需要瀑布流,就选他了,先看看效果

    使用瀑布流布局组件:vue-waterfall-easy
        下载引入:
            方式一:直接从git上复制组件的完整代码,引入vue组件文件即可
                import vueWaterfallEasy from '你的路径/组件名.vue'
                
            方式二:通过npm全局安装:cnpm install vue-waterfall-easy --save-dev
                import vueWaterfallEasy from 'vue-waterfall-easy'
            
            报错注意: 
                Cannot find module 'pug'   原因是:没有安装pug模块,安装:cnpm install --save pug        或去除:lang='pug'
                sass-loader没安装:        解决:安装sass或修改sass为less
    
        注册:
            要在当前组件中注册该组件:export default { components:{vueWaterfallEasy}}

    组件的使用:

    <template>
      <div id="all_user">
        <div class="search_box">
          <input type="text" placeholder="请输入编号或名称"><button><i class="tt tt-quanburen"></i>搜索</button>
        </div>
    
        <vueWaterfallEasy :imgsArr="imgsArr" @scrollLoadImg="fetchImgsData">
          <template slot-scope="props">
            <div class="player_info">
                <div class="title"><i class="tt tt-quanburen"></i>{{props.value.info}}</div>
                <div class="ticket">
                  <mt-button @click="upLoadTicket(props.value.id)" size="small"><i class="tt tt-quanburen"></i>投票</mt-button>
                </div>
                <p class="num">{{props.index+1}}票</p>
              </div>
          </template>
        </vueWaterfallEasy>
      </div>
    </template>
    
    <script>
    import vueWaterfallEasy from './Waterfall/vue-waterfall-easy.vue'
    
    export default {
      name: 'app',
      data() {
        return {
          imgsArr: [],
          fetchImgsArr: []
        }
      },
      components: {
        vueWaterfallEasy
      },
      methods: {
        // 假数据
        initImgsArr(n, m) { //num 图片数量
          var arr = []
          for (var i = n; i < m; i++) {
            arr.push({ id:i,src: `./src/assets/images_test/${i + 1}.jpg`, link: 'https://www.baidu.com', info: '一些图片描述文字' })
          }
          return arr
        },
    
        fetchImgsData() {
          this.imgsArr = this.imgsArr.concat(this.fetchImgsArr)
        },
    
        upLoadTicket(index){ //投票按钮
          console.log(index);
        }
      },
      created() {
        this.imgsArr = this.initImgsArr(0, 5)
        this.fetchImgsArr = this.initImgsArr(5, 10) // 模拟每次请求的新的图片的数据数据
      },
    
    }
    
    </script>

    vue-waterfall-easy.vue组件

    <!-- —————————————↓SCSS———————分界线————————————————————————— -->
    <style lang="less">
    .vue-waterfall-easy {
      position: relative;
       100%; // 移动端生效
      .img-box {
        display: inline-block;
         50%; // 移动端生效
        box-sizing: border-box;
        float: left; // 首行排版
        transition: left 1s, top 1s;
    
        .img-inner-box {
          box-shadow: 0 1px 3px rgba(0, 0, 0, .3);
          .img-wraper {
             100%;
            background: yellow;
          }
          img {
             100%;
            vertical-align: bottom;
          }
          .img-info {
            background: #fff;
            // padding: .6em;
          }
        }
      }
      .loading {
        text-align: center;
         100%;
        position: fixed;
        bottom: 10px;
        left: 50%;
        margin-left: -15px;
         30px;
        height: 30px;
      }
      .loading.first-loading {
        //  首次预加载白屏,让加载动画处于中间
        top: 50%;
        margin-top: -15px;
      }
      .double-bounce1,
      .double-bounce2 {
         100%;
        height: 100%;
        border-radius: 50%;
        background-color: #67CF22;
        opacity: 0.6;
        position: absolute;
        top: 0;
        left: 0;
    
        animation: bounce 2.0s infinite ease-in-out;
      }
    
      .double-bounce2 {
        animation-delay: -1.0s;
      }
    
    
    
      @keyframes bounce {
        0%,
        100% {
          transform: scale(0.0);
        }
        50% {
          transform: scale(1.0);
        }
      }
    }
    </style>
    
    <!-- —————————————↓HTML————————分界线———————————————————————— -->
    <template lang="pug">
    .vue-waterfall-easy(
      :style="isMobile? '':{colWidth*columnCount+'px',left:'50%',marginLeft: -1*colWidth*columnCount/2 +'px'}"
    )
      div.img-box(
        v-for="(v,i) in imgsArrC",
        :style="{padding:gap/2+'px', isMobile ? '' : colWidth+'px'}"
      )
        .img-inner-box
          //- div.img-wraper(:style="{imgWidthC+'px',height:v.height?v.height+'px':''}")
          a.img-wraper(
            :style="{'100%',height:v.height?'auto':''}"
            :href="v.link"
          )
            img(:src="v.src")
          div.img-info
            slot(:index="i",:value="v")
    
      .loading(v-if="isPreloadingC",:class="{'first-loading':isFirstTIme}")
        div.double-bounce1
        div.double-bounce2
    
    
    </template>
    
    <!-- ——————————————↓JS—————————分界线———————————————————————— -->
    <script>
    //import XXX from './components/XXX'
    
    export default {
      name: 'vue-waterfall-easy',
      //组件参数
      props: {    
        gap: {    //图片间隔
          type: Number, 
          default: 10
        },
        maxCols: {    //最大的列数
          type: Number,
          default: 5
        },
        imgsArr: {    //请求返回的图片数据
          type: Array,
          required: true
        },
        imgWidth: {   //制定图片的同一宽度
          type: Number,
          default: 240
        },
        timeOut: { // 预加载事件小于500毫秒就不显示加载动画,增加用户体验
          type: Number,
          default: 500
        }
      },
      data() {
        return {
          msg: 'this is from vue-waterfall-easy.vue',
          columnCount: NaN, // 列数,根据窗口大小初始化
          isMobile: navigator.userAgent.match(/(iPhone|iPod|Android|ios)/i), // 初始化移动端
          beginIndex: NaN, // 第二列首张图片的index,从这一张开始重新计算图片位置
    
          colsHeightArr: [], // 每一列的图片总和高度为元素组成的数组
          imgBoxEls: null, // 所有的.img-box元素
          isPreloading: true, // 预加载状态中(1.以等待图片替换 2.图片全部预加载完显示)
          isPreloadingC: true,
          imgsArrC: [], // 预加载完之后再才开始
          loadedCount: 0, // 已经加载图片数量
          isFirstTIme: true, // 首次加载
        }
      },
      computed: {
        colWidth() { // 每一列的宽度
          return this.imgWidth + this.gap
        },
        imgWidthC() { // 对于移动端重新计算图片宽度
          return this.isMobile ? window.innerWidth / 2 - this.gap*2 : this.imgWidth
        }
      },
      methods: {
        waterfall() { // 执行瀑布布局
          for (var i = this.beginIndex; i < this.imgsArr.length; i++) {
            var minHeight = Math.min.apply(null, this.colsHeightArr) // 最低高低
            var minIndex = this.colsHeightArr.indexOf(minHeight) // 最低高度的索引
            var width = this.imgBoxEls[0].offsetWidth // 图片的宽度获取
            // 设置元素定位的位置
            this.imgBoxEls[i].style.position = 'absolute'
            this.imgBoxEls[i].style.left = minIndex * width + 'px'
            this.imgBoxEls[i].style.top = minHeight + 'px'
    
            // 更新colsHeightArr
            this.$set(this.colsHeightArr, minIndex, minHeight + this.imgBoxEls[i].offsetHeight)
          }
          this.beginIndex = this.imgsArr.length
        },
    
        loadFn(e, oImg, i) { // 每张图片预加载完成执行函数
          this.loadedCount++
          if (e.type === 'load') { // 使用图片原始宽度计算图片的高度
            this.$set(this.imgsArr[i], 'height', Math.round(this.imgWidthC / (oImg.width / oImg.height)))
          }
          if (this.loadedCount === this.imgsArr.length) {
            this.imgsArrC = this.imgsArr.concat([])
    
    
            this.isPreloading = false
            this.isFirstTIme = false
    
            // 预加载完毕
            this.$nextTick(() => {
              this.initImgBoxEls()
              this.$emit('preloaded')
    
            })
          }
        },
        preload() {
          this.imgsArr.forEach((v, i) => {
            if (i < this.loadedCount) return
    
            var oImg = new Image()
            oImg.addEventListener('load', (e) => {
              this.loadFn(e, oImg, i)
            })
            oImg.src = v.src
          })
        },
    
    
        // -----------------初始化化------------------------
    
        initColsHeightArr() { // 第一行元素的高度组成的数组-初始化
          this.colsHeightArr = [] // 列数发生变化重新初始化
          for (var i = 0; i < this.columnCount; i++) {
            this.imgBoxEls[i].style.position = 'static' // 重置下position
            var height = this.imgBoxEls[i].offsetHeight
            this.colsHeightArr.push(height)
          }
        },
        initImgBoxEls() { // 初始化所有装图片的元素集合,注意高度获取需要在图片加载完成之后,所以在window.onload 事件中初始化
          this.imgBoxEls = document.getElementsByClassName('img-box')
        },
    
        initColumnCount() { // 列数初始化
    
          var winWidth = window.innerWidth
          var columnCount = parseInt(winWidth / this.colWidth)
          columnCount = columnCount === 0 ? 1 : columnCount
          this.columnCount = this.isMobile
            ? 2
            : (columnCount > this.maxCols ? this.maxCols : columnCount)
    
        },
      },
      mounted() {
        // ==1== 根据窗口大小初始化列数
        this.initColumnCount()
        this.beginIndex = this.columnCount // 开始排列的元素索引
    
        // ==2== 根据预加载完成的图片的长宽比,计算图片的高度
        this.preload()
    
        this.$on('preloaded', () => {
          if (this.colsHeightArr.length === 0) this.initColsHeightArr() // 第一次初始化
          this.waterfall()
        })
    
        window.addEventListener('resize', () => {
          var old = this.columnCount
          this.initColumnCount()
          if (old === this.columnCount) return // 列数不变直接退出
          this.beginIndex = this.columnCount // 开始排列的元素索引
    
          this.initColsHeightArr()
          this.waterfall()
    
    
        })
          // console.log(this.$el.parentNode)
          // console.log(this.$el.parentNode, this.$el.parentNode.scrollTop + this.$el.parentNode.offsetHeight, this.$el.parentNode.scrollHeight)
    
        this.$el.parentNode.addEventListener('scroll', () => {
          if (this.isPreloading) return
          const lastImgHeight = this.imgsArr[this.imgsArr.length - 1].height
          // console.log(this.$el.parentNode, this.$el.parentNode.scrollTop + this.$el.parentNode.offsetHeight, this.$el.parentNode.scrollHeight)
          
          if (this.$el.parentNode.scrollTop + this.$el.parentNode.offsetHeight > this.$el.parentNode.scrollHeight - lastImgHeight) {
            this.$emit('scrollLoadImg')
            console.log('加载');
          }
        })
    
      },
      watch: {
        imgsArr(newV, oldV) {
          if (newV.length === oldV.length) return
          this.isPreloading = true // 预加载新的图片资源
          this.preload()
    
          // setTimeout(()=>{ // 模拟图片预加载时间为1s
    
          // this.preload()
          // },1000)
    
        },
        isPreloading(v) {
          if (v) {
            setTimeout(() => {
              if (!this.isPreloading) return // 500毫秒内预加载完图片则不显示加载动画
              this.isPreloadingC = true
            }, this.timeOut)
          } else {
            this.isPreloadingC = false
          }
    
        }
      }
    }
    </script>
  • 相关阅读:
    【模板】Sparse-Table
    UVa 11235 Frequent values
    【模板】树状数组
    UVa 1428 Ping pong
    数学技巧
    UVa 11300 Spreading the Wealth
    UVa 11729 Commando War
    UVa 11292 Dragon of Loowater
    POJ 3627 Bookshelf
    POJ 1056 IMMEDIATE DECODABILITY
  • 原文地址:https://www.cnblogs.com/LChenglong/p/8073332.html
Copyright © 2011-2022 走看看