feat: avatar 组件 (#1684)

* feat:avatar 组件初步

* 补充文档及样式

* 修复错误的文字

* 完善 schema 描述
This commit is contained in:
吴多益 2021-03-22 15:27:02 +08:00 committed by GitHub
parent 2d44f6a29a
commit 41ba93a486
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 368 additions and 2 deletions

View File

@ -0,0 +1,172 @@
---
title: Avatar 头像
description:
type: 0
group: ⚙ 组件
menuName: Avatar 头像
icon:
order: 27
---
用来显示用户头像
## 基本使用
```schema: scope="body"
{
"type": "avatar",
"src": "../../../examples/static/ai-fake-face.jpg"
}
```
## 文字
```schema: scope="body"
{
"type": "avatar",
"text": "AM"
}
```
## 图标
通过 icon 设置图标
```schema: scope="body"
{
"type": "avatar",
"icon": "fa fa-user"
}
```
> 如果同时存在 src、text 和 icon会优先用 src、接着 text、最后 icon
## 动态图片或文字
src、text 都支持变量,可以从上下文中动态获取图片或文字,下面的例子中第一个获取到了,而第二个没获取到,因此降级为显示 icon
```schema
{
"data": {
"myAvatar": "../../../examples/static/ai-fake-face.jpg"
},
"type": "page",
"body": [
{
"type": "avatar",
"icon": "fa fa-user",
"src": "$myAvatar"
},
{
"type": "avatar",
"icon": "fa fa-user",
"src": "$other"
}
]
}
```
## 方形和圆角形
可以通过 shape 改成方形或圆角形
```schema: scope="body"
[
{
"type": "avatar",
"shape": "square",
"text": "AM"
},
{
"type": "avatar",
"shape": "rounded",
"text": "AM",
"style": {
"marginLeft": "10px"
}
}
]
```
## 大小
通过 size 可以控制头像的大小
```schema: scope="body"
[
{
"type": "avatar",
"size": 20,
"src": "../../../examples/static/ai-fake-face.jpg"
},
{
"type": "avatar",
"size": 60,
"src": "../../../examples/static/ai-fake-face.jpg"
}
]
```
## 图片拉伸方式
通过 `fit` 可以控制图片拉伸方式,默认是 `cover`,具体细节可以参考 MDN [文档](https://developer.mozilla.org/zh-CN/docs/Web/CSS/object-fit)
```schema: scope="body"
[
{
"type": "avatar",
"fit": "cover",
"src": "../../../examples/static/plumeria.jpeg"
},
{
"type": "avatar",
"fit": "fill",
"src": "../../../examples/static/plumeria.jpeg"
},
{
"type": "avatar",
"fit": "contain",
"src": "../../../examples/static/plumeria.jpeg"
},
{
"type": "avatar",
"fit": "none",
"src": "../../../examples/static/plumeria.jpeg"
},
{
"type": "avatar",
"fit": "scale-down",
"src": "../../../examples/static/plumeria.jpeg"
}
]
```
## 样式
可以通过 style 来控制背景及文字颜色
```schema: scope="body"
{
"type": "avatar",
"text": "AM",
"style": {
"background": "#DB3E35",
"color": "#FFFFFF"
}
}
```
## 属性表
| 属性名 | 类型 | 默认值 | 说明 |
| --------- | -------- | ------ | --------------------- |
| className | `string` | | 外层 dom 的类名 |
| fit | `string` | cover | 图片缩放类型 |
| src | `string` | | 图片地址 |
| text | `string` | | 文字 |
| icon | `string` | | 图标 |
| shape | `string` | circle | 形状,也可以是 square |
| size | `number` | 40 | 大小 |
| style | `object` | | 外层 dom 的样式 |

View File

@ -1088,6 +1088,16 @@ export const components = [
{
label: '其他',
children: [
{
label: 'Avatar 头像',
path: '/zh-CN/components/avatar',
getComponent: () =>
// @ts-ignore
import('../../docs/zh-CN/components/avatar.md').then(
makeMarkdownRenderer
)
},
{
label: 'Audio 音频',
path: '/zh-CN/components/audio',

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

View File

@ -37,8 +37,7 @@ fis.set('project.files', [
'/scss/themes/*.scss',
'/examples/*.html',
'/examples/*.tpl',
'/examples/static/*.png',
'/examples/static/*.svg',
'/examples/static/*',
'/src/**.html',
'mock/**'
]);

View File

@ -160,6 +160,9 @@
--Audio-volume-width: #{px2rem(20px)};
--Audio-volumeControl-width: #{px2rem(110px)};
--Avatar-bg: #{$gray300};
--Avatar-width: #{px2rem(40px)};
--Button--danger-bg: var(--danger);
--Button--danger-border: var(--Button--danger-bg);
--Button--danger-color: var(--button-color);

View File

@ -0,0 +1,37 @@
.#{$ns}Avatar {
background: var(--Avatar-bg);
width: var(--Avatar-width);
height: var(--Avatar-width);
line-height: var(--Avatar-width);
display: inline-block;
overflow: hidden;
flex-shrink: 0;
border-radius: 50%;
text-align: center;
&--square {
border-radius: 0%;
}
&--rounded {
border-radius: 10%;
}
i {
font-size: var(--fontSizeLg);
}
img {
color: transparent;
width: 100%;
height: 100%;
object-fit: cover;
}
&:hover {
img,
i {
transform: scale(1.1);
}
}
}

View File

@ -9,6 +9,7 @@
@import '../layout/hbox';
@import '../layout/vbox';
@import '../components/button'; // 这个要放在最前面
@import '../components/avatar';
@import '../components/breadcrumb';
@import '../components/modal';
@import '../components/drawer';

View File

@ -63,6 +63,7 @@ export type SchemaType =
| 'alert'
| 'app'
| 'audio'
| 'avatar'
| 'button-group'
| 'button-toolbar'
| 'breadcrumb'

View File

@ -48,6 +48,7 @@ export * from './Schema';
import './renderers/Action';
import './renderers/Alert';
import './renderers/App';
import './renderers/Avatar';
import './renderers/Remark';
import './renderers/ButtonGroup';
import './renderers/ButtonToolbar';

142
src/renderers/Avatar.tsx Normal file
View File

@ -0,0 +1,142 @@
/**
* @file
*/
import React from 'react';
import {Renderer, RendererProps} from '../factory';
import {
BaseSchema,
SchemaClassName,
SchemaIcon,
SchemaUrlPath
} from '../Schema';
import {resolveVariable, resolveVariableAndFilter} from '../utils/tpl-builtin';
/**
* Avatar
* https://baidu.gitee.io/amis/docs/components/avatar
*/
export interface AvatarSchema extends BaseSchema {
/**
*
*/
type: 'avatar';
/**
*
*/
size?: number;
/**
*
*/
shape?: 'circle' | 'square';
/**
*
*/
icon?: string;
/**
*
*/
text?: string;
/**
*
*/
src?: string;
/**
*
*/
fit?: 'fill' | 'contain' | 'cover' | 'none' | 'scale-down';
/**
*
*/
alt?: string;
/**
*
*/
className?: SchemaClassName;
/**
*
*/
style?: {
[propName: string]: any;
};
}
export interface AvatarProps
extends RendererProps,
Omit<AvatarSchema, 'type' | 'className'> {}
export class AvatarField extends React.Component<AvatarProps, object> {
static defaultProps = {
size: 40,
shape: 'circle',
fit: 'cover',
icon: 'fa fa-user'
};
render() {
let {
className,
icon,
text,
src,
fit,
data,
shape,
size,
style,
classnames: cx,
props
} = this.props;
let sizeStyle = {
height: size,
width: size,
lineHeight: size + 'px'
};
let avatar = <i className={icon} />;
if (typeof text === 'string' && text[0] === '$') {
text = resolveVariable(text, data);
}
if (typeof src === 'string' && src[0] === '$') {
src = resolveVariable(src, data);
}
if (text) {
if (text.length > 2) {
text = text.substring(0, 2).toUpperCase();
}
avatar = <span>{text}</span>;
}
if (src) {
avatar = <img src={src} style={{objectFit: fit}} />;
}
return (
<div
className={cx('Avatar', className, `Avatar--${shape}`)}
style={{...sizeStyle, ...style}}
{...props}
>
{avatar}
</div>
);
}
}
@Renderer({
test: /(^|\/)avatar$/,
name: 'avatar'
})
export class AvatarFieldRenderer extends AvatarField {}