在生活中,很多地方都有插槽,电脑的USB、电源插槽等,插槽的目的是为了让我们原来的设备具备 更多的扩展性。组件的插槽是为了让我们封装的组件更加具有扩展性,让使用者可以决定组件内部的一些东西到底展示什么。比如,移动网站中的导航栏。在移动开发中,几乎每个页面都有导航栏,这种导航栏我们必然会封装成一个插槽,比如nav-bar组件,一旦有了这个组件,我们就可以在多个页面中复用了。
那么如何封装这类组件呢:抽取不同,保留相同。最好的封装方式就是将共性抽取到组件中,将不同暴露为插槽,一旦我们预留了插槽,就可以让使用者根据自己的需求,决定插槽中插入什么内容,是搜索框、菜单还是文字,由调用者自己来决定。
通过代码演示如何使用普通插槽、具名插槽、作用域插槽。
1.普通插槽:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<cpn>
<div>
<button>按钮</button>
</div>
</cpn>
<cpn>我是组件,啦啦啦啦</cpn>
</div>
<template id="cpn">
<div>
<slot></slot>
</div>
</template>
<script>
const cpn = {
template: "#cpn"
}
const app = new Vue({
el: "#app",
data: {},
components: {
cpn
}
})
}
</script>
</body>
</html>
解释:通过插槽可以自己定义组件中的内容。
2.具名插槽:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<cpn></cpn>
<cpn><button slot="left">按钮</button></cpn>
<cpn><span slot="center">中间</span></cpn>
<cpn><p slot="right">我是下面那</p></cpn>
</div>
<template id="cpn">
<div>
<slot name="left">左边</slot>
<slot name="center">中间</slot>
<slot name="right">右边</slot>
</div>
</template>
<script>
const cpn = {
template:"#cpn"
}
const app = new Vue({
el:"#app",
data:{
},
components:{
cpn
}
})
</script>
</body>
</html>
解释:使用组件时,若直接使用组件,则会将子组件模板中的所有插槽的内容都渲染在该组件中,如上述代码中有四个组件中的第一个子组件。若要改变子组件模板中的部分内容,可以使用slot元素的name属性,在使用组件时,利用slot属性,选择相应的slot元素,改变其内容即可。第二个组将利用name和slot属性,将子组件模板中name为left的插槽中的内容改为了一个button按钮。
3.作用域插槽:
在讲作用域插槽之前首先了解一下什么是编译作用域,即父组件模板中的所有东西都会在父组件作用域内编译,意思就是父组件模板只会使用父级数据。子组件模板中的东西都会在子组件作用域内编译,子组件模板中只会使用子级数据。
div id="app">
<cpn v-show="isShow"></cpn>
</div>
<template id="cpn">
<div>
<p>我是子组件,啦啦啦</p>
</div>
</template>
<script>
const cpn = {
template:"#cpn",
data(){
return {
isShow:false
}
}
}
const app = new Vue({
el:"#app",
data:{
isShow:true
},
components:{
cpn
}
})
</script>
解释:当Vue实例中和组件中都有isShow数据时,会根据作用域选择相应的isShow数据。该实例中会显示子组件中内容,因为程序中用到的isShow是在父组件模板中,因此使用Vue实例中的数据。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
<cpn></cpn>
<cpn>
<template slot-scope="slotProps">
<div>{{slotProps.data.join(' - ')}}</div>
</template>
</cpn>
<cpn><template slot-scope="slotProps">
<div>{{slotProps.data.join(' * ')}}</div>
</template></cpn>
</div>
<template id="cpn">
<div>
<slot :data="pLanguages">
<ul>
<li v-for="item in pLanguages">{{item}}</li>
</ul>
</slot>
</div>
</template>
<script>
const cpn = {
template: "#cpn",
data() {
return {
pLanguages: ["javascript", "C++", "java", "C#","PHP","Go"]
}
}
}
const app = new Vue({
el: "#app",
data: {
name: "我是Vue实例的name",
tel: 12345678910
},
methods: {},
components: {
cpn
}
})
</script>
</body>
</html>
解释:该程序在子组件模板中,把data和pLanguages绑定在一起,在使用父组件时,需要用到子组件中的数据,需要使用template标签作为子组件数据的通道,使用slot-scope属性,与子组件的slot元素进行绑定,若要使用子组件中的数据,则使用slotProps.data即可调用子组件中的数据。