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>