mirror of
https://github.com/Tencent/tmagic-editor.git
synced 2026-08-06 04:48:33 +00:00
feat(editor): getEvent/getMethod 支持节点上下文参数
便于插件通过 beforeGetEvent/afterGetEvent 等钩子按节点定制事件与方法列表;getMethod 第二参数调整为 { node?, targetId? }。
This commit is contained in:
parent
cc34891bb2
commit
d2a02e16d2
@ -65,6 +65,7 @@ eventsService.setEvent('button', [
|
||||
- **参数:**
|
||||
|
||||
- `{string}` type 组件类型
|
||||
- `{ node?: MNode | null }` data 可选上下文,便于插件按节点定制事件列表(默认 `{}`)
|
||||
|
||||
- **返回:**
|
||||
|
||||
@ -72,15 +73,25 @@ eventsService.setEvent('button', [
|
||||
|
||||
- **详情:**
|
||||
|
||||
获取指定组件类型的事件列表
|
||||
获取指定组件类型的事件列表。默认实现仅按 `type` 返回注册事件;可通过 `usePlugin` 的 `beforeGetEvent` / `afterGetEvent` 读取 `data.node` 做节点级过滤或扩展。
|
||||
|
||||
- **示例:**
|
||||
|
||||
```js
|
||||
import { eventsService } from '@tmagic/editor';
|
||||
|
||||
const events = eventsService.getEvent('button');
|
||||
const events = eventsService.getEvent('button', { node });
|
||||
console.log(events); // [{ label: '点击', value: 'click' }, ...]
|
||||
|
||||
// 插件按节点定制
|
||||
eventsService.usePlugin({
|
||||
afterGetEvent(events, type, data) {
|
||||
if (data?.node?.id === 'btn_1') {
|
||||
return events.filter((item) => item.value !== 'longpress');
|
||||
}
|
||||
return events;
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
## setMethods
|
||||
@ -146,7 +157,9 @@ eventsService.setMethod('video', [
|
||||
- **参数:**
|
||||
|
||||
- `{string}` type 组件类型
|
||||
- `{string | number}` _targetId 目标节点id(保留参数,便于扩展时按节点定制)
|
||||
- `{ node?: MNode | null; targetId?: Id }` data 可选上下文(默认 `{}`)
|
||||
- `targetId`:目标节点 id
|
||||
- `node`:目标节点配置,便于插件按节点定制方法列表
|
||||
|
||||
- **返回:**
|
||||
|
||||
@ -154,15 +167,36 @@ eventsService.setMethod('video', [
|
||||
|
||||
- **详情:**
|
||||
|
||||
获取指定组件类型的方法列表
|
||||
获取指定组件类型的方法列表。默认实现仅按 `type` 返回注册方法;可通过 `usePlugin` 的 `beforeGetMethod` / `afterGetMethod` 读取 `data` 做节点级过滤或扩展。
|
||||
|
||||
::: warning 破坏性变更
|
||||
第二参数已从 `targetId: Id` 调整为对象 `{ node?, targetId? }`。请同步更新调用方与插件钩子入参,例如:
|
||||
|
||||
```js
|
||||
// 旧
|
||||
eventsService.getMethod('video', 'video_123');
|
||||
// 新
|
||||
eventsService.getMethod('video', { targetId: 'video_123', node });
|
||||
```
|
||||
:::
|
||||
|
||||
- **示例:**
|
||||
|
||||
```js
|
||||
import { eventsService } from '@tmagic/editor';
|
||||
|
||||
const methods = eventsService.getMethod('video', 'video_123');
|
||||
const methods = eventsService.getMethod('video', { targetId: 'video_123', node });
|
||||
console.log(methods); // [{ label: '播放', value: 'play' }, ...]
|
||||
|
||||
// 插件按节点定制
|
||||
eventsService.usePlugin({
|
||||
afterGetMethod(methods, type, data) {
|
||||
if (data?.targetId === 'video_123') {
|
||||
return methods.filter((item) => item.value !== 'stop');
|
||||
}
|
||||
return methods;
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
## resetState
|
||||
|
||||
@ -311,10 +311,12 @@ const tableConfig = computed(
|
||||
label: '事件名',
|
||||
type: eventNameConfig.value.type,
|
||||
options: (mForm: FormState, { formValue }: any) =>
|
||||
eventsService.getEvent(formValue.type).map((option: any) => ({
|
||||
text: option.label,
|
||||
value: option.value,
|
||||
})),
|
||||
eventsService
|
||||
.getEvent(formValue.type, { node: editorService.getNodeById(formValue.id) })
|
||||
.map((option: any) => ({
|
||||
text: option.label,
|
||||
value: option.value,
|
||||
})),
|
||||
},
|
||||
{
|
||||
name: 'to',
|
||||
@ -329,7 +331,7 @@ const tableConfig = computed(
|
||||
const node = editorService.getNodeById(model.to);
|
||||
if (!node?.type) return [];
|
||||
|
||||
return eventsService.getMethod(node.type, model.to).map((option: any) => ({
|
||||
return eventsService.getMethod(node.type, { targetId: model.to, node }).map((option: any) => ({
|
||||
text: option.label,
|
||||
value: option.value,
|
||||
}));
|
||||
|
||||
@ -20,7 +20,7 @@ import { reactive } from 'vue';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
import type { Writable } from 'type-fest';
|
||||
|
||||
import { type EventOption, type Id } from '@tmagic/core';
|
||||
import type { EventOption, Id, MNode } from '@tmagic/core';
|
||||
import { toLine } from '@tmagic/utils';
|
||||
|
||||
import type { AsyncHookPlugin, SyncHookPlugin } from '@editor/type';
|
||||
@ -56,7 +56,7 @@ class Events extends BaseService {
|
||||
eventMap[toLine(type)] = [...events];
|
||||
}
|
||||
|
||||
public getEvent(type: string): EventOption[] {
|
||||
public getEvent(type: string, _data: { node?: MNode | null } = {}): EventOption[] {
|
||||
return cloneDeep(eventMap[toLine(type)]) || [];
|
||||
}
|
||||
|
||||
@ -70,7 +70,7 @@ class Events extends BaseService {
|
||||
methodMap[toLine(type)] = [...method];
|
||||
}
|
||||
|
||||
public getMethod(type: string, _targetId: Id) {
|
||||
public getMethod(type: string, _data: { node?: MNode | null; targetId?: Id } = {}) {
|
||||
return cloneDeep(methodMap[toLine(type)]) || [];
|
||||
}
|
||||
|
||||
|
||||
@ -56,7 +56,8 @@ export const getEventNameOptions = (
|
||||
}
|
||||
|
||||
if (src === 'component') {
|
||||
let events: EventOption[] | CascaderOption[] = eventsService.getEvent(formValue.type) || [];
|
||||
const sourceNode = editorService.getNodeById(formValue.id);
|
||||
let events: EventOption[] | CascaderOption[] = eventsService.getEvent(formValue.type, { node: sourceNode }) || [];
|
||||
|
||||
if (formValue.type === 'page-fragment-container' && formValue.pageFragmentId) {
|
||||
const pageFragment = editorService.get('root')?.items?.find((page) => page.id === formValue.pageFragmentId);
|
||||
@ -72,9 +73,14 @@ export const getEventNameOptions = (
|
||||
},
|
||||
];
|
||||
|
||||
(pageFragment.items || []).forEach((node) => {
|
||||
traverseNode<MComponent | MContainer>(node, (current) => {
|
||||
const nodeEvents = (current.type && eventsService.getEvent(current.type)) || [];
|
||||
(pageFragment.items || []).forEach((item) => {
|
||||
traverseNode<MComponent | MContainer>(item, (current) => {
|
||||
if (!current.type) {
|
||||
return;
|
||||
}
|
||||
|
||||
const node = editorService.getNodeById(current.id) || current;
|
||||
const nodeEvents = eventsService.getEvent(current.type, { node }) || [];
|
||||
(events as CascaderOption[]).push({
|
||||
label: `${current.name}_${current.id}`,
|
||||
value: `${current.id}`,
|
||||
@ -176,7 +182,7 @@ export const getCompActionOptions = (toId?: Id): EventNameOption[] => {
|
||||
return [];
|
||||
}
|
||||
|
||||
let methods: EventOption[] | CascaderOption[] = eventsService.getMethod(node.type, toId) || [];
|
||||
let methods: EventOption[] | CascaderOption[] = eventsService.getMethod(node.type, { targetId: toId, node }) || [];
|
||||
|
||||
if (node.type === 'page-fragment-container' && node.pageFragmentId) {
|
||||
const pageFragment = editorService.get('root')?.items?.find((page) => page.id === node.pageFragmentId);
|
||||
@ -187,15 +193,22 @@ export const getCompActionOptions = (toId?: Id): EventNameOption[] => {
|
||||
methods = [];
|
||||
(pageFragment.items || []).forEach((item: MComponent | MContainer) => {
|
||||
traverseNode<MComponent | MContainer>(item, (current) => {
|
||||
const nodeMethods = (current.type && eventsService.getMethod(current.type, current.id)) || [];
|
||||
const node = editorService.getNodeById(current.id) || current;
|
||||
|
||||
if (nodeMethods.length) {
|
||||
(methods as CascaderOption[]).push({
|
||||
label: `${current.name}_${current.id}`,
|
||||
value: `${current.id}`,
|
||||
children: nodeMethods,
|
||||
});
|
||||
if (!current.type) {
|
||||
return;
|
||||
}
|
||||
|
||||
const nodeMethods = eventsService.getMethod(current.type, { targetId: current.id, node }) || [];
|
||||
if (!nodeMethods.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
(methods as CascaderOption[]).push({
|
||||
label: `${current.name}_${current.id}`,
|
||||
value: `${current.id}`,
|
||||
children: nodeMethods,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@ -30,7 +30,7 @@ describe('events', () => {
|
||||
test('setMethod', () => {
|
||||
const method = [{ label: '点击', value: 'magic:common:events:click' }];
|
||||
events.setMethod('button', method);
|
||||
expect(events.getMethod('button', '')).toHaveLength(1);
|
||||
expect(events.getMethod('button', { targetId: 'btn_1' })).toHaveLength(1);
|
||||
});
|
||||
|
||||
test('setEvents 批量设置', () => {
|
||||
@ -46,12 +46,20 @@ describe('events', () => {
|
||||
events.setMethods({
|
||||
Image: [{ label: 'show', value: 'show' }],
|
||||
} as any);
|
||||
expect(events.getMethod('image', '')).toHaveLength(1);
|
||||
expect(events.getMethod('image', {})).toHaveLength(1);
|
||||
});
|
||||
|
||||
test('getEvent / getMethod 支持节点上下文参数', () => {
|
||||
const node = { id: 'n1', type: 'button' } as any;
|
||||
events.setEvent('button', [{ label: '点击', value: 'click' }]);
|
||||
events.setMethod('button', [{ label: '打开', value: 'open' }]);
|
||||
expect(events.getEvent('button', { node })).toEqual([{ label: '点击', value: 'click' }]);
|
||||
expect(events.getMethod('button', { targetId: 'n1', node })).toEqual([{ label: '打开', value: 'open' }]);
|
||||
});
|
||||
|
||||
test('未注册类型返回空数组', () => {
|
||||
expect(events.getEvent('not-exist')).toEqual([]);
|
||||
expect(events.getMethod('not-exist', '')).toEqual([]);
|
||||
expect(events.getMethod('not-exist')).toEqual([]);
|
||||
});
|
||||
|
||||
test('resetState 清空所有事件 / 方法', () => {
|
||||
|
||||
@ -52,8 +52,10 @@ describe('event utils', () => {
|
||||
});
|
||||
|
||||
test('getCompActionOptions 普通组件返回 select options', () => {
|
||||
editorService.getNodeById.mockReturnValue({ type: 'btn', id: '1' });
|
||||
const node = { type: 'btn', id: '1' };
|
||||
editorService.getNodeById.mockReturnValue(node);
|
||||
expect(getCompActionOptions('1')).toEqual([{ text: 'open', value: 'open' }]);
|
||||
expect(eventsService.getMethod).toHaveBeenCalledWith('btn', { targetId: '1', node });
|
||||
});
|
||||
|
||||
test('getCompActionOptions 无节点返回空', () => {
|
||||
@ -63,8 +65,10 @@ describe('event utils', () => {
|
||||
});
|
||||
|
||||
test('getCompActionOptions 页面片容器返回 cascader options', () => {
|
||||
editorService.getNodeById.mockReturnValue({ type: 'page-fragment-container', id: '1', pageFragmentId: 'pf1' });
|
||||
editorService.get.mockReturnValue({ items: [{ id: 'pf1', items: [{ id: 'c1', type: 'btn', name: 'b' }] }] });
|
||||
const container = { type: 'page-fragment-container', id: '1', pageFragmentId: 'pf1' };
|
||||
const child = { id: 'c1', type: 'btn', name: 'b' };
|
||||
editorService.getNodeById.mockImplementation((id: string) => (id === '1' ? container : null));
|
||||
editorService.get.mockReturnValue({ items: [{ id: 'pf1', items: [child] }] });
|
||||
expect(getCompActionOptions('1')).toEqual([
|
||||
{
|
||||
label: 'b_c1',
|
||||
@ -72,6 +76,7 @@ describe('event utils', () => {
|
||||
children: [{ label: 'open', value: 'open' }],
|
||||
},
|
||||
]);
|
||||
expect(eventsService.getMethod).toHaveBeenCalledWith('btn', { targetId: 'c1', node: child });
|
||||
});
|
||||
|
||||
test('getCompActionAllowedValues 枚举合法动作', () => {
|
||||
@ -99,6 +104,29 @@ describe('event utils', () => {
|
||||
expect(collectEventNameOptionValues([{ value: 'a', children: [{ value: 'b' }] }], false)).toEqual(new Set(['a.b']));
|
||||
});
|
||||
|
||||
test('getEventNameOptions 页面片子节点查找失败时回退 current', () => {
|
||||
const formValue = { type: 'page-fragment-container', id: '1', pageFragmentId: 'pf1' };
|
||||
const child = { id: 'c1', type: 'btn', name: 'b' };
|
||||
editorService.getNodeById.mockReturnValue(null);
|
||||
editorService.get.mockReturnValue({
|
||||
items: [{ id: 'pf1', name: '页面片', items: [child] }],
|
||||
});
|
||||
|
||||
expect(getEventNameOptions('component', formValue)).toEqual([
|
||||
{
|
||||
label: '页面片',
|
||||
value: 'pf1',
|
||||
children: [{ label: 'click', value: 'click' }],
|
||||
},
|
||||
{
|
||||
label: 'b_c1',
|
||||
value: 'c1',
|
||||
children: [{ label: 'click', value: 'click' }],
|
||||
},
|
||||
]);
|
||||
expect(eventsService.getEvent).toHaveBeenCalledWith('btn', { node: child });
|
||||
});
|
||||
|
||||
test('getEventNameOptions datasource 追加数据变化', () => {
|
||||
dataSourceService.getDataSourceById.mockReturnValue({ fields: [{ name: 'f1' }] });
|
||||
const opts = getEventNameOptions('datasource', { type: 'ds', id: 'd1' });
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user