【问题标题】: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 返回未定义。

【问题讨论】:

    标签: vue.js


    【解决方案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 中指出的那样,对于无渲染组件(例如 &lt;transition&gt;&lt;keep-alive&gt;、...),检查插槽的文本属性失败,因此检查他们建议的是:

    !!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 &lt;transition&gt; 元素,里面有另一个元素。过渡元素的文本属性为undefined。就我而言,我有一个计算属性,它返回 !!this.$slots.default &amp;&amp; !!this.$slots.default[0]
    • @GoogleMac 啊哈,对我来说是 TIL 时刻!感谢分享,我已经编辑了我的答案以包含您的见解
    【解决方案2】:

    @kano 的回答效果很好,但有个问题:this.$slots 不是反应式的,所以如果它开始是false,然后变成true,任何computed 属性都不会更新。

    解决方案是不依赖computed 值,而是依赖createdbeforeUpdated (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]); 然后可以进行空检查,因为作用域槽引用直到生命周期的后期才会成为函数。
    猜你喜欢
    • 1970-01-01
    • 2019-01-11
    • 2011-02-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多