You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue3中如何从插槽内的子组件向父组件传递对象?Tippy JS单例包装组件实现咨询

解决方案:用依赖注入(Provide/Inject)替代事件总线

我之前也碰到过类似的场景,事件总线确实容易出现你说的时机和组件关联问题,而**依赖注入(Provide/Inject)**刚好能完美解决这两个痛点——它天然绑定了父组件和它插槽内的子组件,不会跟其他组件组搞混,还能更优雅地处理实例注册的时机问题。

下面是具体的实现思路和代码示例(以Vue3为例):


1. 实现父级包装组件 TippySingleton

这个组件负责提供注册实例的方法、存储所有子组件的tippy实例,以及创建单例:

<template>
  <div>
    <slot></slot>
  </div>
</template>

<script setup>
import { ref, provide, onMounted, nextTick } from 'vue'
import tippy from 'tippy.js'
import { createSingleton } from 'tippy.js'

// 存储所有子组件的tippy实例
const tippyInstances = ref([])

// 提供给子组件的注册方法
const registerTippyInstance = (instance) => {
  tippyInstances.value.push(instance)
}

// 提供清理方法(可选,用于子组件卸载时移除实例)
const unregisterTippyInstance = (instance) => {
  const index = tippyInstances.value.findIndex(i => i === instance)
  if (index !== -1) {
    tippyInstances.value.splice(index, 1)
  }
}

// 提供给子组件的依赖
provide('tippySingleton', {
  register: registerTippyInstance,
  unregister: unregisterTippyInstance
})

onMounted(async () => {
  // 用nextTick确保所有子组件都完成mounted并注册了实例
  await nextTick()
  
  // 创建单例
  if (tippyInstances.value.length > 0) {
    createSingleton(tippyInstances.value, {
      // 单例配置,比如同一时间只显示一个tooltip
      delay: [100, 0],
      placement: 'top'
    })
  }
})
</script>

2. 实现子组件 TippyItem

这个组件负责初始化自己的tippy实例,并注册到父组件的实例列表中:

<template>
  <div ref="tippyTarget">
    <slot></slot>
  </div>
</template>

<script setup>
import { ref, inject, onMounted, onUnmounted } from 'vue'
import tippy from 'tippy.js'

const tippyTarget = ref(null)
const { register, unregister } = inject('tippySingleton')

let tippyInstance = null

onMounted(() => {
  // 初始化当前组件的tippy实例
  tippyInstance = tippy(tippyTarget.value, {
    // 单个tooltip的配置
    content: '我是tooltip内容',
    interactive: true
  })
  
  // 注册到父组件的实例列表
  register(tippyInstance)
})

onUnmounted(() => {
  // 卸载时清理实例,避免内存泄漏
  tippyInstance?.destroy()
  unregister(tippyInstance)
})
</script>

3. 使用方式

在页面中直接嵌套使用即可,父组件会自动收集所有子组件的tippy实例并创建单例:

<TippySingleton>
  <TippyItem>
    <button>按钮1</button>
  </TippyItem>
  <TippyItem>
    <button>按钮2</button>
  </TippyItem>
  <TippyItem>
    <button>按钮3</button>
  </TippyItem>
</TippySingleton>

为什么这个方案能解决你的问题?

  • 组件组关联清晰:依赖注入是基于组件树的,每个TippySingleton只会收集自己插槽内的TippyItem实例,不会和其他组件组混淆,完美解决了你说的"无法清晰关联包装组件-子组件组"的问题。
  • 时机问题解决:通过nextTick等待所有子组件的mounted钩子执行完毕,确保父组件初始化单例时,所有子组件的tippy实例都已经注册完成,避免了事件总线中子组件触发事件时父组件未准备好的情况。

如果是Vue2的项目,思路完全一致,只是provide/inject的API写法略有不同(比如用选项式API的provide和inject选项),核心逻辑不变。

内容的提问来源于stack exchange,提问作者Rägnar Öock

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 13:52:31