feat: web-component 组件 (#2368)

This commit is contained in:
吴多益 2021-08-09 22:21:54 +08:00 committed by GitHub
parent a3f9ffd049
commit 7e0c7a8b85
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 158 additions and 0 deletions

View File

@ -0,0 +1,60 @@
---
title: Web Component
description:
type: 0
group: ⚙ 组件
menuName: WebComponent
icon:
order: 73
---
专门用来渲染 web component 的组件,可以通过这种方式来扩展 amis 组件,比如使用 Angular。
## 基本用法
比如下面这个 web component
```
<random-number prefix="hello" class="my-class"></random-number>
```
使用 amis 可以这样渲染出来
```schema: scope="body"
{
"type": "web-component",
"tag": "random-number",
"props": {
"prefix": "hello",
"class": "my-class"
}
}
```
其中 `tag` 指定标签,属性放在 `props` 对象里props 里的值支持变量替换,比如:
```schema
{
"data": {
"text": "World"
},
"type": "page",
"body": {
"type": "web-component",
"tag": "random-number",
"props": {
"prefix": "${text}"
}
}
}
```
## 属性表
| 属性名 | 类型 | 默认值 | 说明 |
| ------ | ----------------------------------------- | ----------------- | ----------------------------- |
| type | `string` | `"web-component"` | 指定为 web-component 渲染器 |
| tag | `string` | | 具体使用的 web-component 标签 |
| props | `object` | | 标签上的属性 |
| body | [SchemaNode](../../docs/types/schemanode) | | 子节点 |

View File

@ -1143,6 +1143,15 @@ export const components = [
import('../../docs/zh-CN/components/wizard.md').then( import('../../docs/zh-CN/components/wizard.md').then(
makeMarkdownRenderer makeMarkdownRenderer
) )
},
{
label: 'Web Component',
path: '/zh-CN/components/web-component',
getComponent: () =>
// @ts-ignore
import('../../docs/zh-CN/components/web-component.md').then(
makeMarkdownRenderer
)
} }
] ]
} }

View File

@ -85,6 +85,7 @@ import Tab3Schema from './Tabs/Tab3';
import TestComponent from './Test'; import TestComponent from './Test';
import APP from './APP/index'; import APP from './APP/index';
import {normalizeLink} from '../../src/utils/normalizeLink'; import {normalizeLink} from '../../src/utils/normalizeLink';
import './WebComponent';
export const examples = [ export const examples = [
{ {

View File

@ -0,0 +1,27 @@
/**
* web component 的示例
*/
class RandomNumber extends HTMLElement {
connectedCallback() {
const prefix = this.getAttribute('prefix') || '';
const shadow = this.attachShadow({mode: 'open'});
const text = document.createElement('span');
text.textContent = `${prefix}: ${Math.floor(Math.random() * 1000)}`;
shadow.appendChild(text);
setInterval(function () {
const count = `${prefix}: ${Math.floor(Math.random() * 1000)}`;
text.textContent = count;
}, 2000);
}
}
class WebContainer extends HTMLElement {
connectedCallback() {
const shadow = this.attachShadow();
shadow.innerHTML = 'web-container';
}
}
customElements.define('random-number', RandomNumber);
customElements.define('web-container', WebContainer);

View File

@ -193,6 +193,7 @@ export type SchemaType =
| 'video' | 'video'
| 'wizard' | 'wizard'
| 'wrapper' | 'wrapper'
| 'web-component'
| 'anchor-nav' | 'anchor-nav'
| 'steps' | 'steps'
| 'control' | 'control'

View File

@ -161,6 +161,7 @@ import './renderers/Steps';
import './renderers/Markdown'; import './renderers/Markdown';
import './renderers/TableView'; import './renderers/TableView';
import './renderers/Code'; import './renderers/Code';
import './renderers/WebComponent';
import Scoped, {ScopedContext} from './Scoped'; import Scoped, {ScopedContext} from './Scoped';

View File

@ -0,0 +1,59 @@
import React from 'react';
import {Renderer, RendererProps} from '../factory';
import {BaseSchema, SchemaCollection} from '../Schema';
import {resolveVariable} from '../utils/tpl-builtin';
import mapValues from 'lodash/mapValues';
/**
* WebComponent
* https://baidu.gitee.io/amis/docs/components/web-component
*/
export interface WebComponentSchema extends BaseSchema {
/**
* web-component
*/
type: 'web-component';
/**
*
*/
tag: string;
/**
*
*/
body: SchemaCollection;
/**
*
*/
prpos?: {
[propName: string]: any;
};
}
export default class WebComponent extends React.Component<RendererProps> {
renderBody(): JSX.Element | null {
const {body, render} = this.props;
return body ? (render('body', body) as JSX.Element) : null;
}
render() {
const {tag, props, data} = this.props;
const propsValues = mapValues(props, s => {
if (typeof s === 'string') {
return resolveVariable(s, data) || s;
} else {
return s;
}
});
const Component = (tag as keyof JSX.IntrinsicElements) || 'div';
return <Component {...propsValues}>{this.renderBody()}</Component>;
}
}
@Renderer({
type: 'web-component'
})
export class WebComponentRenderer extends WebComponent {}