refactor: avatar
parent
4a5c4cdeb7
commit
7acf577f56
|
@ -0,0 +1,26 @@
|
||||||
|
import { computed, ComputedRef, inject, provide, UnwrapRef } from 'vue';
|
||||||
|
import { ConfigProviderProps, defaultConfigProvider, SizeType } from '../../config-provider';
|
||||||
|
|
||||||
|
const sizeProvider = Symbol('SizeProvider');
|
||||||
|
|
||||||
|
const useProviderSize = <T = SizeType>(props: Record<any, any>): ComputedRef<T> => {
|
||||||
|
const configProvider = inject<UnwrapRef<ConfigProviderProps>>(
|
||||||
|
'configProvider',
|
||||||
|
defaultConfigProvider,
|
||||||
|
);
|
||||||
|
const size = computed<T>(() => props.size || configProvider.componentSize);
|
||||||
|
provide(sizeProvider, size);
|
||||||
|
return size;
|
||||||
|
};
|
||||||
|
|
||||||
|
const useInjectSize = <T = SizeType>(): ComputedRef<T> => {
|
||||||
|
const size: ComputedRef<T> = inject(
|
||||||
|
sizeProvider,
|
||||||
|
computed(() => ('default' as unknown) as T),
|
||||||
|
);
|
||||||
|
return size;
|
||||||
|
};
|
||||||
|
|
||||||
|
export { useInjectSize, sizeProvider, useProviderSize };
|
||||||
|
|
||||||
|
export default useProviderSize;
|
|
@ -7,16 +7,17 @@ import {
|
||||||
inject,
|
inject,
|
||||||
nextTick,
|
nextTick,
|
||||||
onMounted,
|
onMounted,
|
||||||
onUpdated,
|
|
||||||
PropType,
|
PropType,
|
||||||
ref,
|
ref,
|
||||||
watch,
|
watch,
|
||||||
} from 'vue';
|
} from 'vue';
|
||||||
import { defaultConfigProvider } from '../config-provider';
|
|
||||||
import { getPropsSlot } from '../_util/props-util';
|
import { getPropsSlot } from '../_util/props-util';
|
||||||
import PropTypes from '../_util/vue-types';
|
import PropTypes from '../_util/vue-types';
|
||||||
import useBreakpoint from '../_util/hooks/useBreakpoint';
|
import useBreakpoint from '../_util/hooks/useBreakpoint';
|
||||||
import { Breakpoint, responsiveArray, ScreenSizeMap } from '../_util/responsiveObserve';
|
import { Breakpoint, responsiveArray, ScreenSizeMap } from '../_util/responsiveObserve';
|
||||||
|
import useConfigInject from '../_util/hooks/useConfigInject';
|
||||||
|
import ResizeObserver from '../vc-resize-observer';
|
||||||
|
import { useInjectSize } from '../_util/hooks/useSize';
|
||||||
|
|
||||||
export type AvatarSize = 'large' | 'small' | 'default' | number | ScreenSizeMap;
|
export type AvatarSize = 'large' | 'small' | 'default' | number | ScreenSizeMap;
|
||||||
|
|
||||||
|
@ -44,6 +45,8 @@ export type AvatarProps = Partial<ExtractPropTypes<typeof avatarProps>>;
|
||||||
const Avatar = defineComponent({
|
const Avatar = defineComponent({
|
||||||
name: 'AAvatar',
|
name: 'AAvatar',
|
||||||
props: avatarProps,
|
props: avatarProps,
|
||||||
|
inheritAttrs: false,
|
||||||
|
slots: ['icon'],
|
||||||
setup(props, { slots, attrs }) {
|
setup(props, { slots, attrs }) {
|
||||||
const isImgExist = ref(true);
|
const isImgExist = ref(true);
|
||||||
const isMounted = ref(false);
|
const isMounted = ref(false);
|
||||||
|
@ -52,12 +55,9 @@ const Avatar = defineComponent({
|
||||||
const avatarChildrenRef = ref<HTMLElement>(null);
|
const avatarChildrenRef = ref<HTMLElement>(null);
|
||||||
const avatarNodeRef = ref<HTMLElement>(null);
|
const avatarNodeRef = ref<HTMLElement>(null);
|
||||||
|
|
||||||
const configProvider = inject('configProvider', defaultConfigProvider);
|
const { prefixCls } = useConfigInject('avatar', props);
|
||||||
|
|
||||||
const groupSize = inject(
|
const groupSize = useInjectSize();
|
||||||
'SizeProvider',
|
|
||||||
computed(() => 'default'),
|
|
||||||
);
|
|
||||||
|
|
||||||
const screens = useBreakpoint();
|
const screens = useBreakpoint();
|
||||||
const responsiveSize = computed(() => {
|
const responsiveSize = computed(() => {
|
||||||
|
@ -82,7 +82,7 @@ const Avatar = defineComponent({
|
||||||
return {};
|
return {};
|
||||||
};
|
};
|
||||||
|
|
||||||
const setScale = () => {
|
const setScaleParam = () => {
|
||||||
if (!avatarChildrenRef.value || !avatarNodeRef.value) {
|
if (!avatarChildrenRef.value || !avatarNodeRef.value) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -116,40 +116,35 @@ const Avatar = defineComponent({
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.gap,
|
||||||
|
() => {
|
||||||
|
nextTick(() => {
|
||||||
|
setScaleParam();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
setScale();
|
setScaleParam();
|
||||||
isMounted.value = true;
|
isMounted.value = true;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
onUpdated(() => {
|
|
||||||
nextTick(() => {
|
|
||||||
setScale();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
const {
|
const { shape, size: customSize, src, alt, srcset, draggable } = props;
|
||||||
prefixCls: customizePrefixCls,
|
|
||||||
shape,
|
|
||||||
size: customSize,
|
|
||||||
src,
|
|
||||||
alt,
|
|
||||||
srcset,
|
|
||||||
draggable,
|
|
||||||
} = props;
|
|
||||||
const icon = getPropsSlot(slots, props, 'icon');
|
const icon = getPropsSlot(slots, props, 'icon');
|
||||||
const getPrefixCls = configProvider.getPrefixCls;
|
const pre = prefixCls.value;
|
||||||
const prefixCls = getPrefixCls('avatar', customizePrefixCls);
|
|
||||||
const size = customSize === 'default' ? groupSize.value : customSize;
|
const size = customSize === 'default' ? groupSize.value : customSize;
|
||||||
const classString = {
|
const classString = {
|
||||||
[prefixCls]: true,
|
[`${attrs.class}`]: !!attrs.class,
|
||||||
[`${prefixCls}-lg`]: size === 'large',
|
[pre]: true,
|
||||||
[`${prefixCls}-sm`]: size === 'small',
|
[`${pre}-lg`]: size === 'large',
|
||||||
[`${prefixCls}-${shape}`]: shape,
|
[`${pre}-sm`]: size === 'small',
|
||||||
[`${prefixCls}-image`]: src && isImgExist.value,
|
[`${pre}-${shape}`]: shape,
|
||||||
[`${prefixCls}-icon`]: icon,
|
[`${pre}-image`]: src && isImgExist.value,
|
||||||
|
[`${pre}-icon`]: icon,
|
||||||
};
|
};
|
||||||
|
|
||||||
const sizeStyle: CSSProperties =
|
const sizeStyle: CSSProperties =
|
||||||
|
@ -162,9 +157,10 @@ const Avatar = defineComponent({
|
||||||
}
|
}
|
||||||
: {};
|
: {};
|
||||||
|
|
||||||
let children: VueNode = slots.default?.();
|
const children: VueNode = slots.default?.();
|
||||||
|
let childrenToRender;
|
||||||
if (src && isImgExist.value) {
|
if (src && isImgExist.value) {
|
||||||
children = (
|
childrenToRender = (
|
||||||
<img
|
<img
|
||||||
draggable={draggable}
|
draggable={draggable}
|
||||||
src={src}
|
src={src}
|
||||||
|
@ -174,42 +170,41 @@ const Avatar = defineComponent({
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
} else if (icon) {
|
} else if (icon) {
|
||||||
children = icon;
|
childrenToRender = icon;
|
||||||
} else {
|
} else if (isMounted.value || scale.value !== 1) {
|
||||||
const childrenNode = avatarChildrenRef.value;
|
const transformString = `scale(${scale.value}) translateX(-50%)`;
|
||||||
|
const childrenStyle: CSSProperties = {
|
||||||
if (childrenNode || scale.value !== 1) {
|
msTransform: transformString,
|
||||||
const transformString = `scale(${scale.value}) translateX(-50%)`;
|
WebkitTransform: transformString,
|
||||||
const childrenStyle: CSSProperties = {
|
transform: transformString,
|
||||||
msTransform: transformString,
|
};
|
||||||
WebkitTransform: transformString,
|
const sizeChildrenStyle =
|
||||||
transform: transformString,
|
typeof size === 'number'
|
||||||
};
|
? {
|
||||||
const sizeChildrenStyle =
|
lineHeight: `${size}px`,
|
||||||
typeof size === 'number'
|
}
|
||||||
? {
|
: {};
|
||||||
lineHeight: `${size}px`,
|
childrenToRender = (
|
||||||
}
|
<ResizeObserver onResize={setScaleParam}>
|
||||||
: {};
|
|
||||||
children = (
|
|
||||||
<span
|
<span
|
||||||
class={`${prefixCls}-string`}
|
class={`${pre}-string`}
|
||||||
ref={avatarChildrenRef}
|
ref={avatarChildrenRef}
|
||||||
style={{ ...sizeChildrenStyle, ...childrenStyle }}
|
style={{ ...sizeChildrenStyle, ...childrenStyle }}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</span>
|
</span>
|
||||||
);
|
</ResizeObserver>
|
||||||
} else {
|
);
|
||||||
children = (
|
} else {
|
||||||
<span class={`${prefixCls}-string`} ref={avatarChildrenRef} style={{ opacity: 0 }}>
|
childrenToRender = (
|
||||||
{children}
|
<span class={`${pre}-string`} ref={avatarChildrenRef} style={{ opacity: 0 }}>
|
||||||
</span>
|
{children}
|
||||||
);
|
</span>
|
||||||
}
|
);
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<span
|
<span
|
||||||
|
{...attrs}
|
||||||
ref={avatarNodeRef}
|
ref={avatarNodeRef}
|
||||||
class={classString}
|
class={classString}
|
||||||
style={{
|
style={{
|
||||||
|
@ -218,7 +213,7 @@ const Avatar = defineComponent({
|
||||||
...(attrs.style as CSSProperties),
|
...(attrs.style as CSSProperties),
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{children}
|
{childrenToRender}
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,6 +6,7 @@ import PropTypes from '../_util/vue-types';
|
||||||
import { flattenChildren, getPropsSlot } from '../_util/props-util';
|
import { flattenChildren, getPropsSlot } from '../_util/props-util';
|
||||||
import { tuple } from '../_util/type';
|
import { tuple } from '../_util/type';
|
||||||
import useConfigInject from '../_util/hooks/useConfigInject';
|
import useConfigInject from '../_util/hooks/useConfigInject';
|
||||||
|
import useProviderSize from '../_util/hooks/useSize';
|
||||||
|
|
||||||
const groupProps = {
|
const groupProps = {
|
||||||
prefixCls: PropTypes.string,
|
prefixCls: PropTypes.string,
|
||||||
|
@ -31,10 +32,8 @@ const Group = defineComponent({
|
||||||
props: groupProps,
|
props: groupProps,
|
||||||
inheritAttrs: false,
|
inheritAttrs: false,
|
||||||
setup(props, { slots, attrs }) {
|
setup(props, { slots, attrs }) {
|
||||||
const { prefixCls, direction, size } = useConfigInject('avatar-group', props);
|
const { prefixCls, direction } = useConfigInject('avatar-group', props);
|
||||||
|
useProviderSize<AvatarSize>(props);
|
||||||
provide('SizeProvider', size);
|
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
const { maxPopoverPlacement = 'top', maxCount, maxStyle } = props;
|
const { maxPopoverPlacement = 'top', maxCount, maxStyle } = props;
|
||||||
|
|
||||||
|
|
|
@ -89,7 +89,7 @@ export const configProviderProps = {
|
||||||
type: Object as PropType<{ ghost: boolean }>,
|
type: Object as PropType<{ ghost: boolean }>,
|
||||||
},
|
},
|
||||||
componentSize: {
|
componentSize: {
|
||||||
type: Object as PropType<SizeType>,
|
type: String as PropType<SizeType>,
|
||||||
},
|
},
|
||||||
direction: {
|
direction: {
|
||||||
type: String as PropType<'ltr' | 'rtl'>,
|
type: String as PropType<'ltr' | 'rtl'>,
|
||||||
|
|
Loading…
Reference in New Issue