在使用组件时,组件开始标签和结束标签的内容会被忽视,如下代码
<div id="app">
<my-com>I want to be shown</my-com>
</div>
<script>
Vue.component("myCom", {
template: "<h1>this is the template</h1>"
})
let vm = new Vue({
el: "#app",
data: {},
methods: {}
})
</script>
这里my-com开始标签和结束标签间的内容不会显示出来,整个标签都被模板覆盖了,如果要在html中传入开始标签和结束标签之间的内容的话,就可以使用插槽。
插槽的基本使用
插槽通过<slot>标签来实现,组件标签间的内容会出现在模板中<slot></slot>的位置。如下代码
<div id="app">
<my-com>I want to be shown</my-com>
</div>
<script>
Vue.component("myCom", {
template: "<h1>this is the template <slot></slot></h1>"
})
let vm = new Vue({
el: "#app",
data: {},
methods: {}
})
</script>
在页面中最终就会渲染为
<div id="app">
<h1>this is the template I want to be shown</h1>
</div>
可以看到标签间的内容已经被渲染到原来的<slot></slot>的位置了。
标签间的内容会以html的方式解析出来,即是说可以在标签里面放html结构。
<div id="app">
<my-com>
<span>I am a span</span>
</my-com>
</div>
<script>
Vue.component("myCom", {
template: "<div><p>this is the template</p> <slot></slot></div>"
})
let vm = new Vue({
el: "#app",
data: {},
methods: {}
})
</script>
渲染到页面后为
<div id="app">
<div>
<p>this is the template</p>
<span>I am a span</span>
</div>
</div>
插槽的后备内容/默认值
如果要在标签内没内容时传入一个默认值,那么直接在模板中的<slot></slot>间插入内容即可。
<div id="app">
<my-com>I want to be shown</my-com>
<my-com></my-com>
</div>
<script>
Vue.component("myCom", {
template: "<div><p>this is the template</p> <slot>I am the default value</slot></div>"
})
let vm = new Vue({
el: "#app",
data: {},
methods: {}
})
</script>
在页面中渲染为
<div id="app">
<div>
<p>this is the template</p>
I want to be shown
</div>
<div>
<p>this is the template</p>
I am the default value
</div>
</div>
具名插槽
如果要在模板的不同位置插入不同的内容,就可以使用具名插槽,为每个位置指定具体的名称,分别插入不同的内容。
具名插槽在组件标签中使用template来包裹插槽的内容,并使用v-slot指明插槽的名称,然后在模板中的<slot></slot>中再使用name属性来指明要使用哪一个插槽。
<div id="app">
<my-com>
<template v-slot:first>I am the first</template>
<template v-slot:second>I am the second</template>
<template v-slot:third>I am the third</template>
</my-com>
</div>
<script>
Vue.component("myCom", {
template: `<div>
<h1>
<slot name="first"></slot>
</h1>
<h2>
<slot name="second"></slot>
</h2>
<h3>
<slot name="third"></slot>
</h3>
</div>`
})
let vm = new Vue({
el: "#app",
data: {},
methods: {}
})
</script>
在页面中渲染为
<div id="app">
<div>
<h1>I am the first</h1>
<h2>I am the second</h2>
<h3>I am the third</h3>
</div>
</div>
无名称的插槽
如果有一个template没有指明使用插槽名称,则默认使用defult作为名称
<div id="app">
<my-com>
<template v-slot:first>I am the first</template>
<template v-slot:second>I am the second</template>
<template v-slot:third>I am the third</template>
<template>I don't have v-slot</template>
</my-com>
</div>
<script>
Vue.component("myCom", {
template: `<div>
<h1>
<slot name="first"></slot>
</h1>
<h2>
<slot name="second"></slot>
</h2>
<h3>
<slot name="third"></slot>
</h3>
<p>
<slot name="default"></slot>
</p>
</div>`
})
let vm = new Vue({
el: "#app",
data: {},
methods: {}
})
</script>
页面中渲染为
<div id="app">
<div>
<h1>I am the first</h1>
<h2>I am the second</h2>
<h3>I am the third</h3>
<p> I don't have v-slot</p>
</div>
</div>
变量控制
v-slot也可以绑定data中变量对应的内容,只要在v-slot后面的内容添加[]即可。
<div id="app">
<my-com>
<template v-slot:[h1]>I am the first</template>
<template v-slot:[h2]>I am the second</template>
<template v-slot:[h3]>I am the third</template>
</my-com>
</div>
<script>
Vue.component("myCom", {
template: `<div>
<h1>
<slot name="first"></slot>
</h1>
<h2>
<slot name="second"></slot>
</h2>
<h3>
<slot name="third"></slot>
</h3>
</div>`
})
let vm = new Vue({
el: "#app",
data: {
h1: 'first',
h2: 'second',
h3: 'third'
},
methods: {}
})
</script>
在页面中渲染为
<div id="app">
<div>
<h1>I am the first</h1>
<h2>I am the second</h2>
<h3>I am the third</h3>
</div>
</div>
v-slot缩写
v-slot和v-bind,v-on一样,有自己的缩写"#"。使用缩写与原来渲染出来的结果是相同的。
<div id="app">
<my-com>
<template #:[h1]>I am the first</template>
<template #:[h2]>I am the second</template>
<template #:[h3]>I am the third</template>
</my-com>
</div>
<script>
Vue.component("myCom", {
template: `<div>
<h1>
<slot name="first"></slot>
</h1>
<h2>
<slot name="second"></slot>
</h2>
<h3>
<slot name="third"></slot>
</h3>
</div>`
})
let vm = new Vue({
el: "#app",
data: {
h1: 'first',
h2: 'second',
h3: 'third'
},
methods: {}
})
</script>
插槽的作用域
插槽可以使用其组件所在的父组件的data,但不可以直接使用其组件的data
<div id="app">
<my-com>
<!-- childStr无法正常显示,会报childStr没定义的错误 -->
<p>{{childStr}}</p>
<p>{{parentStr}}</p>
</my-com>
</div>
<script>
Vue.component("myCom", {
template: "<div><slot></slot></div>",
data: () => {
return {
childStr: "child"
}
}
})
let vm = new Vue({
el: "#app",
data: {
parentStr: "parent"
}
})
</script>
要使用其组件中的data,可以在其父作用域中设置一个插槽prop,在组件的模板中将组件的data中的值作为slot的特性绑定到父作用域中。设置插槽prop可以使用v-slot(#),与上面指明哪一个slot使用“:”不一样,这里使用的是“=”。
<div id="app">
<my-com>
<template v-slot="slotProps">{{slotProps.childStr}}</template>
</my-com>
</div>
<script>
Vue.component("myCom", {
template: "<div><slot :childStr='childStr'></slot></div>",
data: () => {
return {
childStr: "child"
}
}
})
let vm = new Vue({
el: "#app",
data: {
parentStr: "parent"
}
})
</script>
解构插槽
在设置插槽prop时,可以采用解构插槽的方法,这样会更为便利,减少了prop名称的设置
<div id="app">
<my-com>
<template v-slot="{childStr}">{{childStr}}</template>
</my-com>
</div>
<script>
Vue.component("myCom", {
template: "<div><slot :childStr='childStr'></slot></div>",
data: () => {
return {
childStr: "child"
}
}
})
let vm = new Vue({
el: "#app",
data: {
parentStr: "parent"
}
})
</script>
使用解构插槽时,可以设置默认值,在没有该值时使用默认值,直接使用=即可。
<div id="app">
<my-com>
<template v-slot="{childStr='default value'}">{{childStr}}</template>
</my-com>
</div>
<script>
Vue.component("myCom", {
template: "<div><slot :childStr='childStr'></slot></div>"
})
let vm = new Vue({
el: "#app",
data: {
parentStr: "parent"
}
})
</script>
页面最后渲染为
<div id="app">
<div>default value</div>
</div>
可以看到最后是使用了默认值。