Avatar.js 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
  2. import _extends from "@babel/runtime/helpers/esm/extends";
  3. import { createVNode as _createVNode } from "vue";
  4. import { computed, defineComponent, nextTick, onMounted, shallowRef, watch } from 'vue';
  5. import { getPropsSlot } from '../_util/props-util';
  6. import PropTypes from '../_util/vue-types';
  7. import useBreakpoint from '../_util/hooks/useBreakpoint';
  8. import { responsiveArray } from '../_util/responsiveObserve';
  9. import useConfigInject from '../config-provider/hooks/useConfigInject';
  10. import ResizeObserver from '../vc-resize-observer';
  11. import eagerComputed from '../_util/eagerComputed';
  12. import useStyle from './style';
  13. import { useAvatarInjectContext } from './AvatarContext';
  14. export const avatarProps = () => ({
  15. prefixCls: String,
  16. shape: {
  17. type: String,
  18. default: 'circle'
  19. },
  20. size: {
  21. type: [Number, String, Object],
  22. default: () => 'default'
  23. },
  24. src: String,
  25. /** Srcset of image avatar */
  26. srcset: String,
  27. icon: PropTypes.any,
  28. alt: String,
  29. gap: Number,
  30. draggable: {
  31. type: Boolean,
  32. default: undefined
  33. },
  34. crossOrigin: String,
  35. loadError: {
  36. type: Function
  37. }
  38. });
  39. const Avatar = defineComponent({
  40. compatConfig: {
  41. MODE: 3
  42. },
  43. name: 'AAvatar',
  44. inheritAttrs: false,
  45. props: avatarProps(),
  46. slots: Object,
  47. setup(props, _ref) {
  48. let {
  49. slots,
  50. attrs
  51. } = _ref;
  52. const isImgExist = shallowRef(true);
  53. const isMounted = shallowRef(false);
  54. const scale = shallowRef(1);
  55. const avatarChildrenRef = shallowRef(null);
  56. const avatarNodeRef = shallowRef(null);
  57. const {
  58. prefixCls
  59. } = useConfigInject('avatar', props);
  60. const [wrapSSR, hashId] = useStyle(prefixCls);
  61. const avatarCtx = useAvatarInjectContext();
  62. const size = computed(() => {
  63. return props.size === 'default' ? avatarCtx.size : props.size;
  64. });
  65. const screens = useBreakpoint();
  66. const responsiveSize = eagerComputed(() => {
  67. if (typeof props.size !== 'object') {
  68. return undefined;
  69. }
  70. const currentBreakpoint = responsiveArray.find(screen => screens.value[screen]);
  71. const currentSize = props.size[currentBreakpoint];
  72. return currentSize;
  73. });
  74. const responsiveSizeStyle = hasIcon => {
  75. if (responsiveSize.value) {
  76. return {
  77. width: `${responsiveSize.value}px`,
  78. height: `${responsiveSize.value}px`,
  79. lineHeight: `${responsiveSize.value}px`,
  80. fontSize: `${hasIcon ? responsiveSize.value / 2 : 18}px`
  81. };
  82. }
  83. return {};
  84. };
  85. const setScaleParam = () => {
  86. if (!avatarChildrenRef.value || !avatarNodeRef.value) {
  87. return;
  88. }
  89. const childrenWidth = avatarChildrenRef.value.offsetWidth; // offsetWidth avoid affecting be transform scale
  90. const nodeWidth = avatarNodeRef.value.offsetWidth;
  91. // denominator is 0 is no meaning
  92. if (childrenWidth !== 0 && nodeWidth !== 0) {
  93. const {
  94. gap = 4
  95. } = props;
  96. if (gap * 2 < nodeWidth) {
  97. scale.value = nodeWidth - gap * 2 < childrenWidth ? (nodeWidth - gap * 2) / childrenWidth : 1;
  98. }
  99. }
  100. };
  101. const handleImgLoadError = () => {
  102. const {
  103. loadError
  104. } = props;
  105. const errorFlag = loadError === null || loadError === void 0 ? void 0 : loadError();
  106. if (errorFlag !== false) {
  107. isImgExist.value = false;
  108. }
  109. };
  110. watch(() => props.src, () => {
  111. nextTick(() => {
  112. isImgExist.value = true;
  113. scale.value = 1;
  114. });
  115. });
  116. watch(() => props.gap, () => {
  117. nextTick(() => {
  118. setScaleParam();
  119. });
  120. });
  121. onMounted(() => {
  122. nextTick(() => {
  123. setScaleParam();
  124. isMounted.value = true;
  125. });
  126. });
  127. return () => {
  128. var _a, _b;
  129. const {
  130. shape,
  131. src,
  132. alt,
  133. srcset,
  134. draggable,
  135. crossOrigin
  136. } = props;
  137. const mergeShape = (_a = avatarCtx.shape) !== null && _a !== void 0 ? _a : shape;
  138. const icon = getPropsSlot(slots, props, 'icon');
  139. const pre = prefixCls.value;
  140. const classString = {
  141. [`${attrs.class}`]: !!attrs.class,
  142. [pre]: true,
  143. [`${pre}-lg`]: size.value === 'large',
  144. [`${pre}-sm`]: size.value === 'small',
  145. [`${pre}-${mergeShape}`]: true,
  146. [`${pre}-image`]: src && isImgExist.value,
  147. [`${pre}-icon`]: icon,
  148. [hashId.value]: true
  149. };
  150. const sizeStyle = typeof size.value === 'number' ? {
  151. width: `${size.value}px`,
  152. height: `${size.value}px`,
  153. lineHeight: `${size.value}px`,
  154. fontSize: icon ? `${size.value / 2}px` : '18px'
  155. } : {};
  156. const children = (_b = slots.default) === null || _b === void 0 ? void 0 : _b.call(slots);
  157. let childrenToRender;
  158. if (src && isImgExist.value) {
  159. childrenToRender = _createVNode("img", {
  160. "draggable": draggable,
  161. "src": src,
  162. "srcset": srcset,
  163. "onError": handleImgLoadError,
  164. "alt": alt,
  165. "crossorigin": crossOrigin
  166. }, null);
  167. } else if (icon) {
  168. childrenToRender = icon;
  169. } else if (isMounted.value || scale.value !== 1) {
  170. const transformString = `scale(${scale.value}) translateX(-50%)`;
  171. const childrenStyle = {
  172. msTransform: transformString,
  173. WebkitTransform: transformString,
  174. transform: transformString
  175. };
  176. const sizeChildrenStyle = typeof size.value === 'number' ? {
  177. lineHeight: `${size.value}px`
  178. } : {};
  179. childrenToRender = _createVNode(ResizeObserver, {
  180. "onResize": setScaleParam
  181. }, {
  182. default: () => [_createVNode("span", {
  183. "class": `${pre}-string`,
  184. "ref": avatarChildrenRef,
  185. "style": _extends(_extends({}, sizeChildrenStyle), childrenStyle)
  186. }, [children])]
  187. });
  188. } else {
  189. childrenToRender = _createVNode("span", {
  190. "class": `${pre}-string`,
  191. "ref": avatarChildrenRef,
  192. "style": {
  193. opacity: 0
  194. }
  195. }, [children]);
  196. }
  197. return wrapSSR(_createVNode("span", _objectSpread(_objectSpread({}, attrs), {}, {
  198. "ref": avatarNodeRef,
  199. "class": classString,
  200. "style": [sizeStyle, responsiveSizeStyle(!!icon), attrs.style]
  201. }), [childrenToRender]));
  202. };
  203. }
  204. });
  205. export default Avatar;