有没有一种方法可以检测是否将作用域内的插槽传递给组件?

时间:2018-09-17 23:44:16

标签: javascript vue.js

我有一个嵌套在多层组件中的组件。有作用域的插槽可以向下传递到此组件。我想检测出何时没有。

示例:

cbox.AutoCompleteMode = AutoCompleteMode.None;

CodePen

在此示例中,作用域插槽从未从根组件传递到Vue.component("parent", { template: ` <child> <template slot="expand" slot-scope="{data}" v-if="$scopedSlots.expand"> <slot name="expand" :data="data"></slot> </template> </child> `, }); Vue.component("child", { template: ` <div> <slot name="expand" :data="1"></slot> <div @click="$scopedSlots.expand && log()">Child</div> </div> `, methods: { log() { console.log(this.$scopedSlots.expand); console.log("This shouldn't work"); } } }); new Vue({ el: "#app", template: `<parent></parent>`, }) 。结果,我会认为<parent>中的$scopedSlots.expandv-if都是虚假的,因此不会有任何槽位传递给<parent>,并且单击不会做任何事情。

但是,这似乎是错误的,原因有两个:

  • 由于<child>是作为函数存储在内部的,因此它将始终评估为真实,如您在CodePen控制台中所见。
  • 似乎$scopedSlots.expand始终呈现,即使<template>也是如此。因此,即使v-if="false"$scopedSlots.expand中被评估为虚假,一个空位仍将传递给<parent>,而<child>内部的$scopedSlots.expand将被评估为真实不管。

有没有办法使这项工作成功?

我知道我可以通过传递一个布尔型道具来完成此操作,该道具指出是否要处理点击。我试图找出是否有可能从广告位本身确定。

1 个答案:

答案 0 :(得分:3)

我以前曾被打过,这很烦人。

Vue模板编译器将对此进行编译

<template v-if="false"/>

本质上

vm._e()

其中_ecreateEmptyVNode的{​​{3}}。因此,我们马上就会期望使用空vnodes 而不是虚假的值。

如果我们通过查看此模板的编译代码进行进一步调查

<child>
  <template slot="expand" slot-scope="scope" v-if="false"/>
</child>

我们得到了这段代码(为了简化说明,只显示了相关内容)

_c('child', {
  scopedSlots: {
    expand(scope) {
      return undefined
    }
  }
})

总结:v-if="false"并非不是暗示将省略作用域插槽功能,而是提供范围的插槽功能,但调用时它将返回undefined。因此,在子组件中,可以预期$scopedSlots.expand存在,但是在调用时将返回undefined

AFAIK没有简单的方法来处理此问题。您的示例的快速“修复”将是

<div @click="$scopedSlots.expand() && log()">Child</div>
                                ^^

但要警惕

  • 您的父组件是否可以处理slot-scope="{data}"不存在的{data}?最好使用真实的$scopedSlots.expand(scope)数据调用scope
  • 调用$scopedSlots.expand()并在渲染周期中多次丢弃潜在的真实结果可能是性能问题。

FWIW通过将v-ifslot分离到单独的<template>节点中,成功实现了 variable

<template v-if="$scopedSlots.expand">
  <template slot="expand" slot-scope="{data}">
    <slot name="expand" :data="data"/>
  </template>
</template>