version:element-plus 1.0.1-beta.0
<template>
<span :class="avatarClass" :style="sizeStyle">
<!-- 先判断是否有 src 地址,有再判断是否加载成功 -->
<img
v-if="(src || srcSet) && !hasLoadError"
:src="src"
:alt="alt"
:srcset="srcSet"
:style="fitStyle"
@error="handleError"
>
<!-- 再判断是否传入 icon -->
<i v-else-if="icon" :class="icon"></i>
<!-- 最后才是默认插槽 也就是说不传 src 和 icon ,插槽才有用 -->
<slot v-else></slot>
</span>
</template>
<script lang="ts">
import { defineComponent, computed, ref, PropType } from 'vue'
const ERROR_EVENT = 'error'
export default defineComponent({
name: 'ElAvatar',
props: {
size: {
type: [Number, String] as PropType<number | string>, // 接受 number 和 string
validator(this: never, val: unknown) {
if (typeof val === 'string') {
return ['large', 'medium', 'small'].includes(val) // 字符串判断是不是三种类型中的
}
return typeof val === 'number'
},
default: 'large',
},
shape: {
type: String,
default: 'circle',
validator(this: never, val: string) {
return ['circle', 'square'].includes(val) // 只支持 圆 和 方
},
},
icon: String, // icon 组件的类名
src: String,
alt: String,
srcSet: String,
fit: {
type: String,
default: 'cover',
},
},
emits: [ERROR_EVENT],
setup(props, { emit }) {
const hasLoadError = ref(false)
// 父标签 span 的 class
const avatarClass = computed(() => {
const { size, icon, shape } = props
let classList = ['el-avatar'] // 默认class
if (size && typeof size === 'string') {
classList.push(`el-avatar--${size}`) // size 是 字符串 class 就将对应的 size 放进去
}
if (icon) {
classList.push('el-avatar--icon') // icon 的 对应类名
}
if (shape) {
classList.push(`el-avatar--${shape}`) // 根据 shape 传入对应的 class
}
return classList
})
// 父标签 span 的 行内样式
const sizeStyle = computed(() => {
const { size } = props
// 如果 size 是 number 就 返回 正方形垂直居中的样式
return typeof size === 'number' ? {
height: `${size}px`,
width: `${size}px`,
lineHeight: `${size}px`,
} : {}
})
// img 标签的行内样式 objectFit 根据传入的 fit 来实现
const fitStyle = computed(() => ({
objectFit: props.fit,
}))
// 图片加载错误的触发函数 => 将 hasLoadError 置位 false ,并触发回调
function handleError(e: Event) {
hasLoadError.value = true
emit(ERROR_EVENT, e) // error 回调
}
return {
hasLoadError, avatarClass, sizeStyle, handleError,
fitStyle,
}
},
})
</script>