mirror of
https://github.com/element-plus/element-plus.git
synced 2025-01-18 10:59:10 +08:00
refactor(components): refactor avatar (#3364)
This commit is contained in:
parent
d26070d939
commit
19752ba778
@ -6,7 +6,7 @@ import {
|
||||
mockImageEvent,
|
||||
} from '@element-plus/test-utils'
|
||||
|
||||
import Avatar from '../src/index.vue'
|
||||
import Avatar from '../src/avatar.vue'
|
||||
|
||||
describe('Avatar.vue', () => {
|
||||
mockImageEvent()
|
||||
|
@ -1,12 +1,7 @@
|
||||
import { App } from 'vue'
|
||||
import type { SFCWithInstall } from '@element-plus/utils/types'
|
||||
import Avatar from './src/index.vue'
|
||||
import Avatar from './src/avatar.vue'
|
||||
import { withInstall } from '@element-plus/utils/with-install'
|
||||
|
||||
Avatar.install = (app: App): void => {
|
||||
app.component(Avatar.name, Avatar)
|
||||
}
|
||||
export const ElAvatar = withInstall(Avatar)
|
||||
export default ElAvatar
|
||||
|
||||
const _Avatar = Avatar as SFCWithInstall<typeof Avatar>
|
||||
|
||||
export default _Avatar
|
||||
export const ElAvatar = _Avatar
|
||||
export * from './src/avatar'
|
||||
|
35
packages/components/avatar/src/avatar.ts
Normal file
35
packages/components/avatar/src/avatar.ts
Normal file
@ -0,0 +1,35 @@
|
||||
import { buildProp } from '@element-plus/utils/props'
|
||||
import type { CSSProperties, ExtractPropTypes } from 'vue'
|
||||
|
||||
export const avatarProps = {
|
||||
size: buildProp({
|
||||
type: [Number, String],
|
||||
values: ['large', 'medium', 'small'],
|
||||
default: 'large',
|
||||
validator: (val): val is number => typeof val === 'number',
|
||||
} as const),
|
||||
|
||||
shape: buildProp({
|
||||
type: String,
|
||||
values: ['circle', 'square'],
|
||||
default: 'circle',
|
||||
} as const),
|
||||
|
||||
icon: String,
|
||||
src: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
alt: String,
|
||||
srcSet: String,
|
||||
fit: buildProp<CSSProperties['objectFit']>({
|
||||
type: String,
|
||||
default: 'cover',
|
||||
} as const),
|
||||
} as const
|
||||
export type AvatarProps = ExtractPropTypes<typeof avatarProps>
|
||||
|
||||
export const avatarEmits = {
|
||||
error: (evt: Event) => evt instanceof Event,
|
||||
}
|
||||
export type AvatarEmits = typeof avatarEmits
|
75
packages/components/avatar/src/avatar.vue
Normal file
75
packages/components/avatar/src/avatar.vue
Normal file
@ -0,0 +1,75 @@
|
||||
<template>
|
||||
<span :class="avatarClass" :style="sizeStyle">
|
||||
<img
|
||||
v-if="(src || srcSet) && !hasLoadError"
|
||||
:src="src"
|
||||
:alt="alt"
|
||||
:srcset="srcSet"
|
||||
:style="fitStyle"
|
||||
@error="handleError"
|
||||
/>
|
||||
<i v-else-if="icon" :class="icon"></i>
|
||||
<slot v-else></slot>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, computed, ref, watch } from 'vue'
|
||||
import { avatarEmits, avatarProps } from './avatar'
|
||||
|
||||
import type { CSSProperties } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'ElAvatar',
|
||||
|
||||
props: avatarProps,
|
||||
emits: avatarEmits,
|
||||
|
||||
setup(props, { emit }) {
|
||||
const hasLoadError = ref(false)
|
||||
|
||||
const avatarClass = computed(() => {
|
||||
const { size, icon, shape } = props
|
||||
const classList = ['el-avatar']
|
||||
if (size && typeof size === 'string') classList.push(`el-avatar--${size}`)
|
||||
if (icon) classList.push('el-avatar--icon')
|
||||
if (shape) classList.push(`el-avatar--${shape}`)
|
||||
return classList
|
||||
})
|
||||
|
||||
const sizeStyle = computed<CSSProperties>(() => {
|
||||
const { size } = props
|
||||
return typeof size === 'number'
|
||||
? {
|
||||
height: `${size}px`,
|
||||
width: `${size}px`,
|
||||
lineHeight: `${size}px`,
|
||||
}
|
||||
: {}
|
||||
})
|
||||
|
||||
const fitStyle = computed<CSSProperties>(() => ({
|
||||
objectFit: props.fit,
|
||||
}))
|
||||
|
||||
// need reset hasLoadError to false if src changed
|
||||
watch(
|
||||
() => props.src,
|
||||
() => (hasLoadError.value = false)
|
||||
)
|
||||
|
||||
function handleError(e: Event) {
|
||||
hasLoadError.value = true
|
||||
emit('error', e)
|
||||
}
|
||||
|
||||
return {
|
||||
hasLoadError,
|
||||
avatarClass,
|
||||
sizeStyle,
|
||||
fitStyle,
|
||||
handleError,
|
||||
}
|
||||
},
|
||||
})
|
||||
</script>
|
@ -1,109 +0,0 @@
|
||||
<template>
|
||||
<span :class="avatarClass" :style="sizeStyle">
|
||||
<img
|
||||
v-if="(src || srcSet) && !hasLoadError"
|
||||
:src="src"
|
||||
:alt="alt"
|
||||
:srcset="srcSet"
|
||||
:style="fitStyle"
|
||||
@error="handleError"
|
||||
/>
|
||||
<i v-else-if="icon" :class="icon"></i>
|
||||
<slot v-else></slot>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, computed, ref, watch, toRef } from 'vue'
|
||||
import type { CSSProperties, PropType } from 'vue'
|
||||
|
||||
const ERROR_EVENT = 'error'
|
||||
export default defineComponent({
|
||||
name: 'ElAvatar',
|
||||
props: {
|
||||
size: {
|
||||
type: [Number, String] as PropType<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,
|
||||
src: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
alt: String,
|
||||
srcSet: String,
|
||||
fit: {
|
||||
type: String,
|
||||
default: 'cover',
|
||||
},
|
||||
},
|
||||
emits: [ERROR_EVENT],
|
||||
setup(props, { emit }) {
|
||||
const hasLoadError = ref(false)
|
||||
|
||||
const src = toRef(props, 'src')
|
||||
// need reset hasLoadError to false if src changed
|
||||
watch(src, () => {
|
||||
hasLoadError.value = false
|
||||
})
|
||||
|
||||
const avatarClass = computed(() => {
|
||||
const { size, icon, shape } = props
|
||||
const classList = ['el-avatar']
|
||||
if (size && typeof size === 'string') {
|
||||
classList.push(`el-avatar--${size}`)
|
||||
}
|
||||
if (icon) {
|
||||
classList.push('el-avatar--icon')
|
||||
}
|
||||
if (shape) {
|
||||
classList.push(`el-avatar--${shape}`)
|
||||
}
|
||||
return classList
|
||||
})
|
||||
|
||||
const sizeStyle = computed(() => {
|
||||
const { size } = props
|
||||
return typeof size === 'number'
|
||||
? {
|
||||
height: `${size}px`,
|
||||
width: `${size}px`,
|
||||
lineHeight: `${size}px`,
|
||||
}
|
||||
: {}
|
||||
})
|
||||
|
||||
const fitStyle = computed(
|
||||
() =>
|
||||
({
|
||||
objectFit: props.fit,
|
||||
} as CSSProperties)
|
||||
)
|
||||
|
||||
function handleError(e: Event) {
|
||||
hasLoadError.value = true
|
||||
emit(ERROR_EVENT, e)
|
||||
}
|
||||
return {
|
||||
hasLoadError,
|
||||
avatarClass,
|
||||
sizeStyle,
|
||||
handleError,
|
||||
fitStyle,
|
||||
}
|
||||
},
|
||||
})
|
||||
</script>
|
Loading…
Reference in New Issue
Block a user