vue 插槽 slot 的用法
vue插槽slot的用法
vue 插槽 slot 的用法
一、简单定义、使用 slot
- 新建
child
子组件,定义container
插槽。
<!-- child.vue -->
<template>
<div>
<p> child 组件</p>
<slot name="container"></slot>
</div>
</template>
- 新建
father
组件,引用子组件child
的container
插槽。
<!-- father.vue -->
<template>
<div>
<p> father 组件</p>
<child>
<template slot="container">写法1</template>
<!-- <template #container>写法2</template> -->
<!-- <template v-slot:container>写法3</template> -->
</child>
</div>
</template>
<script>
import child from "./child.vue";
export default {
name: "father",
components: { child }
};
</script>
效果如图所示:
注:如果 father
组件引用插槽的时候不加具插槽名slot="container"
, 则默认替换整个 child
组件的内容。
二、slot 变量传值
- 在子组件
child
的基础上,给 slot 绑定message
变量,值为data
中的msg
变量值
<!-- child.vue -->
<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
变量。
<!-- father.vue -->
<template>
<div>
<p> father 组件</p>
<child>
<!-- <template slot="container" slot-scope="{message}">{{message}}</template> -->
<!-- <template #container="{message}">{{message}}</template> -->
<template v-slot:container="{message}">{{message}}</template>
</child>
</div>
</template>
<script>
import child from "./child.vue";
export default {
name: "father",
components: { child }
};
</script>
效果如图所示:
三、跨组件传递 slot
需求描述:
目前有三个组件,GrandFather.vue
组件、father.vue
组件 和child.vue
组件,GrandFather.vue
组件 想直接引用并向child.vue
的 slot 传递变量。
我们期望的正确展示效果如下图所示:
<!-- 1. child.vue 初始代码状态 -->
<template>
<div>
<p> 我是 child 组件</p>
<slot name="child-container"></slot>
</div>
</template>
<!-- 2. father.vue 初始代码状态 -->
<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>
<!-- 3. GrandFather.vue 初始代码状态 -->
<template>
<div>
<p> 我是 GrandFather 组件</p>
<father>
<template slot = "father-container">这里的值是 GrandFather 组件 想在 father 组件中的 father-container 插槽中展示</template>
<!-- 注意:GrandFather 组件想直接引用并替换 child 组件 的 child-container 的值,但按照目前 GrandFather 组件、father组件、child组件,是不可行的。-->
<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
组件是无法直接访问到的。那么要怎么实现上面的这种效果,有以下几种方法。
方法1: 多定义一个中间插槽
在不改动 child.vue
和 GrandFather.vue
的前提下,我们单独改动 father.vue
组件如下:
<!-- 2. father.vue -->
<template>
<div>
<p> 我是 father 组件</p>
<slot name="father-container"></slot>
<child>
<template slot="child-container"> <!-- 重点1:这里是在 father 组件中 引用 child 组件的 child-container 插槽 -->
<slot name="child-container"></slot> <!-- 重点2:这里是定义了一个 father 组件的 child-container 插槽 -->
</template>
</child>
</div>
</template>
<script>
import child from "./child.vue";
export default {
name: "father",
components: { child }
};
</script>
方法2:使用 scopedSlots 字段 传递作用域插槽
在 vue 官网上有句话叫做:vm.$scopedSlots
在使用 渲染函数 开发一个组件时特别有用。这个方法的改动也需要借助渲染函数。在不改动 child.vue
和 GrandFather.vue
的前提下,我们单独改动 father.vue
组件如下:
<!-- 注释代码:这段 template 代码与下面的 render 函数渲染的代码等价,但我们在 render 函数中借用了 scopedSlots,使得插槽 'child-container' 在当前作用域有效。
<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 },
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>
方法3:动态组件渲染[TODO]
该方法的大概思路为:子组件 主动去获取 父级组件 的 slot 对象,然后再创建一个动态组件进行渲染。将代码恢复至初始状态之后,在不改动GrandFather.vue
和 father.vue
的前提下,我们单独改动 child.vue
组件。
方法4:Provide/Inject 将Slot主动传递给子节点 [TODO]
附加
- $slots 可以拿到当前作用域的所有slot插槽
参考文件:
https://cn.vuejs.org/v2/guide/components-slots.html
https://cn.vuejs.org/v2/guide/render-function.html#%E6%8F%92%E6%A7%BD
更多推荐
所有评论(0)