152 lines
3.7 KiB
Vue
152 lines
3.7 KiB
Vue
|
|
import Icon from '../icon'
|
|
|
|
export default {
|
|
name: 'AAvatar',
|
|
props: {
|
|
prefixCls: {
|
|
type: String,
|
|
default: 'ant-avatar',
|
|
},
|
|
shape: {
|
|
validator: (val) => (['circle', 'square'].includes(val)),
|
|
default: 'circle',
|
|
},
|
|
size: {
|
|
validator: (val) => {
|
|
return typeof val === 'number' || ['small', 'large', 'default'].includes(val)
|
|
},
|
|
default: 'default',
|
|
},
|
|
src: String,
|
|
icon: String,
|
|
alt: String,
|
|
loadError: Function,
|
|
},
|
|
data () {
|
|
return {
|
|
isImgExist: true,
|
|
scale: 1,
|
|
}
|
|
},
|
|
mounted () {
|
|
this.prevChildren = this.$slots.default
|
|
this.prevState = { ...this.$data }
|
|
this.$nextTick(() => {
|
|
this.setScale()
|
|
})
|
|
},
|
|
updated () {
|
|
if (this.preChildren !== this.$slots.default ||
|
|
(this.prevState.scale !== this.$data.scale && this.$data.scale === 1) ||
|
|
(this.prevState.isImgExist !== this.$data.isImgExist)) {
|
|
this.$nextTick(() => {
|
|
this.setScale()
|
|
})
|
|
}
|
|
this.preChildren = this.$slots.default
|
|
this.prevState = { ...this.$data }
|
|
},
|
|
methods: {
|
|
setScale () {
|
|
const childrenNode = this.$refs.avatarChildren
|
|
if (childrenNode) {
|
|
const childrenWidth = childrenNode.offsetWidth
|
|
const avatarWidth = this.$el.getBoundingClientRect().width
|
|
if (avatarWidth - 8 < childrenWidth) {
|
|
this.scale = (avatarWidth - 8) / childrenWidth
|
|
} else {
|
|
this.scale = 1
|
|
}
|
|
this.$forceUpdate()
|
|
}
|
|
},
|
|
handleImgLoadError () {
|
|
const { loadError } = this.$props
|
|
const errorFlag = loadError ? loadError() : undefined
|
|
if (errorFlag !== false) {
|
|
this.isImgExist = false
|
|
}
|
|
},
|
|
},
|
|
render () {
|
|
const {
|
|
prefixCls, shape, size, src, icon, alt,
|
|
} = this.$props
|
|
|
|
const { isImgExist, scale } = this.$data
|
|
|
|
const sizeCls = {
|
|
[`${prefixCls}-lg`]: size === 'large',
|
|
[`${prefixCls}-sm`]: size === 'small',
|
|
}
|
|
|
|
const classString = {
|
|
[prefixCls]: true,
|
|
...sizeCls,
|
|
[`${prefixCls}-${shape}`]: shape,
|
|
[`${prefixCls}-image`]: src && isImgExist,
|
|
[`${prefixCls}-icon`]: icon,
|
|
}
|
|
|
|
const sizeStyle = typeof size === 'number' ? {
|
|
width: `${size}px`,
|
|
height: `${size}px`,
|
|
lineHeight: `${size}px`,
|
|
fontSize: icon ? `${size / 2}px` : '18px',
|
|
} : {}
|
|
|
|
let children = this.$slots.default
|
|
if (src && isImgExist) {
|
|
children = (
|
|
<img
|
|
src={src}
|
|
onError={this.handleImgLoadError}
|
|
alt={alt}
|
|
/>
|
|
)
|
|
} else if (icon) {
|
|
children = <Icon type={icon} />
|
|
} else {
|
|
const childrenNode = this.$refs.avatarChildren
|
|
if (childrenNode || (scale !== 1 && childrenNode)) {
|
|
const childrenStyle = {
|
|
msTransform: `scale(${scale})`,
|
|
WebkitTransform: `scale(${scale})`,
|
|
transform: `scale(${scale})`,
|
|
position: 'absolute',
|
|
display: 'inline-block',
|
|
left: `calc(50% - ${Math.round(childrenNode.offsetWidth / 2)}px)`,
|
|
}
|
|
const sizeChildrenStyle = typeof size === 'number' ? {
|
|
lineHeight: `${size}px`,
|
|
} : {}
|
|
children = (
|
|
<span
|
|
class={`${prefixCls}-string`}
|
|
ref='avatarChildren'
|
|
style={{ ...sizeChildrenStyle, ...childrenStyle }}
|
|
>
|
|
{children}
|
|
</span>
|
|
)
|
|
} else {
|
|
children = (
|
|
<span
|
|
class={`${prefixCls}-string`}
|
|
ref='avatarChildren'
|
|
>
|
|
{children}
|
|
</span>
|
|
)
|
|
}
|
|
}
|
|
return (
|
|
<span {...{ on: this.$listeners, class: classString, style: sizeStyle }}>
|
|
{children}
|
|
</span>
|
|
)
|
|
},
|
|
}
|
|
|