Vue: 提供的道具未注入功能组件中

创建于 2017-06-07  ·  16评论  ·  资料来源: vuejs/vue

2.3.3

复制链接

http://jsfiddle.net/p861bj9y/

重现步骤

我对要测试的行为进行了最小化的复制,该示例只需要JSX即可工作。

期望什么?

从父级传递过来的属性应显示在ctx.injections

实际发生了什么?

Ctx.injections存在,但为空。 这些属性未传递到功能组件上下文。

最有用的评论

是否有计划在v3中解决此问题?

例如,我试图将v-for抽象化为渲染函数,但是我的孩子可以是功能组件(因此进入渲染函数时它们已经被渲染了,我无法克隆它们)。

所有16条评论

这是因为child被认为是vm子代(可能是一个问题),而不是parent 。 因此,您可能需要在vm写入provide vm

顺便说一句,你的提琴使用[email protected] 😅

提供注入的查找算法是子级自行查看提供的属性,然后循环其$parent层次结构以查找提供的道具,直到其位于根目录为止。
https://github.com/vuejs/vue/blob/b182ac40697edbe8253d4bd68b6ac09e93259e1c/src/core/instance/inject.js#L59 -L59

无法运行您的小提琴,但是当我运行https://jsfiddle.net/Austio/vhgztp59/7/时,当我进入查找上下文时,在子组件上未定义$ parent。 如果这与渲染插槽无关紧要,并且组件之间没有关系,那么至少这是一个开始。

似乎在解决插槽之前就渲染了功能组件

@Kingwl正确,这是一种技术要求。

我记得我提出这一点是因为我对此感到疯狂。 最后,对我来说这看起来很正常,因为功能组件已附加到要在其中渲染的组件,因此在插槽中使用时,它们会附加到外部组件。 但是,对于非功能组件则不是这种情况:

容器注入mode: 'foo'并渲染<div><slot/></div>

<!-- rendered in App -->
<container>
   <!-- parent is App, mode is undefined -->
  <functional></functional>
</container>

<container>
   <!-- parent is container, mode is foo -->
  <not-functional></not-functional>
</container>

http://jsfiddle.net/p861bj9y/

编辑: @alidcastano我更新了您评论中的小提琴,因为您的评论甚至没有使用Vue 2

哈哈,抱歉在小提琴中使用了错误的Vue版本,我因为无法配置我没有意识到的JSX而深陷其中。 @posva感谢您修复我的示例!

-

因此,这里的问题不是功能组件无法接收所提供的属性,而是功能组件在插槽之前呈现?

@LinusBorg通过“技术要求”是否意味着没有解决方法或该行为是预期的?

是否应该创建一个容器来充当传递道具的vm ? 例如,设计将更改为:

// before
<parent-component>
  <child-component />
</parent-component>

// after
<vm-container>
   <parent-component>
     <child-component />
   </parent-component>
<vm-container>

但是上面的示例似乎不必要地already肿,因为父组件的本质已经包含了它需要提供给子组件的所有数据。 但是我愿意讨论。 这是你们的建议吗?

vm-container不会更改任何内容,因为广告位是在app上下文中呈现的

“技术要求”是否意味着没有解决方法或该行为是预期的?

该行为是功能组件工作方式的结果。 考虑以下一组组件:

<!-- template of a `parent` component -->
<template>
  <Child>
    <functional />
  </Child>
</template>

当您将功能组件传递到另一个组件的插槽中时,必须先将其呈现,然后再将其传递给子组件,以便该子组件可以接收生成的vNode作为插槽内容。 (*)

在上面的示例中,这意味着在<functional>组件呈现时,可用的父对象是外部组件( <parent> ),而不是<child>

因此,功能部件可用的唯一进样也是<parent>中可用的进样。


(*):这就是虚拟域的当前实现与功能组件一起工作的方式。 要改变这一点,就需要改变很多内部机制。

@posva @LinusBorg知道了,谢谢您的解释。

因此,由于这些要求,使用提供/注入功能组件的唯一方法是在app上下文中提供props。

我确定此约束条件将在文档中阐明。 如果没有其他需要完成或澄清的问题,请继续并解决此问题; 再次感谢!

也许我们可以找到一种方法来改善插槽中的功能组件
但是目前,它应该像@posva@LinusBorg所说的那样完成

@Kingwl感谢您保持打开状态。

我终于有时间尝试使用上述建议将其合并到我的vue-mobiledoc-editor插件中。 我预见到是否需要从app实例中使用组件的一个问题是,使用嵌套的组件要灵活得多。

例如,我必须导出已在该应用程序实例下注册的组件:

...

export default Vue.extend({
  render (h) {
    return (
      <div>
        <ParentComp>
          <ChildFuncComp/>
        </ParentComp>
      </div>
    )
  },

  provide () { // data that needs to be injected into functional components 
    return {
       msg: 'hello'
    }
  },

  components: {
    ParentComp,
    ChildFuncComp
  }
})

然后,据我了解,当用户使用插件时,会像这样:

// template
<div id="app">
   <div id="#someWhereInApp" />
</div>

// script 
import SuperCoolComponent from 'SuperCoolComponent' 

export default {
   mounted () {
    this.$once('mounted', () => new SuperCoolComponent().$mount('#someWhereInApp'))
    this.$emit('mounted')
  }
}

如果我的实现是正确的,那么这将严重限制功能组件的提供/注入的使用,因为不允许您单独导入和注册要使用的组件。

我会使用完整的组件来支持提供/注入

我正在尝试解决这个问题
也许这是一个漫长的过程🌚

@Kingwl您能解决吗?

是否有计划在v3中解决此问题?

例如,我试图将v-for抽象化为渲染函数,但是我的孩子可以是功能组件(因此进入渲染函数时它们已经被渲染了,我无法克隆它们)。

任何更新?

此页面是否有帮助?
0 / 5 - 0 等级