mirror of
https://gitee.com/baidu/amis.git
synced 2024-11-29 18:48:45 +08:00
feat: service 支持 js: 请求,使得动态渲染支持 JavaScript 函数 (#4866)
This commit is contained in:
parent
78955f4ea9
commit
e871f24c61
@ -216,6 +216,8 @@ amis 中部分组件,作为展示组件,自身没有**使用接口初始化
|
||||
|
||||
它将`data`返回的对象作为 amis 页面配置,进行了解析渲染,实现动态渲染页面的功能。
|
||||
|
||||
### jsonp 请求
|
||||
|
||||
`schemaApi` 同样支持 `jsonp` 请求,完整用法请参考 amis-admin 项目。
|
||||
|
||||
```schema: scope="body"
|
||||
@ -242,6 +244,44 @@ amis 中部分组件,作为展示组件,自身没有**使用接口初始化
|
||||
})();
|
||||
```
|
||||
|
||||
### js 请求
|
||||
|
||||
> 2.1.0 及以上版本
|
||||
|
||||
`schemaApi` 支持 `js` 请求,它会发起一个 xhr 请求去下载 js 文件后执行
|
||||
|
||||
```schema: scope="body"
|
||||
{
|
||||
"type": "service",
|
||||
"schemaApi": "js:/api/mock2/service/jsschema"
|
||||
}
|
||||
```
|
||||
|
||||
这个接口的返回结果期望是一段 JavaScript 代码,和普通 json 返回结果最大的不同是这里可以执行 JavaScript 代码,比如支持 onClick 函数
|
||||
|
||||
```javascript
|
||||
return {
|
||||
type: 'button',
|
||||
label: '按钮修改',
|
||||
onClick: (e, props) => {
|
||||
alert('消息通知');
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
这段代码里可以通过 api 变量拿到当前请求的 api 参数,比如 url 地址,可以通过判断进行二次处理
|
||||
|
||||
```javascript
|
||||
console.log(api);
|
||||
return {
|
||||
type: 'button',
|
||||
label: '按钮修改',
|
||||
onClick: (e, props) => {
|
||||
alert(api.url);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
## 动态渲染表单项
|
||||
|
||||
默认 Service 可以通过配置`schemaApi` [动态渲染页面内容](../service#%E5%8A%A8%E6%80%81%E6%B8%B2%E6%9F%93%E9%A1%B5%E9%9D%A2),但是如果想渲染表单项,请返回下面这种格式:
|
||||
|
@ -37,48 +37,48 @@
|
||||
document.write(
|
||||
`<link rel="stylesheet" title="ang" ${
|
||||
theme !== 'ang' ? 'disabled' : ''
|
||||
} href="${__uri('../../scss/themes/ang.scss')}" />`
|
||||
} href="${__uri('amis/lib/themes/ang.css')}" />`
|
||||
);
|
||||
document.write(
|
||||
`<link rel="stylesheet" title="cxd" ${
|
||||
theme !== 'cxd' ? 'disabled' : ''
|
||||
} href="${__uri('../../scss/themes/cxd.scss')}" />`
|
||||
} href="${__uri('amis/lib/themes/cxd.css')}" />`
|
||||
);
|
||||
document.write(
|
||||
`<link rel="stylesheet" title="dark" ${
|
||||
theme !== 'dark' ? 'disabled' : ''
|
||||
} href="${__uri('../../scss/themes/dark.scss')}" />`
|
||||
} href="${__uri('amis/lib/themes/dark.css')}" />`
|
||||
);
|
||||
document.write(
|
||||
`<link rel="stylesheet" title="antd" ${
|
||||
theme !== 'antd' ? 'disabled' : ''
|
||||
} href="${__uri('../../scss/themes/antd.scss')}" />`
|
||||
} href="${__uri('amis/lib/themes/antd.css')}" />`
|
||||
);
|
||||
} else {
|
||||
document.write(
|
||||
`<link rel="stylesheet" title="ang" ${
|
||||
theme !== 'ang' ? 'disabled' : ''
|
||||
} href="${__uri('../../scss/themes/ang-ie11.scss')}" />`
|
||||
} href="${__uri('amis/lib/themes/ang-ie11.css')}" />`
|
||||
);
|
||||
document.write(
|
||||
`<link rel="stylesheet" title="cxd" ${
|
||||
theme !== 'cxd' ? 'disabled' : ''
|
||||
} href="${__uri('../../scss/themes/cxd-ie11.scss')}" />`
|
||||
} href="${__uri('amis/lib/themes/cxd-ie11.css')}" />`
|
||||
);
|
||||
document.write(
|
||||
`<link rel="stylesheet" title="dark" ${
|
||||
theme !== 'dark' ? 'disabled' : ''
|
||||
} href="${__uri('../../scss/themes/dark-ie11.scss')}" />`
|
||||
} href="${__uri('amis/lib/themes/dark-ie11.css')}" />`
|
||||
);
|
||||
document.write(
|
||||
`<link rel="stylesheet" title="antd" ${
|
||||
theme !== 'antd' ? 'disabled' : ''
|
||||
} href="${__uri('../../scss/themes/antd-ie11.scss')}" />`
|
||||
} href="${__uri('amis/lib/themes/antd-ie11.css')}" />`
|
||||
);
|
||||
}
|
||||
</script>
|
||||
<!--ignore-->
|
||||
<link rel="stylesheet" href="../../scss/helper.scss" />
|
||||
<link rel="stylesheet" href="amis/lib/helper.css" />
|
||||
<!--ignore-->
|
||||
</head>
|
||||
|
||||
|
@ -37,12 +37,13 @@ function mockResponse(event, context, callback) {
|
||||
body: JSON.stringify(json)
|
||||
});
|
||||
},
|
||||
send(res) {
|
||||
send(res, headers = {}) {
|
||||
callback(null, {
|
||||
statusCode: 200,
|
||||
headers: {
|
||||
...createHeaders(event.headers),
|
||||
'Content-Type': 'text/javascript'
|
||||
'Content-Type': 'text/javascript',
|
||||
...headers
|
||||
},
|
||||
json: false,
|
||||
body: res
|
||||
|
14
mock/cfc/mock/service/jsschema.js
Normal file
14
mock/cfc/mock/service/jsschema.js
Normal file
@ -0,0 +1,14 @@
|
||||
module.exports = function (req, res) {
|
||||
return res.send(
|
||||
`
|
||||
return {
|
||||
type: 'button',
|
||||
label: '按钮修改',
|
||||
onClick: (e, props) => {
|
||||
alert('消息通知');
|
||||
}
|
||||
}
|
||||
`,
|
||||
{'Content-Type': 'text/javascript'}
|
||||
);
|
||||
};
|
@ -98,7 +98,7 @@ export interface RenderOptions
|
||||
|
||||
export interface fetcherConfig {
|
||||
url: string;
|
||||
method?: 'get' | 'post' | 'put' | 'patch' | 'delete' | 'jsonp';
|
||||
method?: 'get' | 'post' | 'put' | 'patch' | 'delete' | 'jsonp' | 'js';
|
||||
data?: any;
|
||||
config?: any;
|
||||
}
|
||||
|
@ -76,7 +76,7 @@ export interface BaseApiObject {
|
||||
/**
|
||||
* API 发送类型
|
||||
*/
|
||||
method?: 'get' | 'post' | 'put' | 'delete' | 'patch' | 'jsonp';
|
||||
method?: 'get' | 'post' | 'put' | 'delete' | 'patch' | 'jsonp' | 'js';
|
||||
|
||||
/**
|
||||
* API 发送目标地址
|
||||
@ -230,7 +230,7 @@ export interface fetcherResult {
|
||||
}
|
||||
|
||||
export interface fetchOptions {
|
||||
method?: 'get' | 'post' | 'put' | 'patch' | 'delete' | 'jsonp';
|
||||
method?: 'get' | 'post' | 'put' | 'patch' | 'delete' | 'jsonp' | 'js';
|
||||
successMessage?: string;
|
||||
errorMessage?: string;
|
||||
autoAppend?: boolean;
|
||||
|
@ -19,7 +19,8 @@ import isPlainObject from 'lodash/isPlainObject';
|
||||
import {debug, warning} from './debug';
|
||||
import {evaluate, parse} from 'amis-formula';
|
||||
|
||||
const rSchema = /(?:^|raw\:)(get|post|put|delete|patch|options|head|jsonp):/i;
|
||||
const rSchema =
|
||||
/(?:^|raw\:)(get|post|put|delete|patch|options|head|jsonp|js):/i;
|
||||
|
||||
interface ApiCacheConfig extends ApiObject {
|
||||
cachedPromise: Promise<any>;
|
||||
@ -178,7 +179,7 @@ export function buildApi(
|
||||
}
|
||||
|
||||
// get 类请求,把 data 附带到 url 上。
|
||||
if (api.method === 'get' || api.method === 'jsonp') {
|
||||
if (api.method === 'get' || api.method === 'jsonp' || api.method === 'js') {
|
||||
if (
|
||||
!api.data &&
|
||||
((!~raw.indexOf('$') && autoAppend) || api.forceAppendDataToQuery)
|
||||
@ -424,6 +425,10 @@ export function wrapFetcher(
|
||||
return wrapAdaptor(jsonpFetcher(api), api);
|
||||
}
|
||||
|
||||
if (api.method?.toLocaleLowerCase() === 'js') {
|
||||
return wrapAdaptor(jsFetcher(fn, api), api);
|
||||
}
|
||||
|
||||
if (typeof api.cache === 'number' && api.cache > 0) {
|
||||
const apiCache = getApiCache(api);
|
||||
return wrapAdaptor(
|
||||
@ -469,6 +474,37 @@ export function wrapAdaptor(promise: Promise<fetcherResult>, api: ApiObject) {
|
||||
: promise.then(ret => responseAdaptor(ret, api));
|
||||
}
|
||||
|
||||
/**
|
||||
* 请求远程 js 文件然后 new Function 执行,用于 schemaApi 支持 JavaScript
|
||||
* @param api
|
||||
* @returns
|
||||
*/
|
||||
export function jsFetcher(
|
||||
fetcher: (config: fetcherConfig) => Promise<fetcherResult>,
|
||||
api: ApiObject
|
||||
): Promise<fetcherResult> {
|
||||
return new Promise((resolve, reject) => {
|
||||
// 大概也不会有人用 post
|
||||
api.method = 'get';
|
||||
fetcher(api).then((response: fetcherResult) => {
|
||||
if (typeof response.data === 'string') {
|
||||
const result = new Function('api', response.data)(api);
|
||||
resolve({
|
||||
status: 200,
|
||||
headers: {},
|
||||
data: {
|
||||
status: 0,
|
||||
msg: '',
|
||||
data: result
|
||||
}
|
||||
});
|
||||
} else {
|
||||
reject('must return string: ' + response.data);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function jsonpFetcher(api: ApiObject): Promise<fetcherResult> {
|
||||
return new Promise((resolve, reject) => {
|
||||
let script: HTMLScriptElement | null = document.createElement('script');
|
||||
|
@ -490,7 +490,7 @@ export interface SchemaApiObject {
|
||||
/**
|
||||
* API 发送类型
|
||||
*/
|
||||
method?: 'get' | 'post' | 'put' | 'delete' | 'patch' | 'jsonp';
|
||||
method?: 'get' | 'post' | 'put' | 'delete' | 'patch' | 'jsonp' | 'js';
|
||||
|
||||
/**
|
||||
* API 发送目标地址
|
||||
|
@ -33,7 +33,7 @@ export interface fetcherResult {
|
||||
}
|
||||
|
||||
export interface fetchOptions {
|
||||
method?: 'get' | 'post' | 'put' | 'patch' | 'delete' | 'jsonp';
|
||||
method?: 'get' | 'post' | 'put' | 'patch' | 'delete' | 'jsonp' | 'js';
|
||||
successMessage?: string;
|
||||
errorMessage?: string;
|
||||
autoAppend?: boolean;
|
||||
|
Loading…
Reference in New Issue
Block a user