mirror of
https://gitee.com/baidu/amis.git
synced 2024-11-30 02:48:55 +08:00
feat: web-component 组件 (#2368)
This commit is contained in:
parent
a3f9ffd049
commit
7e0c7a8b85
60
docs/zh-CN/components/web-component.md
Normal file
60
docs/zh-CN/components/web-component.md
Normal 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) | | 子节点 |
|
@ -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
|
||||||
|
)
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -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 = [
|
||||||
{
|
{
|
||||||
|
27
examples/components/WebComponent.jsx
Normal file
27
examples/components/WebComponent.jsx
Normal 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);
|
@ -193,6 +193,7 @@ export type SchemaType =
|
|||||||
| 'video'
|
| 'video'
|
||||||
| 'wizard'
|
| 'wizard'
|
||||||
| 'wrapper'
|
| 'wrapper'
|
||||||
|
| 'web-component'
|
||||||
| 'anchor-nav'
|
| 'anchor-nav'
|
||||||
| 'steps'
|
| 'steps'
|
||||||
| 'control'
|
| 'control'
|
||||||
|
@ -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';
|
||||||
|
|
||||||
|
59
src/renderers/WebComponent.tsx
Normal file
59
src/renderers/WebComponent.tsx
Normal 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 {}
|
Loading…
Reference in New Issue
Block a user