基础用法 标签<slot>会把组件使用上下文的内容注入到此标签所占据的位置上。组件分发的概念简单而强大,因为它意味着对一个隔离的组件除了通过属性、事件交互之外,还可以注入内容。 尽管内容分发这个概念看起来极为复杂,而实际上可以简单了解为把HTML标签传入组件的一种方法。所以归根结底,内容分发是一种为组件传递参数的方法。 <div class="" id="app"> <my-component> <p>hi,slots</p> </my-component> </div> <script> Vue.component('my-component', { template:'<div><slot></slot><div>' }); new Vue({ el: "#app" }); </script>
编译作用域 组件作用域简单地说是:父组件模板的内容在父组件作用域内编译;子组件模板的内容在子组件作用域内编译。 <!DOCTYPE html> <html> <head> <title></title> <meta charset="utf-8"/> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> </head> <body> <div id="app"> <child-component v-show="someChildProperty"></child-component> </div> <script> Vue.component('child-component', { template: '<div>这是子组件内容</div>', data: function () { return { someChildProperty: true } } }) new Vue({ el:'#app' }) </script> </body> </html>
这里someChildProperty绑定的是父组件的数据,所以是无效的,获取不到数据。如果想在子组件上绑定,可以是如下代码: 因此,slot分发的内容是在父作用域内编译。 <div id="app"> <child-component ></child-component> </div> <script> Vue.component('child-component', { // 有效,因为是在正确的作用域内 template: '<div v-show="someChildProperty">这是子组件内容</div>', data: function () { return { someChildProperty: true } } }) new Vue({ el:'#app' }) </script>
默认 slot 如果要父组件在子组件中插入内容 ,必须要在子组件中声明slot 标签 ,如果子组件模板不包含<slot>插口,父组件的内容将会被丢弃 <!DOCTYPE html> <html> <head> <title></title> <meta charset="utf-8"/> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> </head> <body> <div id="app"> <!-- 1.2 那组件innerHTML位置以后不管有任何代码,都会被放进插槽那个坑里面去 --> <index> <span>首页</span> <span>首页</span> <span>首页</span> <h1>手机</h1> </index> </div> <script> // 插槽的作用就是组件外部取代码片段放到组件内部来 // 定义默认插槽通过slot组件定义,定义好了之后,就相当于一个坑,你可以把它理解为电脑上usb插口 Vue.component('index', { template:' <div>index</div>' }) var vm = new Vue({ el: '#app', }) </script> </body> </html>
页面显示结果为:index。所有子组件中的内容都不会被显示,被丢弃。 要想父组件在 子组件中插入内容,必须要在子组件中声明 slot 标签,示例代码如下: <script> vue. component ( 'index', { template : '<div><slot></slot>index </div>' }) var vm=new vue ( { el : '#app ' , }) </script>
具名 slot slot 元素可以用一个特殊的属性 name 来配置如何分发内容。多个 slot 标签可以有不同的名字。 使用方法。 父组件要在分发的标签中添加属性"slot=name 名"。 子组件在对应分发位置上的 slot 标签添加属性"name=name 名"。
<!DOCTYPE html> <html> <head> <title></title> <meta charset="utf-8"/> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> </head> <body> <body> <div id="app"> <child> <span slot="one">123456</span> <span slot="two">abcdef</span> </child> </div> <script> new Vue({ el:'#app', components:{ child:{ template:"<div><slot name='two'></slot>我是子组件<slot name='one'></slot></div>" } } }); </script> </body> </body> </html>
作用域插槽 作用域插槽的样式由父组件决定,内容却由子组件控制。 作用域插槽更具代表性的应用是列表组件,允许组件自定义应该如何渲染列表每一项,如下面示例代码: <div id="app"> <child></child> </div> <script> Vue.component('child', { data(){ return { list:[1,2,3,4] } }, template: '<div> <ul>' + '<li v-for="item of list">{{item}}</li></ul></div>', }) var vm = new Vue({ el: '#app' }) </script>
在上面示例代码中,如果需要child组件在很多地方会被调用,我希望在不同的地方调用child的组件时,这个列表到底怎么循环,列表的样式不是child组件控制的,而是外部child模版占位符告诉我们组件的每一项该如何渲染,也就是说这里不用li标签,而是要用slot标签,示例代码如下: <div id="app"> <child> <template slot-scope="props"> <!--固定写法,属性值可以自定义--> <li>{{props.item}}</li> <!--用插值表达式就可以直接使用--> </template> </child> </div> <script> Vue.component('child', { data(){ return { list:[1,2,3,4] } }, template: '<div> <ul>' + '<slot v-for="item of list" :item=item></slot> </ul></div>', }) var vm = new Vue({ el: '#app' }) </script>