CNCEC_APP/uni_modules/uview-pro/libs/util/emitter.ts

113 lines
4.1 KiB
TypeScript
Raw Permalink Normal View History

2026-03-25 14:54:15 +08:00
import { getCurrentInstance, type ComponentInternalInstance } from 'vue';
/**
* uni-app Vue3 /广
* import { dispatch, broadcast } from './emitter'
*/
/**
*
* @param instance setup中可用getCurrentInstance()
* @param componentName
* @param eventName
* @param params
*/
// 将事件名转换为驼峰格式
// 例如on-form-change -> onFormChange
function formatToCamelCase(str: string): string {
return str.replace(/-([a-z])/g, function (g) {
return g[1].toUpperCase();
});
}
/**
*
* @param instance setup中可用getCurrentInstance()
* @param componentName
* @returns
*/
function parent(instance: ComponentInternalInstance | null | undefined = undefined, componentName: string = '') {
if (!instance) {
instance = getCurrentInstance();
}
let parent = instance && (instance.parent as ComponentInternalInstance | null | undefined);
if (!componentName) return parent;
while (parent) {
const name = (parent.type as any)?.name as string | undefined;
if (name === componentName) {
return parent;
}
parent = parent.parent;
}
return null;
}
/** *
* @param instance setup中可用getCurrentInstance()
* @param componentName
* @param eventName
* @param params
*/
function dispatch(
instance: ComponentInternalInstance | null | undefined,
componentName: string,
eventName: string,
...params: any[]
) {
let parent = instance && (instance.parent as ComponentInternalInstance | null | undefined);
while (parent) {
const name = (parent.type as any)?.name as string | undefined;
if (name === componentName) {
// 找到目标组件,派发事件
// Vue3未解决目标组件事件监听失效待优化暂时使用下面的方式解决如果你有好的方式也可以告诉我或者提PR
parent.emit && parent.emit(eventName, ...params);
// 如果有对应的方法,执行方法
// 这里可以考虑将 eventName 转换为驼峰格式
// 例如on-form-change -> onFormChange
parent.exposed?.[formatToCamelCase(eventName)] && parent.exposed[formatToCamelCase(eventName)](...params);
break;
}
parent = parent.parent;
}
}
/**
* 广
* @param instance setup中可用getCurrentInstance()
* @param componentName
* @param eventName
* @param params
*/
function broadcast(
instance: ComponentInternalInstance | null | undefined,
componentName: string,
eventName: string,
...params: any[]
) {
if (!instance) return;
const subTree = (instance.subTree as any)?.children || [];
const children = Array.isArray(subTree) ? subTree : [subTree];
children.forEach((vnode: any) => {
const child = vnode.component as ComponentInternalInstance | undefined;
if (child) {
const name = (child.type as any)?.name as string | undefined;
if (name === componentName) {
// 找到目标组件,广播事件
// Vue3未解决目标组件事件监听失效待优化暂时使用下面的方式解决如果你有好的方式也可以告诉我或者提PR
child.emit && child.emit(eventName, ...params);
// 如果有对应的方法,执行方法
// 这里可以考虑将 eventName 转换为驼峰格式
// 例如on-form-change -> onFormChange
child.exposed?.[formatToCamelCase(eventName)] && child.exposed[formatToCamelCase(eventName)](...params);
} else {
broadcast(child, componentName, eventName, ...params);
}
}
});
}
export { dispatch, broadcast, parent };