Vue瀑布流插件

我自己寫的一個的Vue瀑布流插件,列數自適應,不用設置每個卡片的高度。

測試頁面:Page.vue
模板頁面:WaterFollow.vue 和 WFColumn.vue

在Page.vue中,修改itemW的值,設置每列的最小寬度。例如:itemW="200"(意爲200px)。list爲數組。高度不用設置,:style="{height:item+'px'}"是我爲了創造卡片高度加上去的,不加就顯示卡片的原來大小。

經測試,created加載數據正常,mounted加載、更新數據正常。

Page.vue

<template>
  <div class="container">
    <w-f-column itemW="200">
      <template slot-scope="{columnNum,columnIndex}">
        <water-follow :list="list" :columnNum="columnNum" :columnIndex="columnIndex">
          <template slot-scope="{item,index}">
            <div class="my-box" :style="{height:item+'px'}">{{item}}-{{index}}</div>
          </template>
        </water-follow>
      </template>
    </w-f-column>
  </div>
</template>

<script>
import WFColumn from '../waterFollow/WFColumn'
import WaterFollow from '../waterFollow/WaterFollow'
export default {
  name: 'page',
  components: {WaterFollow, WFColumn},
  data () {
    return {
      list: []
    }
  },
  created () {
    // 有初始數據
    for (let i = 0; i < 50; i++) {
      this.list.push(Math.floor(Math.random() * 301 + 200))
    }
  },
  mounted () {
    // 模擬網絡請求
    // window.setTimeout(() => {
    //   this.list = []
    //   for (let i = 0; i < 50; i++) {
    //     this.list.push(Math.floor(Math.random() * 301 + 200))
    //   }
    // }, 1000)
    // -- 分割 --
    // 模擬數據不斷變化
    // window.setInterval(() => {
    //   this.list = []
    //   for (let i = 0; i < 50; i++) {
    //     this.list.push(Math.floor(Math.random() * 301 + 200))
    //   }
    // }, 1000)
  }
}
</script>

<style scoped lang="scss">
  .container{
    width: 100%;
    background: gray;
    .my-box{
      width: 200px;
      background: #000;
      margin-bottom: 20px;
      color: #fff;
    }
  }
</style>

WFColumn.vue

<template>
  <div class="wf-container">
    <div class="wf-column" v-for="(item,index) in columnNum" :key="'column-'+index" :name="index">
      <slot :columnNum="columnNum" :columnIndex="index"></slot>
    </div>
  </div>
</template>

<script>
export default {
  name: 'WFColumn',
  props: ['itemW'],
  data () {
    return {
      columnNum: 0
    }
  },
  created () {
    this.columnNum = Math.floor(document.body.clientWidth / this.itemW)
    window.onresize = () => {
      this.columnNum = Math.floor(document.body.clientWidth / this.itemW)
    }
  }
}
</script>

<style scoped lang="scss">
.wf-container{
  width: 100%;
  display: flex;
  .wf-column{
    flex: 1;
  }
}
</style>

WaterFollow.vue

<template>
  <div>
    <div v-for="(item,index) in list" :key="'item-'+index" class="item" :id="'card-'+columnIndex+'-'+index" v-if="load?(record[index].index===columnIndex):true">
      <slot :item="item" :index="index"></slot>
    </div>
  </div>
</template>

<script>
export default {
  name: 'WaterFollow',
  props: ['list', 'columnNum', 'columnIndex'],
  data () {
    return {
      column: 0,
      record: [],
      load: false,
      update: false
    }
  },
  methods: {
    calculateColumn () {
      let cList = []
      for (let i = 0; i < this.columnNum; i++) {
        cList.push(0)
      }
      for (let i = 0; i < this.record.length; i++) {
        let index = 0
        for (let j = 0; j < cList.length; j++) {
          if (cList[index] > cList[j]) {
            index = j
          }
        }
        cList[index] += this.record[i].height
        this.record[i].index = index
      }
    },
    recordInit () {
      for (let i = 0; i < this.list.length; i++) {
        this.record.push({index: -1, height: -1})
      }
    },
    initHeightData () {
      for (let i = 0; i < this.list.length; i++) {
        if (document.getElementById('card-' + this.columnIndex + '-' + i)) {
          let h = document.getElementById('card-' + this.columnIndex + '-' + i).offsetHeight
          this.record[i].height = h
        }
      }
    }
  },
  beforeCreate () {},
  created () {
    this.load = false
    this.recordInit()
  },
  beforeMount () {},
  mounted () {
    this.initHeightData()
    this.calculateColumn()
    this.load = true
  },
  beforeUpdate () {},
  updated () {
    if (this.update) {
      this.initHeightData()
      this.calculateColumn()
      this.update = false
      this.load = true
    }
  },
  beforeDestroy () {},
  destroyed () {},
  watch: {
    columnNum (curr, old) {
      this.calculateColumn()
    },
    list (curr, old) {
      console.log('list change')
      this.recordInit()
      this.load = false
      this.update = true
    }
  }
}
</script>

<style scoped>
</style>

多多指教!~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章