my-img-wall/src/ImgWall.vue

<template>
 
  <Horizontal v-if="isHorizontal" ref="imgWall" v-bind="$attrs">
    <template v-slot:image="{scope}"> 
      <slot name="image" :scope="scope.item"></slot>
    </template>
    <template v-slot:content="{scope}"> 
      <slot name="content" :scope="scope.item"></slot>
    </template> 
  </Horizontal>

  <Vertical v-else ref="imgWall" v-bind="$attrs">
    <template v-slot:image="{scope}"> 
      <slot name="image" :scope="scope"></slot>
    </template>
    <template v-slot:content="{scope}"> 
      <slot name="content" :scope="scope"></slot>
    </template> 
  </Vertical>
 
</template>
<style lang="scss" scope>
</style>
<script>
/**
 * 图片墙组件
 * @module $ui/components/my-im-wall
 */
import Horizontal from './Horizontal'
import Vertical from './Vertical'
import DefaultImg from '$ui/assets/img/PRESENTED_IMAGE_DEFAULT.png'
/**
 * 插槽
 * @member slots
 * @property {string} image 图片插槽
 * @property {string} content 内容插槽
 */
export default {
  name: 'MyImgWall',
  mixins: [],
  components: {
    Horizontal,
    Vertical
  },
  /**
   * 属性参数
   * @member props
   * @property {Boolean} [isHorizontal] 是否横向布局,默认true, false 为纵向布局
   * @property {Object} [keyMap] 字段映射, 用于映射加载数组对象中的 图片链接字段
   * @property {Function} [loadData] 加载图片方法,返回promise, promise 中返回数组, 数组元素图片链接(Promise.resolve([{src: xxxx}, {src: xxxx}]))
   * @property {Number} [imgHeight] 横向布局时 图片基础高度(此参数为横向布局的图片最小高度)
   * @property {Number} [margin] 图片间距,横向布局时为图片四边margin,纵向布局时为图片下边距
   * @property {Object} [columns] 纵向布局时 显示列数,支持响应式对象设置 {xxl,xl,lg,md,sm,xs}
   */
  props: {
    isHorizontal: {
      type: Boolean,
      default: true
    },
    // 字段映射
    keyMap: {
      type: Object,
      default() {
        return {
          src: 'src'
        }
      }
    },
    // 加载函数
    loadData: {
      type: Function
    }
  },
  data() {
    return {}
  },
  computed: {
  },
  methods: {
    imgPreload(data) {
      const imgData = data
      const loadPromise = imgData.map((data) => {
        return new Promise((resolve, reject) => {
          const imgObj = new Image()
          imgObj.src = data[this.keyMap.src]
          imgObj.onload = (e) => {
            resolve({
              _img: imgObj,
              ...data
            })
          }
          imgObj.onerror = () => {
            resolve({
              _img: {
                src: DefaultImg,
                width: 184,
                height: 152
              },
              ...data
            })
          }
        })
      })
      Promise.all(loadPromise).then((res) => { 
        this.$refs.imgWall.addImgData(res)
        const allImgs = this.getImages()
        /**
         * 数据插入事件
         * @event on-added
         * @param {array} 当前插入图片
         * @param {array} 全部图片
         */
        this.$emit('on-added', res, allImgs)
      }) 
    },
    loadMore() {
      this.loadData().then((res) => {
        this.imgPreload(res)
      })
    },
    getImages() {
      return this.$refs.imgWall.imgData.concat([])
    },
    setImages(arr) {
      this.$refs.imgWall.addImgData(arr)
    },
    clearImages() {
      this.$refs.imgWall.imgData = []
    }
  },
  created() {},
  mounted() {
    if (this.loadData) {
      this.loadMore()
    }
  }
}
</script>