ChatGPT解决这个技术问题 Extra ChatGPT

仅在有内容时才显示插槽

如果它有任何内容,有没有办法只显示一个插槽?

例如,我正在构建一个简单的 Card.vue 组件,并且我只希望在页脚槽有内容时显示页脚:

模板

<template>
    <div class="panel" :class="panelType">
        <div class="panel-heading">
            <h3 class="panel-title">
                <slot name="title">
                    Default Title
                </slot>
            </h3>
        </div>

        <div class="panel-body">
            <slot name="body"></slot>
            
            <p class="category">
                <slot name="category"></slot>
            </p>
        </div>

        <div class="panel-footer" v-if="hasFooterSlot">
            <slot name="footer"></slot>
        </div>
    </div>
</template>

脚本

<script>
    export default {
        props: {
            active: true,
            type: {
                type: String,
                default: 'default',
            },
        },

        computed: {
            panelType() {
                return `panel-${this.type}`;
            },

            hasFooterSlot() {
                return this.$slots['footer']
            }
        }
    }
</script>

在视图中:

<card type="success"></card>

由于上述组件不包含页脚,因此不应渲染它,但它是。

我试过使用 this.$slots['footer'],但这返回未定义。

有没有人有任何提示?


r
radbyx

它应该在

this.$slots.footer

所以,这应该有效。

hasFooterSlot() {
  return !!this.$slots.footer;
}

Example


作品!抱歉,这是我的错,在插槽中输入内容时使用了不正确的语法。谢谢!! :)
this.$slots.footerthis.$slots['footer'] 是等价的,不是吗?这真的是解决方案还是有其他问题?
@DanielBeck你是对的,他们都会指向同一件事。如果没有内容,两者都将返回 undefined。唯一不同的是我返回一个布尔值,但是,测试它,从 hasFooterSlot 返回 undefined 将导致 v-if 隐藏组件。所以,从技术上讲,我认为你的代码应该可以工作。
这似乎不适用于 Vue 2.6 中的所有情况 - 当存在其他 $scopedSlots 时错误地返回 false(至少在某些情况下,例如从 dom 中删除并通过 v-if 添加回来的元素)
请注意,在 Vue 3 中,$slots 中的属性现在是方法,因此您需要使用如下语法:this.$slots.footer()
M
Madmadi

您应该检查 vm.$slotsvm.$scopedSlots

hasSlot (name = 'default') {
   return !!this.$slots[ name ] || !!this.$scopedSlots[ name ];
}

但是 this.$scopedSlots[ name ] 返回一个渲染函数,而不是像 vm.$slots 那样的 vNode 数组。
所以最后它强制布尔值为真。
我的 this.$slots 是一个空对象,this.$scopedSlots 帮助我。
请参阅 stackoverflow.com/a/60977785/752916 以获得考虑到 $scopeSlots[name] 是一个函数的答案(Vue 2.1.0+)
b
biquillo

CSS 大大简化了这一点。只需使用以下代码,瞧!

.panel-footer:empty {
  display: none;
}

这真的很有用,没有意识到这在 CSS 中存在。谢谢!
M
Mustafa Akçakaya

这是 Vue 3 组合 API 的解决方案:

<template>
    <div class="md:grid md:grid-cols-5 md:gap-6">

        <!-- Here, you hide the wrapper if there is no used slot or empty --> 
        <div class="md:col-span-2" v-if="hasTitle">
            <slot name="title"></slot>
        </div>

        <div class="mt-5 md:mt-0" 
            :class="{'md:col-span-3': hasTitle, 'md:col-span-5': !hasTitle}">
            <div class="bg-white rounded-md shadow">
                <div class="py-7">
                    <slot></slot>
                </div>
            </div>
        </div>
    </div>
</template>

<script>
import {ref} from "vue";

export default {
    setup(props, {slots}) {
        const hasTitle = ref(false)

        // Check if the slot exists by name and has content.
        // It returns an empty array if it's empty.
        if (slots.title && slots.title().length) {
            hasTitle.value = true
        }

        return {
            hasTitle
        }
    }
}
</script>

S
Syed

简而言之,内联执行此操作:

<template lang="pug">
  div
    h2(v-if="$slots.title")
      slot(name="title")
    h3(v-if="$slots['sub-title']")
      slot(name="sub-title")
</template>

最佳答案。适用于 Vue 3!非常感谢!
F
Francis Leigh

我遇到了一个类似的问题,但是在广泛的代码库中,当创建原子设计结构化组件时,一直编写 hasSlot() 方法可能会很累,而当涉及到 TDD 时——它的另一种测试方法......说,您始终可以将原始逻辑放在 v-if 中,但我发现模板有时会变得混乱且难以阅读,尤其是对于检查代码结构的新开发人员而言。

