vue3 父级传给子组件render函数时的scopeId和父级不一致?

父级:

<template>
  <comp :r="r" />
</template>

<script>
import { defineComponent, h, withCtx, getCurrentInstance } from 'vue'
import Comp from './Comp.vue'

export default defineComponent({
  components: { Comp },
  setup() {
    const ins = getCurrentInstance()
    return {
      r: () => h('span', { class: 'span' }, '哈哈')
      // r: withCtx(() => h('span', { class: 'span' }, '哈哈'), ins)
    }
  },
})
</script>

<style scoped>
.span {
  color: blue;
}
</style>

子组件:

<script>
import { defineComponent, h } from 'vue'

export default defineComponent({
  name: 'Comp',
  props: { r: Function },
  setup(props) {
    return () => h('div', { class: 'comp' }, props.r())
  },
})
</script>

<style scoped>
.comp {
  color: red
}
</style>

如果使用withCtx(() => h('span', { class: 'span' }, '哈哈'), ins)是可以让spanscopeId和父级一致,但是这样必须在每个使用了子组件的父级里写一遍,太麻烦还容易漏,官方文档根本没写这东西

所以有没有一种方式,能通过修改子组件,父级不需要传其他乱七八糟的比如instance之类的给子组件,就能达到说子组件接收的render函数始终使用传入者的scopeId

阅读 994
avatarAI BotBETA

这是一个涉及Vue 3组件递归渲染的问题,其关键在于Vue的render函数在渲染子组件时并不会保留或使用其自身的scopeId

在你的例子中,父组件的r函数返回了一个span元素,这个元素被渲染到了子组件中。然而,由于这个span元素是在子组件的setup函数中创建的,所以它的scopeId是子组件的,而不是父组件的。

要解决这个问题,一种可能的解决方案是使用Vue的withCtx函数来创建一个具有正确scopeId的函数。然而,你提到这种方法需要在每个使用了子组件的父级里写一遍,这确实是一个问题。

另一种可能的解决方案是修改子组件,使其能够接收一个带有正确scopeId的函数,而不是在父组件中创建这个函数。这可以通过在子组件的props中添加一个新的prop来实现,这个prop接收一个函数,然后在子组件的setup函数中使用这个函数来创建需要渲染的元素。

下面是一个修改后的子组件示例:

<script>
import { defineComponent, h } from 'vue'

export default defineComponent({
  name: 'Comp',
  props: { 
    r: Function, 
    render: Function 
  },
  setup(props) {
    return () => h('div', { class: 'comp' }, props.render(props.r))
  },
})
</script>

然后,在父组件中,你可以这样使用这个子组件:

<template>
  <comp :r="r" :render="render" />
</template>

<script>
import { defineComponent, h } from 'vue'
import Comp from './Comp.vue'

export default defineComponent({
  components: { Comp },
  setup() {
    return {
      r: () => h('span', { class: 'span' }, '哈哈'),
      render: (createNode) => createNode(() => '哈哈')
    }
  },
})
</script>

在这个修改后的例子中,父组件传递了一个名为render的prop给子组件。这个prop接收一个函数,然后在子组件中创建一个新的元素,这个新元素的scopeId与子组件的相同。这样就解决了你的问题。

1 个回答

实在要在子组件做那就只能用非标方式,直接从vnode上拿值写入,
return () => h('div', { class: 'comp',[getCurrentInstance().parent.type.__scopeId]: '' }, props.r())
从命名上也知道这是个私有属性,最好是不要用

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题