组件的插槽
组件本身就是一个容器,也可以是一个vue对象,也是一个虚拟DOM
普通插槽
组件本身是一个容器,这个容器本身是空的,当我们把需要封装的html结构装进去之后,我们可以认为这个容器被塞满了,那就意味着,我们无法想组件内部添加新的html结构进去,但是我们想在每次调用组件的时候需要渲染一些个性化的东西,这个时候我们就需要给组件做一个预留空间,这个预留空间就是插槽
<body><div id="app"><one><p>我是子标题</p></one></div><template id="temp1"><div><h2>我是标题</h2></div></template>
</body>
<script src="js/vue.js"></script>
<script>let one = {template:"#temp1"}new Vue({el:"#app",components:{one}})
</script>
代码分析:
以上的代码渲染之后,我们在虚拟DOM中写入了一个p标签,着就是所谓的插入,但是并没有效果,因为我们并没有在one组件中预留空间,也就是插槽
如果想在组件内部预留插槽,使用
<slot></slot>
<body><div id="app"><one><p>我是子标题</p><p>我是子标题</p><p>我是子标题</p><p>我是子标题</p><p>我是子标题</p><p>我是子标题</p></one></div><template id="temp1"><div><h2>我是标题</h2><slot><!-- 组件内预留给插槽的空间 --></slot></div></template>
</body>
<script src="js/vue.js"></script>
<script>let one = {template:"#temp1"}new Vue({el:"#app",components:{one}})
</script>
一个插入点插入多个插槽
现在我们想让刚才的代码中前3个p标签出现在标题的上方,后面3个出现在标题的下方
<body><div id="app"><one><p>我是子标题</p><p>我是子标题</p><p>我是子标题</p><p>我是子标题</p><p>我是子标题</p><p>我是子标题</p></one></div><template id="temp1"><div><slot></slot><h2>我是标题</h2><slot></slot></div></template>
</body>
<script src="js/vue.js"></script>
<script>let one = {template:"#temp1"}new Vue({el:"#app",components:{one}})
</script>
代码分析:
上面的代码中,我们发现,在模板中的标题上方也制作了一个插槽slot,但是,从效果上来看只是单纯把插入的内容复制了一份,分别插入不同的插槽里面
其实我们上面写的都是默认插槽,把插槽语法写完成如下
<div id="app"><one><p slot="default">我是子标题</p><p slot="default">我是子标题</p><p slot="default">我是子标题</p><p slot="default">我是子标题</p><p slot="default">我是子标题</p><p slot="default">我是子标题</p></one>
</div>
<template id="temp1"><div><slot name="default"></slot><h2>我是标题</h2><slot name="default"></slot></div>
</template>
默认情况下,所有的slot都必须要指定一个name,只是如果我们不自己指定的话,系统会给我们指定一个默认的名称default
具名插槽
在上面的插槽中,我们所有的slot如果在不指定name的情况下全都是default,但是这个name属性可以设置的,如果设置一些其他的值,我们就把这个插槽叫做具名插槽
<div id="app"><one><p slot="top">我是子标题</p><p slot="top">我是子标题</p><p slot="top">我是子标题</p><p slot="bottom">我是子标题</p><p slot="bottom">我是子标题</p><p slot="bottom">我是子标题</p></one>
</div>
<template id="temp1"><div><slot name="top"></slot><h2>我是标题</h2><slot name="bottom"></slot></div>
</template>
代码分析:
在上面的代码中,我们可以为插槽取一个名字,从而实现一对多,或者多对一的插入,当插槽有了名字之后,我们就可以在插入的时候指定插入到某一个插槽中
- 我们组件里面定义插槽的时候使用slot标签,并且这个标签上面定义name属性,成为具名插槽
- 在调用组件的时候,我们可以向指定的插槽插入内容,只需要在这个插入的元素上面添加一个slot=“插槽名”即可
- 具名插槽是可以多次使用的,所以我们可以把上面的top复制一份放到bottom的下面,这样上面三个p标签也会出现在下面的插槽里面
插槽作用域
<body><div id="app"><one><p>我想要拿到组件内部的userName</p></one></div><template id="temp1"><div><h2>我是一个组件</h2><slot><!-- 组件的预留空间 --></slot></div></template>
</body>
<script src="js/vue.js"></script>
<script>let one = {template:"#temp1",data(){return {userName:"zhangsan"}}}new Vue({el:"#app",components:{one}})
</script>
之前我们一直都是外部的数据传递给内部,如果要把组件内部的数据传递给外部,我们可以:
1、利用对象的堆栈原理
2、自定义事件
注意:
我们现在要做一个区分,我们是可以把数据渲染在组件里面的,也可以渲染在插槽里面,但是这两种方式在向组件外部传值的时候是有区别的,我们上面说的这两种方法,只针对在组件内渲染的,如果是渲染在组件的插槽内部的,我们可以通过插槽作用域取拿
比如我们现在要userName的值传递到外面,我们可以在插入的标签上面添加一个slot-scope=“scope”
<body><div id="app"><one><div slot-scope="scope"><p>{{scope.userName}}</p><p>{{scope.age}}</p></div> </one></div><template id="temp1"><div><h2>我是一个组件</h2><slot :user-name="userName" :age="18"><!-- 组件的预留空间 --></slot></div></template>
</body>
<script src="js/vue.js"></script>
<script>let one = {template:"#temp1",data(){return {userName:"zhangsan"}}}new Vue({el:"#app",components:{one}})
</script>
插槽作用域旧版本语法
<div id="app"><one><div slot="footer" slot-scope="scope"><p>{{scope.userName}}</p><p>{{scope.age}}</p></div> </one></div><template id="temp1"><div><h2>我是一个组件</h2><slot name="footer" :user-name="userName" :age="18"><!-- 组件的预留空间 --></slot></div></template>
新版本语法
<one><template v-slot:footer="scope"><p>{{scope.userName}}</p><p>{{scope.age}}</p></template>
</one>
最新语法
<one><template #footer="{userName,age}"><p>{{userName}}</p>"<p>{{age}}</p></template>
</one>
代码分析:
最新语法可以直接解构获取,并且v-slot这个指令也直接使用#来替代,简化代码