refactor: avatar

feat-new-menu
tanjinzhou 2021-05-13 12:57:42 +08:00
parent 4a5c4cdeb7
commit 7acf577f56
4 changed files with 87 additions and 67 deletions

View File

@ -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;

View File

@ -7,16 +7,17 @@ import {
inject,
nextTick,
onMounted,
onUpdated,
PropType,
ref,
watch,
} from 'vue';
import { defaultConfigProvider } from '../config-provider';
import { getPropsSlot } from '../_util/props-util';
import PropTypes from '../_util/vue-types';
import useBreakpoint from '../_util/hooks/useBreakpoint';
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;
@ -44,6 +45,8 @@ export type AvatarProps = Partial<ExtractPropTypes<typeof avatarProps>>;
const Avatar = defineComponent({
name: 'AAvatar',
props: avatarProps,
inheritAttrs: false,
slots: ['icon'],
setup(props, { slots, attrs }) {
const isImgExist = ref(true);
const isMounted = ref(false);
@ -52,12 +55,9 @@ const Avatar = defineComponent({
const avatarChildrenRef = ref<HTMLElement>(null);
const avatarNodeRef = ref<HTMLElement>(null);
const configProvider = inject('configProvider', defaultConfigProvider);
const { prefixCls } = useConfigInject('avatar', props);
const groupSize = inject(
'SizeProvider',
computed(() => 'default'),
);
const groupSize = useInjectSize();
const screens = useBreakpoint();
const responsiveSize = computed(() => {
@ -82,7 +82,7 @@ const Avatar = defineComponent({
return {};
};
const setScale = () => {
const setScaleParam = () => {
if (!avatarChildrenRef.value || !avatarNodeRef.value) {
return;
}
@ -116,40 +116,35 @@ const Avatar = defineComponent({
},
);
watch(
() => props.gap,
() => {
nextTick(() => {
setScaleParam();
});
},
);
onMounted(() => {
nextTick(() => {
setScale();
setScaleParam();
isMounted.value = true;
});
});
onUpdated(() => {
nextTick(() => {
setScale();
});
});
return () => {
const {
prefixCls: customizePrefixCls,
shape,
size: customSize,
src,
alt,
srcset,
draggable,
} = props;
const { shape, size: customSize, src, alt, srcset, draggable } = props;
const icon = getPropsSlot(slots, props, 'icon');
const getPrefixCls = configProvider.getPrefixCls;
const prefixCls = getPrefixCls('avatar', customizePrefixCls);
const pre = prefixCls.value;
const size = customSize === 'default' ? groupSize.value : customSize;
const classString = {
[prefixCls]: true,
[`${prefixCls}-lg`]: size === 'large',
[`${prefixCls}-sm`]: size === 'small',
[`${prefixCls}-${shape}`]: shape,
[`${prefixCls}-image`]: src && isImgExist.value,
[`${prefixCls}-icon`]: icon,
[`${attrs.class}`]: !!attrs.class,
[pre]: true,
[`${pre}-lg`]: size === 'large',
[`${pre}-sm`]: size === 'small',
[`${pre}-${shape}`]: shape,
[`${pre}-image`]: src && isImgExist.value,
[`${pre}-icon`]: icon,
};
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) {
children = (
childrenToRender = (
<img
draggable={draggable}
src={src}
@ -174,42 +170,41 @@ const Avatar = defineComponent({
/>
);
} else if (icon) {
children = icon;
} else {
const childrenNode = avatarChildrenRef.value;
if (childrenNode || scale.value !== 1) {
const transformString = `scale(${scale.value}) translateX(-50%)`;
const childrenStyle: CSSProperties = {
msTransform: transformString,
WebkitTransform: transformString,
transform: transformString,
};
const sizeChildrenStyle =
typeof size === 'number'
? {
lineHeight: `${size}px`,
}
: {};
children = (
childrenToRender = icon;
} else if (isMounted.value || scale.value !== 1) {
const transformString = `scale(${scale.value}) translateX(-50%)`;
const childrenStyle: CSSProperties = {
msTransform: transformString,
WebkitTransform: transformString,
transform: transformString,
};
const sizeChildrenStyle =
typeof size === 'number'
? {
lineHeight: `${size}px`,
}
: {};
childrenToRender = (
<ResizeObserver onResize={setScaleParam}>
<span
class={`${prefixCls}-string`}
class={`${pre}-string`}
ref={avatarChildrenRef}
style={{ ...sizeChildrenStyle, ...childrenStyle }}
>
{children}
</span>
);
} else {
children = (
<span class={`${prefixCls}-string`} ref={avatarChildrenRef} style={{ opacity: 0 }}>
{children}
</span>
);
}
</ResizeObserver>
);
} else {
childrenToRender = (
<span class={`${pre}-string`} ref={avatarChildrenRef} style={{ opacity: 0 }}>
{children}
</span>
);
}
return (
<span
{...attrs}
ref={avatarNodeRef}
class={classString}
style={{
@ -218,7 +213,7 @@ const Avatar = defineComponent({
...(attrs.style as CSSProperties),
}}
>
{children}
{childrenToRender}
</span>
);
};

View File

@ -6,6 +6,7 @@ import PropTypes from '../_util/vue-types';
import { flattenChildren, getPropsSlot } from '../_util/props-util';
import { tuple } from '../_util/type';
import useConfigInject from '../_util/hooks/useConfigInject';
import useProviderSize from '../_util/hooks/useSize';
const groupProps = {
prefixCls: PropTypes.string,
@ -31,10 +32,8 @@ const Group = defineComponent({
props: groupProps,
inheritAttrs: false,
setup(props, { slots, attrs }) {
const { prefixCls, direction, size } = useConfigInject('avatar-group', props);
provide('SizeProvider', size);
const { prefixCls, direction } = useConfigInject('avatar-group', props);
useProviderSize<AvatarSize>(props);
return () => {
const { maxPopoverPlacement = 'top', maxCount, maxStyle } = props;

View File

@ -89,7 +89,7 @@ export const configProviderProps = {
type: Object as PropType<{ ghost: boolean }>,
},
componentSize: {
type: Object as PropType<SizeType>,
type: String as PropType<SizeType>,
},
direction: {
type: String as PropType<'ltr' | 'rtl'>,