113 lines
4.1 KiB
TypeScript
113 lines
4.1 KiB
TypeScript
|
|
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 };
|