vue祖先与孙子跨级别传递方法(祖先调用孙子方法、中间层调用)-----provide、inject

单变量存储多个方法

// injectionKeys.js

// injectionKeys.js
export const DataIntegrationGrandApiKey = Symbol('DataIntegrationGrandApi');

 

祖先组件(API 管理者)

  ✔ 一个 provide
  ✔ 一个 key
  ✔ 清晰、安全

核心职责:

  • 持有一个 apiRef

  • 提供 registerGrandApi

  • 把“容器对象” provide 出去

<script setup>
import { ref, provide } from 'vue';
import { DataIntegrationGrandApiKey } from '@/injectionKeys';

// 用来存孙子暴露的 api
const grandApiRef = ref(null);

// 孙子调用:注册 / 注销
function registerGrandApi(api) {
  grandApiRef.value = api;
}

// ⚠️ 注意:provide 的是 ref,不是 .value
provide(DataIntegrationGrandApiKey, {
  registerGrandApi,   // 孙子用
  grandApiRef,        // 中间层 / 其他后代用
});
</script>

孙子组件(API 提供者)

  ✔ 孙子只关心注册
  ✔ 不关心谁调用
  ✔ 不依赖层级

核心职责:

  • 实现真实业务方法

  • mounted 时注册

  • unmount 时注销

 

<script setup>
import { inject, onMounted, onBeforeUnmount } from 'vue';
import { DataIntegrationGrandApiKey } from '@/injectionKeys';

const apiContainer = inject(DataIntegrationGrandApiKey);

function save() {
  console.log('孙子:save 被调用');
}

function insert(code) {
  console.log('孙子:insert', code);
}

const api = {
  save,
  insert,
};

onMounted(() => {
  apiContainer?.registerGrandApi(api);
});

onBeforeUnmount(() => {
  apiContainer?.registerGrandApi(null);
});
</script>

 中间层组件

核心职责:

  • 直接调用孙子暴露的方法

  • 不需要 emit / 不需要 ref 链

<script setup>
import { inject } from 'vue';
import { DataIntegrationGrandApiKey } from '@/injectionKeys';

const apiContainer = inject(DataIntegrationGrandApiKey);

function onClickSave() {
  apiContainer?.grandApiRef.value?.save();
}

function onInsert() {
  apiContainer?.grandApiRef.value?.insert?.('test code');
}
</script>

<template>
  <button @click="onClickSave">保存</button>
  <button @click="onInsert">插入</button>
</template>

 如果后续代码需要等待,则使用promise或者await定义异步方法。主动停止js执行

 

-------------------------------------下方为简单示例及原理姐好啊---------------------------

 

 

 

 

1️⃣ 定义 Injection Key(单独文件)目的:避免方法名重复:

Symbol 的优势(核心)

const KEY = Symbol('RegisterGrandApi');
  • 全局唯一(不会冲突)

  • 类型系统可约束

  • IDE 自动提示

  • 官方推荐(Vue / Pinia 都在用)

ts版本:

// injectionKeys.ts
import type { InjectionKey } from 'vue';

export interface GrandApi {
  save: () => void;
  insert?: (code: string) => void;
}

export const RegisterGrandApiKey: InjectionKey<
  (api: GrandApi | null) => void
> = Symbol('RegisterGrandApi');

js版本:

// injectionKeys.ts:跨级方法调用
export const RegisterGrandApiKey = Symbol('RegisterGrandApi');

 

祖先组件(提供注册器)

<script setup lang="ts">
import { provide, ref } from 'vue';
import { RegisterGrandApiKey, type GrandApi } from '@/injectionKeys';

const grandApi = ref<GrandApi | null>(null);

function registerGrandApi(api: GrandApi | null) {
  grandApi.value = api;
}

function callSave() {
  grandApi.value?.save();
}

provide(RegisterGrandApiKey, registerGrandApi);
</script>

<template>
  <el-button @click="callSave">保存</el-button>
  <Parent />
</template>

孙子组件(注册能力)

<script setup lang="ts">
import { inject, onMounted, onBeforeUnmount } from 'vue';
import { RegisterGrandApiKey, type GrandApi } from '@/injectionKeys';

function save() {
  console.log('孙子保存逻辑');
}

const api: GrandApi = {
  save,
};

const registerGrandApi = inject(RegisterGrandApiKey);

onMounted(() => {
  registerGrandApi?.(api);
});

onBeforeUnmount(() => {
  registerGrandApi?.(null);
});
</script>

中间层使用孙子方法:

 

 

一句话工程总结(你可以直接记)

Symbol = 接口名
InjectionKey = 类型约束
provide / inject = 依赖注入

 

 

一、provide / inject 是干嘛的?

一句话定义:

用于祖先组件向任意层级的后代组件“依赖注入”数据或方法

👉 不受组件层级限制


对比一下你熟悉的方式

方式 能否祖先→孙子 是否强耦合 推荐程度
props
emit
ref ⚠️ 极高
provide / inject ⭐⭐⭐⭐⭐

二、基本用法(最简单版)

祖先组件

import { provide } from 'vue';

provide('msg', 'hello');

后代组件(任意层级)

import { inject } from 'vue';

const msg = inject('msg');
console.log(msg); // 'hello'

provide / inject 的“作用域规则” 

App
 └─ A (provide)
    └─ B
       └─ C (inject) ✅
  • ❌ 兄弟组件不可用

  • ❌ 父组件不能 inject 子组件

  • ✅ 祖先 → 后代

 

 

为什么孙子要用 onMounted / onBeforeUnmount

不是“必须”,而是“正确”

onMounted(() => register(api)); onBeforeUnmount(() => register(null));

原因:

1️⃣ 保证 DOM / 编辑器实例已存在
2️⃣ 避免祖先拿到“失效引用”
3️⃣ 支持组件销毁 / 重建
4️⃣ 防止内存泄漏

posted @ 2026-01-06 18:15  SimoonJia  阅读(5)  评论(0)    收藏  举报