SOURCE

<template>
  <div class="ratio-fixed-image" :class="{loading : status === 'loading'}" :style="style">
    <slot />
  </div>
</template>

<script>
  import { cropImage } from 'utils/qiniu';

  export default {
    props: ['ratioHeight', 'ratioWidth', 'url', 'qiniuCrop'],

    data() {
      const ratio = this.ratioHeight / this.ratioWidth * 100 + '%';

      return {
        status: 'loading',
        ratio,
        realWidth: 0,
        realHeight: 0
      };
    },

    computed: {
      src() {
        return this.url &&
          this.qiniuCrop ?
          cropImage(this.url, this.realWidth, this.realHeight) :
          this.url;
      },

      style() {
        const backgroundImage = this.status === 'loaded' && `url(${this.src})`;

        return {
          paddingTop: this.ratio,
          backgroundImage
        };
      }
    },

    watch: {
      url() {
        this.loadImage();
      }
    },

    methods: {
      loadImage() {
        this.status = 'loading';

        if (this.src) {
          let img = new Image();
          img.onload = this.handleLoad;
          img.onerror = this.handleError;
          img.src = this.src;
        }
      },

      handleLoad() {
        this.status = 'loaded';
        this.$nextTick(() => {
          this.$emit('load');
        });
      },

      handleError() {
        this.status = 'error';
        this.$nextTick(() => {
          this.$emit('error');
        });
      }
    },

    mounted() {
      ({ clientWidth: this.realWidth, clientHeight: this.realHeight } = this.$el);
      this.loadImage();
    }
  };
</script>

<style lang="scss" scoped>
  .ratio-fixed-image {
    background-position: center center;
    background-repeat: no-repeat;
    background-size: cover;
    background-color: #f0f0f0;

    &.loading {
      background-image: url('~images/loading.svg');
      background-size: auto;
    }
  }
</style>
console 命令行工具 X clear

                    
>
console