确定槽内容是空还是空
Posted
技术标签:
【中文标题】确定槽内容是空还是空【英文标题】:Determining if slot content is null or empty 【发布时间】:2018-05-06 01:46:28 【问题描述】:我有一个小加载组件,我希望其默认文本为“加载中...”。插槽的好候选人,所以我有这样的东西作为我的模板:
<p class="loading"><i class="fa fa-spinner fa-spin"></i><slot>Loading...</slot></p>
这使我可以更改加载消息,例如<loading>Searching...</loading>
。不过,我想要的行为不仅是在未提供插槽内容时显示默认消息,而且在插槽内容为空或空白时显示默认消息。目前,如果我执行例如<loading>loadingMessage</loading>
并且 loadingMessage 为空,则不会显示任何文本(我希望显示默认文本)。所以理想情况下我需要测试this.$slots.default
。这告诉我内容是否传入,但我如何找到它是否为空? this.$slots.default.text
返回未定义。
【问题讨论】:
【参考方案1】:您需要一个计算属性来检查this.$slots
。对于默认插槽,您需要检查 this.$slots.default
,对于命名插槽,只需将 default
替换为插槽名称即可。
computed:
slotPassed()
return !!this.$slots.default[0].text.length
然后在你的模板中使用它:
<template>
<div>
<slot v-if="slotPassed">Loading...</slot>
<p v-else>Searching...</p>
</div>
</template>
你可以看一个小例子here。请注意后备内容的显示方式,而不是插槽内的“默认内容”。
编辑:
我的措辞本来可以更好。您需要做的是检查$slots.X
值,但计算属性是一种方法来检查。您也可以在模板中编写插槽检查:
<template>
<div>
<slot v-if="!!$slots.default[0].text">Loading...</slot>
<p v-else>Searching...</p>
</div>
</template>
编辑 2:正如 @GoogleMac 在 cmets 中指出的那样,对于无渲染组件(例如 <transition>
、<keep-alive>
、...),检查插槽的文本属性失败,因此检查他们建议的是:
!!this.$slots.default && !!this.$slots.default[0]
// or..
!!(this.$slots.default || [])[0]
【讨论】:
我看到的问题是$slots.default.text
始终未定义。这是一个 jsfiddle:jsfiddle.net/JohnMoore/rmafyz2x/2
我的错,$slots.default
是一个数组,所以你需要的是$slots.default[0].text
:)
是的,这就是我一直在寻找的答案。只要我能测试$slots.default[0].text
,我就能实现我想要的。
对我来说,有一个插槽通过,但上面的答案仍然失败,因为插槽是一个 Vue <transition>
元素,里面有另一个元素。过渡元素的文本属性为undefined
。就我而言,我有一个计算属性,它返回 !!this.$slots.default && !!this.$slots.default[0]
。
@GoogleMac 啊哈,对我来说是 TIL 时刻!感谢分享,我已经编辑了我的答案以包含您的见解【参考方案2】:
@kano 的回答效果很好,但有个问题:this.$slots
不是反应式的,所以如果它开始是false
,然后变成true
,任何computed
属性都不会更新。
解决方案是不依赖computed
值,而是依赖created
和beforeUpdated
(as @MathewSonke points out):
export default
name: "YourComponentWithDynamicSlot",
data()
return
showFooter: false,
showHeader: false,
;
,
created()
this.setShowSlots();
,
beforeUpdate()
this.setShowSlots();
,
methods:
setShowSlots()
this.showFooter = this.$slots.footer?.[0];
this.showHeader = this.$slots.header?.[0];
,
,
;
更新:Vue 3(组合 API)
对于 Vue 3,检查插槽是否有内容的方式似乎发生了变化(使用新的组合 API):
import computed, defineComponent from "vue";
export default defineComponent(
setup(_, slots )
const showHeader = computed(() => !!slots.header);
return
showHeader,
;
,
);
注意:我找不到任何关于此的文档,所以请稍加注意,但似乎在我非常有限的测试中有效。
【讨论】:
对于 Vue 2,如果您使用的是作用域插槽,那么引用实际上是一个函数,而不是一个对象。所以你必须在检查子元素之前执行它。const scopedSlot = this.$scopedSlots.myScopedSlot; const scopedSlotResolved = scopedSlot(); const hasChild = !!(scopedSlotResolved?.[0]);
然后可以进行空检查,因为作用域槽引用直到生命周期的后期才会成为函数。以上是关于确定槽内容是空还是空的主要内容,如果未能解决你的问题,请参考以下文章