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, 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>
); );
}; };

View File

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

View File

@ -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'>,