element Image组件

<template>
  <div class="el-image">
    <slot v-if="loading" name="placeholder">
      <div class="el-image__placeholder"></div>
    </slot>
    <slot v-else-if="error" name="error">
      <div class="el-image__error">{{ t('el.image.error') }}</div>
    </slot>
    <img
      v-else
      class="el-image__inner"
      :src="src"
      :alt="alt"
      :style="{ 'object-fit': fit }">
  </div>
</template>

<script>
  import Locale from 'element-ui/src/mixins/locale';
  import { on, off, getScrollContainer, isInContainer } from 'element-ui/src/utils/dom';
  import { isString, isHtmlElement } from 'element-ui/src/utils/types';
  import throttle from 'throttle-debounce/throttle';

  export default {
    name: 'ElImage',

    mixins: [Locale],

    props: {
      // src    图片源,同原生    string
      src: String,
      // fit    确定图片如何适应容器框,同原生 object-fit    string    fill / contain / cover / none / scale-down
      fit: String,
      // lazy    是否开启懒加载    boolean    —    false
      lazy: Boolean,
      // scroll-container    开启懒加载后,监听 scroll 事件的容器    string / HTMLElement    —    最近一个 overflow 值为 auto 或 scroll 的父元素
      scrollContainer: [String, HTMLElement],
      // alt    原生 alt    string
      alt: String
    },

    data() {
      return {
        loading: true,
        error: false,
        show: !this.lazy
      };
    },

    watch: {
      // 监听src变化,加载新图片
      src: {
        handler(val) {
          this.show && this.loadImage(val);
        },
        immediate: true
      },
      // show变化,加载新图片
      show(val) {
        val && this.loadImage(this.src);
      }
    },

    mounted() {
      // 初始化如果有lazy,执行滚动监听
      this.lazy && this.addLazyLoadListener();
    },

    beforeDestroy() {
      this.lazy && this.removeLazyLoadListener();
    },

    methods: {
      // 加载图片
      loadImage(val) {
        // reset status
        this.loading = true;
        this.error = false;

        const img = new Image();
        img.onload = this.handleLoad.bind(this);
        img.onerror = this.handleError.bind(this);
        img.src = val;
      },
      // load    图片加载成功触发    (e: Event)
      handleLoad(e) {
        this.loading = false;
        this.$emit('load', e);
      },
      // error    图片加载失败触发    (e: Error)
      handleError(e) {
        this.loading = false;
        this.error = true;
        this.$emit('error', e);
      },
      // 如果滚动元素还在当前组件内,移除监听
      handleLazyLoad() {
        if (isInContainer(this.$el, this._scrollContainer)) {
          this.show = true;
          this.removeLazyLoadListener();
        }
      },
      // 添加滚动监听
      addLazyLoadListener() {
        if (this.$isServer) return;

        const { scrollContainer } = this;
        let _scrollContainer = null;

        if (isHtmlElement(scrollContainer)) {
          _scrollContainer = scrollContainer;
        } else if (isString(scrollContainer)) {
          _scrollContainer = document.querySelector(scrollContainer);
        } else {
          _scrollContainer = getScrollContainer(this.$el);
        }

        if (_scrollContainer) {
          this._scrollContainer = _scrollContainer;
          // 节流函数,每隔200ms检测一次加载完毕事件移除监听
          this._lazyLoadHandler = throttle(200, this.handleLazyLoad);
          // 绑定到滚动元素,监听元素滚动事件
          on(_scrollContainer, 'scroll', this._lazyLoadHandler);
          // 首次执行
          this.handleLazyLoad();
        }
      },
      // 移除滚动监听
      removeLazyLoadListener() {
        const { _scrollContainer, _lazyLoadHandler } = this;

        if (this.$isServer || !_scrollContainer || !_lazyLoadHandler) return;

        off(_scrollContainer, 'scroll', _lazyLoadHandler);
        this._scrollContainer = null;
        this._lazyLoadHandler = null;
      }
    }
  };
</script>

 

posted on 2019-05-30 19:46  心痛随缘  阅读(20041)  评论(0编辑  收藏  举报