一、初步了解slot
什么是slot呢?通俗的来说就是“占坑”,举个简单的例子看看
在child.vue中有如下代码
<template>
<div>
<slot></slot>
</div>
</template>
在App.vue中的代码如下:
<template>
<div id="app">
<child>
<h1>我就是占坑的内容啦,哈哈哈~</h1>
</child>
</div>
</template>
结果:
可以看到,在child组件中slot就相当于一个坑,让App组件往里面填充任何你想要填充的东西,这个坑就是专为你准备的,如果这时候将child组件里面的<slot></slot>去掉,那么<h1>我就是占坑的内容啦,哈哈哈~</h1>将会被抛弃。
哇~原来是那么简单的呀,如果此时你有这样的想法,那么我就要残忍的告诉你,你想多了,这只是简单的一个例子,关于插槽,我们还需要了解它的编译作用域、具名插槽、作用域插槽等等。
二、编译作用域
关于编译作用域,我们只需记住一句话:父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的。
三、具名插槽
在实际的开发中,有时候我们需要多个插槽而不是一个,这个时候我们又该怎么做呢?对于这个情况,<slot>
元素有一个特殊的特性:name
。这个特性可以用来定义额外的插槽:
child组件代码如下:
<template>
<div>
<header>
<slot name="header"></slot>
</header>
<slot></slot>
<footer>
<slot name="footer"></slot>
</footer>
</div>
</template>
一个不带 name
的 <slot>
出口会带有隐含的名字“default”。
在向具名插槽提供内容的时候,我们可以在一个 <template>
元素上使用 v-slot
指令,并以 v-slot
的参数的形式提供其名称:
App组件的代码如下:
<template>
<div id="app">
<child>
<template v-slot:header>
<h1>i am header</h1>
</template>
<template v-slot:default>
<h1>i am default</h1>
</template>
<template v-slot:footer>
<h1>i am footer</h1>
</template>
</child>
</div>
</template>
在 <template>
元素中的所有内容都将会被传入相应的插槽。任何没有被包裹在带有 v-slot
的 <template>
中的内容都会被视为默认插槽的内容。
然而,如果你希望更明确一些,仍然可以在一个 <template>
中包裹默认插槽的内容,如上面的dafault部分,也可以选择直接写
<h1>i am default</h1>
注意 v-slot
只能添加在一个 <template>
上 (只有一种例外情况),这一点和已经废弃的 slot
特性不同。
四、作用域插槽
有时让插槽内容能够访问子组件中才有的数据是很有用的。如下面的例子,在App组件里面去访问child组件里面的数据
child组件的代码如下:
<template>
<div>
<header>
<slot name="header" :user="user"></slot> //将 user
作为一个 <slot>
元素的特性绑定上去,绑定在 <slot>
元素上的特性被称为插槽 prop
</header>
<slot></slot>
<footer>
<slot name="footer"></slot>
</footer>
</div>
</template>
<script>
export default {
data(){
return {
user:{
firstname:'zhangsan'
}
}
}
}
</script>
App组件的代码如下:
<template>
<div id="app">
<child>
<template v-slot:header="onuser"> //给 v-slot
带一个值来定义我们提供的插槽 prop 的名字,这里的onuser也可以起你们喜欢的名字
<h1>i am header</h1>
<h2>{{ onuser.user.firstname }}</h2>
</template>
<template v-slot:default>
<h1>i am default</h1>
</template>
<template v-slot:footer>
<h1>i am footer</h1>
</template>
</child>
</div>
</template>
五、动态插槽名
动态指令参数也可以用在 v-slot
上,来定义动态的插槽名:
child组件的代码如下:
<template>
<div>
<header>
<slot name="header"></slot>
</header>
<slot></slot>
<footer>
<slot name="footer"></slot>
</footer>
</div>
</template>
App组件的代码如下:
<template>
<div id="app">
<child>
<template v-slot:[dynamicSlotName]>
<h1>i am header</h1>
</template>
<template v-slot:default>
<h1>i am default</h1>
</template>
<template v-slot:footer>
<h1>i am footer</h1>
</template>
</child>
</div>
</template>
export default {
name: 'App',
data(){
return{
dynamicSlotName: 'header' //可以动态改变插槽名
}
}
}
六、具名插槽的缩写
跟 v-on
和 v-bind
一样,v-slot
也有缩写,即把参数之前的所有内容 (v-slot:
) 替换为字符 #
。例如 v-slot:header
可以被重写为 #header