child
子组件,定义 container
插槽。
<template>
<div>
<p> child 组件p>
<slot name="container">slot>
div>
template>
father
组件,引用子组件 child
的 container
插槽。
<template>
<div>
<p> father 组件p>
<child>
<template slot="container">写法1template>
child>
div>
template>
<script>
import child from "./child.vue";
export default {
name: "father",
components: { child }
};
script>
注:如果 father
组件引用插槽的时候不加具插槽名slot="container"
, 则默认替换整个 child
组件的内容。
child
的基础上,给 slot 绑定 message
变量,值为 data
中的 msg
变量值
<template>
<div>
<p> child 组件p>
<slot name="container" :message="msg">slot>
div>
template>
<script>
export default {
name: 'child',
data() {
return {
msg: '我是子组件 data 中的 msg 变量'
}
}
}
script>
father
的基础上,接收子组件 child
的 container
插槽传过来的 message
变量。
<template>
<div>
<p> father 组件p>
<child>
<template v-slot:container="{message}">{{message}}template>
child>
div>
template>
<script>
import child from "./child.vue";
export default {
name: "father",
components: { child }
};
script>
需求描述:
目前有三个组件,GrandFather.vue
组件、father.vue
组件 和child.vue
组件,GrandFather.vue
组件 想直接引用并向child.vue
的 slot 传递变量。
我们期望的正确展示效果如下图所示:
<template>
<div>
<p> 我是 child 组件p>
<slot name="child-container">slot>
div>
template>
<template>
<div>
<p> 我是 father 组件p>
<slot name="father-container">slot>
<child>
<template slot="child-container">这里的值是 father 组件在 child 组件中的 child-container 插槽中展示template>
child>
div>
template>
<script>
import child from "./child.vue";
export default {
name: "father",
components: { child }
};
script>
<template>
<div>
<p> 我是 GrandFather 组件p>
<father>
<template slot = "father-container">这里的值是 GrandFather 组件 想在 father 组件中的 father-container 插槽中展示template>
<template slot = "child-container">这里的值是 GrandFather 组件 想在 child 组件中的 child-container 插槽中展示template>
father>
div>
template>
<script>
import father from "./father.vue";
export default {
name: "GrandFather",
components: { father}
};
script>
上面的图片结果是初始化代码运行的结果,但似乎与我们期望的代码结果不一致。这是为什么呢?注意在 vue 官网中强调过一点:
父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的。
所以,在 GrandFather
组件中,仅能访问到 father
组件中定义过的插槽,而 child
组件中定义的插槽,GrandFather
组件是无法直接访问到的。那么要怎么实现上面的这种效果,有以下几种方法。
在不改动 child.vue
和 GrandFather.vue
的前提下,我们单独改动 father.vue
组件如下:
<template>
<div>
<p> 我是 father 组件p>
<slot name="father-container">slot>
<child>
<template slot="child-container">
<slot name="child-container">slot>
template>
child>
div>
template>
<script>
import child from "./child.vue";
export default {
name: "father",
components: { child }
};
script>
在 vue 官网上有句话叫做:vm.$scopedSlots
在使用 渲染函数 开发一个组件时特别有用。这个方法的改动也需要借助渲染函数。在不改动 child.vue
和 GrandFather.vue
的前提下,我们单独改动 father.vue
组件如下:
<script>
import child from "./child.vue";
export default {
name: "father",
components: { child },
render(createElement) {
const defaultChildSlotMsg = '这里的值是 father 组件在 child 组件中的 child-container插槽中展示'
return createElement("div", [
createElement("p", "我是 father 组件"),
createElement("slot", this.$slots["father-container"]), // 创建插槽,内容为 GrandFather.vue 中引用 'father-container' 的内容
createElement("child", {
scopedSlots: {
// child.vue 中的插槽名: ()=> GrandFather.vue 引用的插槽名
"child-container": () => this.$slots["child-container"] || defaultChildSlotMsg
}
}),
]);
}
};
script>
该方法的大概思路为:子组件 主动去获取 父级组件 的 slot 对象,然后再创建一个动态组件进行渲染。将代码恢复至初始状态之后,在不改动GrandFather.vue
和 father.vue
的前提下,我们单独改动 child.vue
组件。
参考文件:
https://cn.vuejs.org/v2/guide/components-slots.html
https://cn.vuejs.org/v2/guide/render-function.html#%E6%8F%92%E6%A7%BD