有没有办法只显示一个插槽,如果它有任何内容?
例如,我正在构建一个简单的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>
Run Code Online (Sandbox Code Playgroud)
脚本:
<script>
export default {
props: {
active: true,
type: {
type: String,
default: 'default',
},
},
computed: {
panelType() {
return `panel-${this.type}`;
},
hasFooterSlot() {
return this.$slots['footer']
}
}
}
</script>
Run Code Online (Sandbox Code Playgroud)
在视图中:
<card type="success"></card>
Run Code Online (Sandbox Code Playgroud)
由于上面的组件不包含页脚,因此不应该呈现,但它是.
我尝试过使用this.$slots['footer']
,但这会返回undefined.
有人有任何提示吗?
小智 54
现在,在 Vue3 组合 API 中,您可以使用useSlots
.
<script setup>
import { useSlots } from 'vue'
const slots = useSlots()
</script>
<template>
<div v-if="slots.content" class="classname">
<slot name="content"></slot>
</div>
</template>
Run Code Online (Sandbox Code Playgroud)
Ber*_*ert 42
它应该在
this.$slots.footer
Run Code Online (Sandbox Code Playgroud)
所以,这应该工作.
hasFooterSlot() {
return !!this.$slots.footer
}
Run Code Online (Sandbox Code Playgroud)
例子.
biq*_*llo 22
CSS 大大简化了这个过程。只需使用以下代码即可!
.panel-footer:empty {
display: none;
}
Run Code Online (Sandbox Code Playgroud)
Mus*_*aya 13
这是 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>
Run Code Online (Sandbox Code Playgroud)
您应该检查vm.$slots
,也vm.$scopedSlots
为它。
hasSlot (name = 'default') {
return !!this.$slots[ name ] || !!this.$scopedSlots[ name ];
}
Run Code Online (Sandbox Code Playgroud)
简而言之,在内联中执行此操作:
<template lang="pug">
div
h2(v-if="$slots.title")
slot(name="title")
h3(v-if="$slots['sub-title']")
slot(name="sub-title")
</template>
Run Code Online (Sandbox Code Playgroud)
我遇到了一个类似的问题,但是在广泛的代码库中,并且在创建原子设计结构化组件时,编写hasSlot()
方法一直很累人,而且当涉及到 TDD 时 - 它是另一种测试方法......说,你可以总是将原始逻辑放在 a 中,v-if
但我发现模板最终会变得混乱且难以阅读,尤其是对于检查代码结构的新开发人员而言。
div
当没有提供插槽时,我的任务是找出一种删除插槽父级的方法。
问题:
<template>
<div>
<div class="hello">
<slot name="foo" />
</div>
<div class="world">
<slot name="bar" />
</div>
</div>
</template>
//instantiation
<my-component>
<span slot="foo">show me</span>
</my-component>
//renders
<div>
<div class="hello">
<span slot="foo">show me</span>
</div>
<div class="world"></div>
</div>
Run Code Online (Sandbox Code Playgroud)
如您所见,问题是我有一个几乎“尾随”的 div,当组件作者决定不需要bar
插槽时,它可能会提供样式问题。
ofcourse我们可以去<div v-if="$slots.bar">...</div>
或<div v-if="hasBar()">...</div>
等,但就像我说的-即可以得到烦人,最终落得难以阅读。
解决方案
我的解决方案是制作一个通用slot
组件,它只是渲染出一个带有周围 div 的插槽......见下文。
//slot component
<template>
<div v-if="!!$slots.default">
<slot />
</div>
</template>
//usage within <my-component/>
<template>
<div>
<slot-component class="hello">
<slot name="foo"/>
</slot-component>
<slot-component class="world">
<slot name="bar"/>
</slot-component>
</div>
</template>
//instantiation
<my-component>
<span slot="foo">show me</span>
</my-component>
//renders
<div>
<div class="hello">
<span>show me</span>
</div>
</div>
Run Code Online (Sandbox Code Playgroud)
我在尝试这个想法时遇到了用例问题,有时我的标记结构需要为了这种方法的好处而改变。这种方法减少了在每个组件模板中进行小槽检查的需要。我想您可以将组件视为<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: `
<div v-if="$slots.default">
<slot />
</div>
`
}
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)
//...rest of code
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
12596 次 |
最近记录: |