<div id="app">
  <span>设置列数:{{colCount}}<input type="range" min="2" max="5" v-model="colCount"></span>
  <div class="photos" >
    <div class="col" v-for="(col,idx) in cols" :key="idx">
       <img class="photo" :src="photo" v-for="photo in col" :key="photo">
    </div>
  </div>
</div>
.photos{
  display: flex;
  flex-flow: row;
  justify-items: center;
  width: 750px;
}
.col{
  width: 50%;
}
.photo{
  display:block;
  margin:5px;
  object-fit:none;
}
function rnd(min, max) {
  return min + ~~((max-min)*Math.random())
}
function dp(ws, vs, limit) {
  let len = ws.length;
    let tables = new Array(len).fill().map(x => [])
  tables[-1] = new Array(limit + 1).fill(0);

    for(let i = 0; i < len; i++) {
        for (let w = 0; w <= limit; w++) {
            if (ws[i] > w) {
                tables[i][w] = tables[i-1][w]
            } else {
                tables[i][w] = Math.max(tables[i-1][w], tables[i-1][w-ws[i]] + vs[i])
            }
        }
    }
    // 回溯得到应该选哪些
    let max = limit;
    let selected = [];
    for (let idx = len - 1; idx >= 0; idx--) {
        if (ws[idx] <= max) {
            let isSelected = tables[idx-1][max] < tables[idx-1][max-ws[idx]] + vs[idx]
            if(isSelected) {
                selected.push(idx);
                max = max - ws[idx];
            }
        }
    }
    return selected;
}
let app = new Vue({
  data: {
    colCount: 5,
    cols: [],
    photoHeights: []
  },
  created() {
    this.photos = Array.from({length: 50}).map((v,i) => {
      let height = rnd(100, 300)
      this.photoHeights.push(height + 10)
      return Mock.Random.dataImage('150x' + height, i)
    })
    this.computeColumns()
  },
  methods: {
      computeColumns() {
        this.cols = []
    let photos = this.photos
    
      let photoHeights = JSON.parse(JSON.stringify(this.photoHeights))
      let total = photoHeights.reduce((prev, curr) => prev + curr, 0)
      let aver = Math.floor(total / this.colCount)
      
      let colCount = this.colCount
      while(colCount--) {
          let idxs = dp(photoHeights, photoHeights, aver)
          let photoCol = photos.filter((p,idx) => idxs.includes(idx)) 
          this.cols.push(photoCol)
        // 不能直接改变photoHeights
        photoHeights.forEach((v,i) => {
          if (idxs.includes(i)) {
            photoHeights[i] = null
          }
        })
      }
   },
  },
  watch: {
    colCount() {
      this.computeColumns()
    }
  }
})
app.$mount(document.getElementById('app'));

console.log(app)

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.10/vue.js
  2. https://cdnjs.cloudflare.com/ajax/libs/Mock.js/1.0.0/mock-min.js