我的任务是找出在未提供插槽时删除父插槽 div 的方法。

问题:

//实例化 show me //渲染

给我看

如您所见,问题是我有一个几乎“尾随”的 div,当组件作者认为不需要 bar 插槽时,它可能会提供样式问题。

当然,我们可以使用 <div v-if="$slots.bar">...</div><div v-if="hasBar()">...</div> 等,但就像我说的那样 - 这会让人厌烦并最终变得更难阅读。

解决方案

我的解决方案是制作一个通用 slot 组件,它只渲染出一个带有周围 div 的插槽...见下文。

//slot 组件 //在 中使用 //实例化 show me //渲染

给我看

我在尝试这个想法时遇到了用例问题,有时我的标记结构需要为了这种方法的利益而改变。这种方法减少了在每个组件模板中进行小槽检查的需要。我想您可以将该组件视为 <conditional-div /> 组件...

还值得注意的是,将属性应用到 slot-component 实例化 (<slot-component class="myClass" data-random="randomshjhsa" />) 很好,因为属性会滴入 slot-component 模板的包含 div。

希望这可以帮助。

更新我为此编写了一个插件,因此不再需要在每个使用者组件中导入 custom-slot 组件,您只需在 main.js 中编写 Vue.use(SlotPlugin)实例化。 (见下文)

const SLOT_COMPONENT = { name: 'custom-slot', template: `

` } const SLOT_PLUGIN = { install (Vue) { Vue.component (SLOT_COMPONENT.name, SLOT_COMPONENT) } } export default SLOT_PLUGIN //main.js import SlotPlugin from 'path/to/plugin' Vue.use(SlotPlugin) //...其余代码


这很酷,但由于各种边缘情况、scopedSlots、默认插槽内部内容、命名插槽等而有一个滑坡;在我看来,包装插槽似乎是一种反模式,最好询问您要包装的插槽是否存在于组件中(this.$slots)。好奇您的解决方案从那时起是如何演变的。
A
AlexMA

最初我认为 https://stackoverflow.com/a/50096300/752916 正在工作,但我不得不对其进行一些扩展,因为 $scopeSlots 返回一个无论其返回值如何总是真实的函数。这是我的解决方案,尽管我得出的结论是,这个问题的真正答案是“这样做是一种反模式,你应该尽可能避免它”。例如,只需制作一个可以插入的单独页脚组件。

哈克解决方案

   hasFooterSlot() {
        const ss = this.$scopedSlots;
        const footerNodes = ss && ss.footer && ss.footer();
        return footerNodes && footerNodes.length;
   }

最佳实践(页脚的辅助组件)

const panelComponent = { template: `

` } const footerComponent = { template: ` ` } var app = new Vue({ el: '#app', components: { panelComponent, footerComponent }, data() { return { name: 'Vue' } } }) .nice-panel { max-宽度:200px;边框:1px 纯浅灰色; } .nice-panel-content { 填充:30px; } .nice-panel-footer { 背景颜色:浅灰色;填充:5px 30px;文本对齐:居中; }

带页脚的面板

lorem ipsum

没有页脚的面板

lorem ipsum


g
grindking

希望我理解这一点。如果插槽为空,为什么不使用未呈现的 <template> 标记。

<slot name="foo"></slot>

像这样使用它:

<template slot="foo">
   ...
</template>

问题是当您希望外部元素包装插槽,但不希望在插槽未给定或为空时呈现外部元素。这不会解决用例问题。
N
Non404

经过测试

所以这在 vue 3 中对我有用:

我使用 onMounted 首先获取值,然后使用 onUpdate 来更新值。

   <template>
     <div v-if="content" class="w-1/2">
          <slot name="content"></slot>
     </div>
   </template>


 <script>
     import { ref, onMounted, defineComponent, onUpdated } from "vue";   
     export default defineComponent({
        setup(props, { slots }) {
        const content = ref()
        onMounted(() => {
                if (slots.content && slots.content().length) {
                    content.value = true
                }
            })
            onUpdated(() => {
                content.value = slots.content().length
                console.log('CHECK VALUE', content.value)
            })
})
</script>

y
yellowsir

@Bert 答案似乎不适用于 <template v-slot:foo="{data}"> ... </template> 等动态模板。我最终使用:

 return (
        Boolean(this.$slots.foo) ||
        Boolean(typeof this.$scopedSlots.foo == 'function')
      );

S
Sunghyun Cho

现在,在 Vue3 组合 API 中,您可以使用 useSlots

<script setup>
const slots = useSlots()
</script>

<template>
  <div v-if="slots.content" class="classname">
    <slot name="content"></slot>
  </div>
</template>

关注公众号,不定期副业成功案例分享
关注公众号

不定期副业成功案例分享

领先一步获取最新的外包任务吗?

立即订阅