一、插槽用法及概念
slot又名插槽,是Vue的内容分发机制,组件内部的模板引擎使用slot元素作为承载分发内容的出口。插槽slot是子组件的一个模板标签元素,而这一个标签元素是否显示,以及怎么显示是由父组件决定的。slot又分为默认插槽,具名插槽和作用域插槽等。
二、插槽的基本类型
1. 默认插槽(Default Slot)
- 定义:没有指定名称的插槽,用于接收父组件传递的未明确指定插槽名称的内容。
- 用法:在子组件中使用
<slot></slot>
定义默认插槽的位置,父组件中直接放在子组件标签内的内容会被渲染到该位置。
举例说明:
子组件 (DefaultSlotChild.vue)
<template>
<div class="child">
<h2>我是子组件的标题</h2>
<!-- 默认插槽 -->
<slot></slot>
</div>
</template>
父组件
<template>
<div>
<DefaultSlotChild>
<!-- 这里的内容会被渲染到子组件的默认插槽中 -->
<p>这是来自父组件的默认插槽内容。111</p>
<p>这是来自父组件的默认插槽内容。222</p>
</DefaultSlotChild>
</div>
</template>
<script>
import DefaultSlotChild from './DefaultSlotChild.vue';
export default {
components: {
DefaultSlotChild
}
}
</script>
父组件上最终效果
<template>
<div>
<!-- 以下内容是子组件中的内容 begin-->
<template>
<div class="child">
<h2>我是子组件的标题</h2>
<!-- 这里的内容会被渲染到子组件的默认插槽中 -->
<p>这是来自父组件的默认插槽内容。111</p>
<p>这是来自父组件的默认插槽内容。222</p>
</div>
</template>
<!-- 以上内容是子组件中的内容 end-->
</div>
</template>
2. 具名插槽(Named Slots)
- 定义:带有名称的插槽,用于接收父组件中明确指定插槽名称的内容。
- 用法:在子组件中使用
<slot name="插槽名称"></slot>
定义具名插槽,父组件中通过<template v-slot:插槽名称>
或简写为<template #插槽名称>
来指定内容应该插入哪个具名插槽。
举例说明:
子组件 (NamedSlotChild.vue)
<template>
<div class="child">
<header>
<!-- 具名插槽:header -->
<slot name="header"></slot>
</header>
<main>
<!-- 默认插槽 -->
<slot></slot>
</main>
<footer>
<!-- 具名插槽:footer -->
<slot name="footer"></slot>
</footer>
</div>
</template>
父组件
<template>
<NamedSlotChild>
<template v-slot:header>
<!-- 这里的内容会被渲染到子组件的header插槽中 -->
<h1>这是标题</h1>
</template>
<p>这是默认插槽的内容。</p>
<template v-slot:footer>
<!-- 这里的内容会被渲染到子组件的footer插槽中 -->
<p>这是页脚</p>
</template>
</NamedSlotChild>
</template>
<script>
import NamedSlotChild from './NamedSlotChild.vue';
export default {
components: {
NamedSlotChild
}
}
</script>
3. 作用域插槽(Scoped Slots)
- 定义:一种特殊的插槽,允许子组件将数据暴露给父组件的插槽内容。
- 用法:
在子组件中,通过<slot :数据名="数据值"></slot>
将数据传递给插槽;
在父组件中,通过<template v-slot:插槽名称="slotProps">
接收数据,并使用slotProps
来访问传递过来的数据。
举例说明
子组件 (ScopedSlotChild.vue)
<template>
<ul>
<li v-for="item in items" :key="item.id">
<slot name="item" :item="item">
<!-- 后备内容 -->
{{ item.text }}
</slot>
</li>
</ul>
</template>
<script>
export default {
data() {
return {
items: [
{ id: 1, text: '苹果' },
{ id: 2, text: '香蕉' },
{ id: 3, text: '橙子' }
]
}
}
}
</script>
父组件
<template>
<ScopedSlotChild>
<template v-slot:item="slotProps">
<!-- 使用slotProps访问子组件传递的数据 -->
<strong>{{ slotProps.item.text }}</strong>
</template>
</ScopedSlotChild>
</template>
<script>
import ScopedSlotChild from './ScopedSlotChild.vue';
export default {
components: {
ScopedSlotChild
}
}
</script>
4. 动态插槽名(Dynamic Slot Names)
- 定义:允许插槽的名称是动态的,根据组件的状态或其他条件来决定使用哪个插槽。
- 用法:在父组件中,通过
:slot="动态名称"
来绑定插槽的名称,其中动态名称可以是一个计算属性、方法返回值或数据属性。
举例说明:
这个例子稍微复杂一些,因为它通常用于更高级的场景,比如根据条件动态渲染不同的插槽。但基本思想是使用计算属性或方法来返回插槽名。
子组件(与前面的例子类似,不需要特别修改)
父组件(简化示例)
<template>
<div>
<NamedSlotChild>
<!-- 使用计算属性dynamicSlotName来决定内容应该渲染到哪个插槽中 -->
<template v-slot:[dynamicSlotName]>
<p>这是根据条件动态插入到对应插槽的内容。</p>
</template>
</NamedSlotChild>
</div>
</template>
<script>
import NamedSlotChild from './NamedSlotChild.vue';
export default {
components: {
NamedSlotChild
},
computed: {
// 假设这里根据某个条件返回不同的插槽名
dynamicSlotName() {
// 示例:根据某个数据属性来决定
const someCondition = true; // 实际应用中这里可能是更复杂的逻辑或响应式数据
if (someCondition) {
return 'header';
} else {
return 'footer';
}
}
}
}
</script>
三、Vue 2.6.0之前与Vue 2.6.0后的比对
在Vue 2.6.0及以后的版本中,Vue团队对插槽(slot)的语法进行了简化和改进,引入了v-slot指令来替代原有的slot和slot-scope语法
1.默认插槽 缩写(由不写变成v-slot)
父组件
<child-component><p>这是默认插槽的内容</p></child-component>
子组件
<template><slot></slot></template>
缩写后变成
父组件(推荐使用<template>标签,但也可直接用于元素上)
<child-component>
<template v-slot><p>这是默认插槽的内容</p></template>
</child-component>
或(注意:直接在元素上使用v-slot较少见,且可能需要额外配置)
<child-component>
<p v-slot></p>
</child-component>
子组件不变
<template><slot></slot></template>
2.具名插槽 缩写 (由slot变成 v-slot)
父组件
<child-component>
<template slot="header"><h1>这是头部内容</h1></template>
<template slot="footer"><p>这是底部内容</p></template>
</child-component>
子组件
<template>
<slot name="header"></slot>
<slot name="footer"></slot>
</template>
缩写后变成
父组件
<child-component>
<template v-slot:header><h1>这是头部内容</h1></template>
<template v-slot:footer><p>这是底部内容</p></template>
</child-component>
或简写
<child-component>
<template #header><h1>这是头部内容</h1></template>
<template #footer><p>这是底部内容</p></template>
</child-component>
子组件不变
<template>
<slot name="header"></slot>
<slot name="footer"></slot>
</template>
3.作用域插槽 缩写 (由slot变成 v-slot)
父组件
<child-component>
<template slot="item" slot-scope="slotProps">
<p>{{ slotProps.text }}</p>
</template>
</child-component>
子组件
<template>
<slot name="item" :text="itemText"></slot>
</template>
缩写后变成
父组件
<child-component>
<template v-slot:item="slotProps">
<p>{{ slotProps.text }}</p>
</template>
</child-component>
或简写
<child-component>
<template #item="slotProps">
<p>{{ slotProps.text }}</p>
</template>
</child-component>
子组件不变
<template>
<slot name="item" :text="itemText"></slot>
</template>
结语:
插槽是Vue.js中非常重要的一个概念,它允许父组件向子组件的模板中插入内容,从而实现组件内容的分发和组合。
1.复用组件:插槽可以使组件更加灵活和可复用,使用者可以根据需要在插槽中插入不同的内容,而不需要修改组件的源代码。
2.定制化(组件可扩展性):插槽可以用来定制组件的外观和功能。通过插槽,使用者可以自定义组件中特定的部分,从而满足自己的需求。
3.组件通信:插槽也可以用于组件之间的通信。通过插槽,父组件可以向子组件传递数据或者方法,子组件可以通过插槽接收并使用这些数据或方法。
在实际开发中,根据具体的需求和场景选择合适的插槽用法,可以构建出高效、可维护的Vue.js应用。