Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: 新增全局变量功能 #11349

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
151 changes: 83 additions & 68 deletions examples/components/EventAction/update-data/SetVariable.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,34 @@ import update from 'lodash/update';
import isEqual from 'lodash/isEqual';
import {cloneObject, setVariable} from 'amis-core';

const namespace = 'appVariables';
const initData = JSON.parse(sessionStorage.getItem(namespace)) || {
ProductName: 'BCC',
Banlance: 1234.888,
ProductNum: 10,
isOnline: false,
ProductList: ['BCC', 'BOS', 'VPC'],
PROFILE: {
FirstName: 'Amis',
Age: 18,
Address: {
street: 'ShangDi',
postcode: 100001
}
const variables = [
{
key: 'xxx',
defaultValue: 'yyy'
},

{
key: 'ProductName',
defaultValue: ''
},

{
key: 'count',
defaultValue: 0,
scope: 'page',
storageOn: 'client'
},

{
key: 'arr',
defaultValue: []
},

{
key: 'select',
defaultValue: ''
}
};
];

export default {
/** schema配置 */
Expand All @@ -30,7 +42,7 @@ export default {
body: [
{
type: 'tpl',
tpl: '变量的命名空间通过环境变量设置为了<code>appVariables</code>, 可以通过\\${appVariables.xxx}来取值'
tpl: '变量的命名空间通过环境变量设置为了<code>global</code>, 可以通过\\${global.xxx}来取值'
},
{
type: 'container',
Expand All @@ -43,12 +55,12 @@ export default {
body: [
{
type: 'tpl',
tpl: '<h2>数据域appVariables</h2>'
tpl: '<h2>数据域global</h2>'
},
{
type: 'json',
id: 'u:44521540e64c',
source: '${appVariables}',
source: '${global}',
levelExpand: 10
},
{
Expand All @@ -59,7 +71,7 @@ export default {
},
{
type: 'tpl',
tpl: '<h3>变量中的<code>ProductName (\\${appVariables.ProductName})</code>: <strong>${appVariables.ProductName|default:-}</strong></h3>',
tpl: '<h3>变量中的<code>ProductName (\\${global.ProductName})</code>: <strong>${global.ProductName|default:-}</strong></h3>',
inline: false,
id: 'u:98ed5c5534ef'
}
Expand All @@ -82,7 +94,24 @@ export default {
actions: [
{
args: {
path: 'appVariables.ProductName',
path: 'global.ProductName',
value: '${event.data.value}'
},
actionType: 'setValue'
},

{
args: {
path: 'global.arr',
value:
'${[{label: event.data.value, value: event.data.value}]}'
},
actionType: 'setValue'
},

{
args: {
path: 'global.select',
value: '${event.data.value}'
},
actionType: 'setValue'
Expand All @@ -95,8 +124,39 @@ export default {
type: 'static',
label: '产品名称描述',
id: 'u:7bd4e2a4f95e',
value: '${appVariables.ProductName}',
value: '${global.ProductName}',
name: 'staticName'
},

{
type: 'input-number',
label: 'Count (client)',
description: '存储自动存入客户端,刷新页面后数据还在',
id: 'u:7bd4e2a4f95e',
value: '${global.count}',
name: 'count',
onEvent: {
change: {
weight: 0,
actions: [
{
args: {
path: 'global.count',
value: '${event.data.value}'
},
actionType: 'setValue'
}
]
}
}
},

{
type: 'select',
label: 'select(${global.select})',
name: 'select',
value: '${global.select}',
source: '${global.arr}'
}
],
id: 'u:dc2580fa447a'
Expand All @@ -109,7 +169,7 @@ export default {
actions: [
{
args: {
path: 'appVariables.ProductName',
path: 'global.ProductName',
value: '${event.data.ProductName}'
},
actionType: 'setValue'
Expand All @@ -119,51 +179,6 @@ export default {
}
},
props: {
data: {[namespace]: JSON.parse(sessionStorage.getItem(namespace))}
},
/** 环境变量 */
env: {
beforeSetData: (renderer, action, event) => {
const value = event?.data?.value ?? action?.args?.value;
const path = action?.args?.path;
const {session = 'global'} = renderer.props?.env ?? {};
const comptList = event?.context?.scoped?.getComponentsByRefPath(
session,
path
);

for (let component of comptList) {
const {$path: targetPath, $schema: targetSchema} = component?.props;
const {$path: triggerPath, $schema: triggerSchema} = renderer?.props;

if (
!component.setData &&
(targetPath === triggerPath || isEqual(targetSchema, triggerSchema))
) {
continue;
}

if (component?.props?.onChange) {
const submitOnChange = !!component.props?.$schema?.submitOnChange;

component.props.onChange(value, submitOnChange, true);
} else if (component?.setData) {
const currentData = JSON.parse(
sessionStorage.getItem(namespace) || JSON.stringify(initData)
);
const varPath = path.replace(/^appVariables\./, '');

update(currentData, varPath, origin => {
return typeof value === typeof origin ? value : origin;
});

sessionStorage.setItem(namespace, JSON.stringify(currentData));
const newCtx = cloneObject(component?.props?.data ?? {});
setVariable(newCtx, path, value, true);

component.setData(newCtx, false);
}
}
}
globalVars: variables
}
};
7 changes: 1 addition & 6 deletions examples/components/Example.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -668,12 +668,7 @@ export const examples = [
{
label: '更新全局变量数据',
path: '/examples/action/setdata/variable',
component: makeSchemaRenderer(
SetVariable.schema,
SetVariable.props ?? {},
true,
SetVariable.env
)
component: makeSchemaRenderer(SetVariable)
}
]
},
Expand Down
9 changes: 9 additions & 0 deletions examples/components/SchemaRender.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,15 @@ export default function (schema, schemaProps, showCode, envOverrides) {
};
}

if (!schema.type && schema.schema) {
schemaProps = schema.props;
envOverrides = schema.env;
showCode = schema.showCode ?? true;
schema = {
...schema.schema
};
}

return withRouter(
class extends React.Component {
static displayName = 'SchemaRenderer';
Expand Down
3 changes: 3 additions & 0 deletions packages/amis-core/src/Root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,14 @@ import {
StatusScopedWrapper,
StatusScopedProps
} from './StatusScoped';
import {GlobalVariableItem} from './globalVar';

export interface RootRenderProps {
globalVars?: Array<GlobalVariableItem>;
location?: Location;
theme?: string;
data?: Record<string, any>;
context?: Record<string, any>;
locale?: string;
[propName: string]: any;
}
Expand Down
8 changes: 7 additions & 1 deletion packages/amis-core/src/RootRenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export class RootRenderer extends React.Component<RootRendererProps> {
this.store.updateContext(props.context);
this.store.initData(props.data);
this.store.updateLocation(props.location, this.props.env?.parseLocation);
this.store.setGlobalVars(props.globalVars);

// 将数据里面的函数批量的绑定到 this 上
bulkBindFunctions<RootRenderer /*为毛 this 的类型自动识别不出来?*/>(this, [
Expand Down Expand Up @@ -97,6 +98,11 @@ export class RootRenderer extends React.Component<RootRendererProps> {
componentDidUpdate(prevProps: RootRendererProps) {
const props = this.props;

// 更新全局变量
if (props.globalVars !== prevProps.globalVars) {
this.store.setGlobalVars(props.globalVars);
}

if (props.location !== prevProps.location) {
this.store.updateLocation(props.location, this.props.env?.parseLocation);
}
Expand Down Expand Up @@ -521,7 +527,7 @@ export class RootRenderer extends React.Component<RootRendererProps> {
}

render() {
const {pathPrefix, schema, render, ...rest} = this.props;
const {pathPrefix, schema, render, globalVars, ...rest} = this.props;
const store = this.store;

if (store.runtimeError) {
Expand Down
38 changes: 35 additions & 3 deletions packages/amis-core/src/SchemaRenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ import {isExpression} from './utils/formula';
import {StatusScopedProps} from './StatusScoped';
import {evalExpression, filter} from './utils/tpl';
import Animations from './components/Animations';
import {cloneObject} from './utils/object';
import {observeGlobalVars} from './globalVar';

interface SchemaRendererProps
extends Partial<Omit<RendererProps, 'statusStore'>>,
Expand Down Expand Up @@ -101,6 +103,8 @@ export class SchemaRenderer extends React.Component<SchemaRendererProps, any> {
schema: any;
path: string;

tmpData: any;

toDispose: Array<() => any> = [];
unbindEvent: (() => void) | undefined = undefined;
unbindGlobalEvent: (() => void) | undefined = undefined;
Expand All @@ -114,13 +118,16 @@ export class SchemaRenderer extends React.Component<SchemaRendererProps, any> {
this.reRender = this.reRender.bind(this);
this.resolveRenderer(this.props);
this.dispatchEvent = this.dispatchEvent.bind(this);
this.handleGlobalVarChange = this.handleGlobalVarChange.bind(this);

const schema = props.schema;

// 监听statusStore更新
this.toDispose.push(
reaction(
() => {
const id = filter(props.schema.id, props.data);
const name = filter(props.schema.name, props.data);
const id = filter(schema.id, props.data);
const name = filter(schema.name, props.data);
return `${
props.statusStore.visibleState[id] ??
props.statusStore.visibleState[name]
Expand All @@ -135,6 +142,10 @@ export class SchemaRenderer extends React.Component<SchemaRendererProps, any> {
() => this.forceUpdate()
)
);

this.toDispose.push(
observeGlobalVars(schema, props.topStore, this.handleGlobalVarChange)
);
}

componentWillUnmount() {
Expand Down Expand Up @@ -172,6 +183,21 @@ export class SchemaRenderer extends React.Component<SchemaRendererProps, any> {
return false;
}

handleGlobalVarChange() {
const handler = this.renderer?.onGlobalVarChanged;
const newData = cloneObject(this.props.data);

// 如果渲染器自己做了实现,且返回 false,则不再继续往下执行
if (handler?.(this.cRef, this.props.schema, newData) === false) {
return;
}

this.tmpData = newData;
this.forceUpdate(() => {
delete this.tmpData;
});
}

resolveRenderer(props: SchemaRendererProps, force = false): any {
let schema = props.schema;
let path = props.$path;
Expand Down Expand Up @@ -308,7 +334,10 @@ export class SchemaRenderer extends React.Component<SchemaRendererProps, any> {
? evalExpression(_.staticOn, rest.data)
: _.static ?? rest.defaultStatic),
...subProps,
data: subProps.data || rest.data,
data:
this.tmpData && subProps.data === this.props.data
? this.tmpData
: subProps.data || rest.data,
env: env
});
}
Expand Down Expand Up @@ -517,6 +546,9 @@ export class SchemaRenderer extends React.Component<SchemaRendererProps, any> {
mobileUI: schema.useMobileUI === false ? false : rest.mobileUI
};

// 用于全局变量刷新
props.data = this.tmpData || props.data;

// style 支持公式
if (schema.style) {
(props as any).style = buildStyle(schema.style, detectData);
Expand Down
5 changes: 5 additions & 0 deletions packages/amis-core/src/actions/CmptAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ export class CmptAction implements RendererAction {

/** 如果args中携带path参数, 则认为是全局变量赋值, 否则认为是组件变量赋值 */
if (action.actionType === 'setValue' && path && typeof path === 'string') {
if (path.startsWith('global.')) {
const topStore = renderer.props.topStore;
topStore?.updateGlobalVarValue(path.substring(7), action.args.value);
}

const beforeSetData = event?.context?.env?.beforeSetData;
if (beforeSetData && typeof beforeSetData === 'function') {
const res = await beforeSetData(renderer, action, event);
Expand Down
Loading
Loading