Files
cmgd-mini-app/uni_modules/nutui-uni/components/avatar/avatar.vue
2026-01-05 12:47:14 +08:00

140 lines
3.2 KiB
Vue

<script setup lang="ts">
import type { CSSProperties } from 'vue'
import { computed, defineComponent, getCurrentInstance, ref, watch } from 'vue'
import { PREFIX } from '../_constants'
import { useInject } from '../_hooks'
import { getMainClass, getMainStyle, pxCheck } from '../_utils'
import type { AvatarGroupProps } from '../avatargroup'
import { AVATAR_GROUP_KEY } from '../avatargroup'
import { avatarProps } from './avatar'
import type { AvatarFinalSize, AvatarShape, AvatarSize } from './type'
import { avatarSize } from './type'
const props = defineProps(avatarProps)
const instance = getCurrentInstance()
const { parent } = useInject<{ props: Required<AvatarGroupProps> }>(AVATAR_GROUP_KEY)
const show = ref(true)
const innerZIndex = ref<number | undefined>(undefined)
watch(() => ({
maxCount: parent?.props.maxCount,
children: parent?.internalChildren,
}), ({ maxCount, children }) => {
if (maxCount == null || Number(maxCount) <= 0 || children == null || instance == null) {
show.value = true
innerZIndex.value = undefined
return
}
const index = children.findIndex((item) => {
return item.uid === instance.uid && !(item.props.customClass as string)?.includes('avatar-fold')
})
if (index < 0) {
show.value = true
innerZIndex.value = undefined
return
}
show.value = index < Number(maxCount)
if (parent?.props.zIndex === 'right')
innerZIndex.value = children.length - index
else
innerZIndex.value = undefined
}, {
immediate: true,
deep: true,
})
function getTrulySize() {
if (props.size != null)
return props.size
if (parent != null && parent.props.size != null)
return parent.props.size
return 'normal'
}
const finalSize = computed<AvatarFinalSize>(() => {
const size: string | number = getTrulySize()
const preset: boolean = avatarSize.includes(size as AvatarSize)
return {
preset,
value: preset ? (size as AvatarSize) : pxCheck(size),
}
})
const finalShape = computed<AvatarShape>(() => {
if (props.shape != null)
return props.shape
if (parent != null && parent.props.shape != null)
return parent.props.shape
return 'round'
})
const classes = computed(() => {
const value: Record<string, boolean> = {
[`nut-avatar-${finalShape.value}`]: true,
'nut-hidden': !show.value,
}
if (finalSize.value.preset)
value[`nut-avatar-${finalSize.value.value}`] = true
return getMainClass(props, componentName, value)
})
const styles = computed(() => {
const value: CSSProperties = {
backgroundColor: props.bgColor,
color: props.customColor,
}
if (!finalSize.value.preset) {
value.width = finalSize.value.value
value.height = finalSize.value.value
}
if (parent?.props.span)
value.marginLeft = pxCheck(parent?.props.span)
if (innerZIndex.value !== undefined)
value.zIndex = innerZIndex.value
return getMainStyle(props, value)
})
</script>
<script lang="ts">
const componentName = `${PREFIX}-avatar`
export default defineComponent({
name: componentName,
options: {
virtualHost: true,
addGlobalClass: true,
styleIsolation: 'shared',
},
})
</script>
<template>
<view :style="styles" :class="classes">
<slot />
</view>
</template>
<style lang="scss">
@import './index';
</style>