春节Vue-2.6.0发布后,对slot插槽进行了必定的优化,那么对于插槽,你真正的了解吗?如下是我使用中总结的拙见,欢迎批评指正+++++html
最近在作业务组件的时候,用到三种slot,被叫作”默认插槽“,”具名插槽“,”做用域插槽“。浏览器
子组件ide
<a v-bind:href="url" class="nav-link"> <slot>content</slot> </a>
父组件post
<navigation-link url="/profile"> Your Profile </navigation-link>
若是父组件为这个插槽提供了内容Your Profile,则默认的内容content会被替换掉。优化
若是子组件中的多个位置都须要父组件塞进不一样的内容时,你须要使用具名插槽。url
<div class="container"> <header> <slot name="header"></slot> </header> <main> <slot name-"main"></slot> </main> <footer> <slot name="footer"></slot> </footer> </div>
子组件在header main footer三处须要塞入不一样的内容,在父组件的 <template> 元素上使用 slot特性:spa
<base-layout> <template slot="header"> <h1>Here might be a page title</h1> </template> <p>A paragraph for the main content.</p> <p>And another one.</p> <template slot="footer"> <p>Here's some contact info</p> </template> </base-layout>
看起来具名插槽能解决大部分的问题了,可是,在这种状况面前使用具名插槽会报错:code
<div v-for="(item, index) in resultList" :key="index"> <div class="list-content"> <p class="content" v-html="item.content"/> <slot name="content"></slot> </div> </div>
当使用v-for迭代,同一具名插槽重复出现的时候,浏览器就会报错
这时咱们不得不使用做用域插槽component
在 <template> 上使用特殊的 slot-scope 特性,能够接收传递给插槽的 prophtm
子组件内两处地方放置两处插槽
<!--位置1--> <slot name="tips" :tips="item.access"></slot> <!--位置2--> <slot name="content" :content="item.content"></slot>
父组件-使用时,slot=name 具名,调用scope.[name]
<template slot="tips" slot-scope="scope"> <span class="item-header-state" v-if="scope.tips === true"><i class="el-icon-check" />已认证</span> </template> <template slot="content" slot-scope="scope"> <el-tag v-for="(tag, index) in scope.content.labels" :key="index" closable type="info" size="small" :disable-transitions="false" @close="handleCloseTag(tag, scope.content)"> {{tag.label}} </el-tag> </template>
But 自 2.6.0 起以上被废弃。新推荐的语法请查阅这里。
父组件以另一种方式(不是经过常规的 Props 属性传递机制)向子组件传递信息。我发现把这种方法同常规的 HTML 元素联系起来颇有帮助。
好比说 HTML 标签。
<a href=”/sometarget">This is a link</a>
若是这是在 Vue 环境中而且 <a>
是你的组件,那么你须要发送“This is a link”信息到‘a’组件里面,而后它将被渲染成为一个超连接,而“This is a link”就是这个连接的文本。
让咱们定义一个子组件来展现它的机制是怎样的:
<template> <div> <slot></slot> </div> </template>
而后在父组件咱们这么作:
<template> <div> <child-component>This is from outside</child-component> </div> </template>
这时候屏幕上呈现的就应该和你预期的同样就是“This is from outside”,但这是由子组件所渲染出来的。
咱们还能够给子组件添加默认的信息,以避免到时候这里出现什么都没有传入的状况,就像这样子:
<template> <div> <slot>Some default message</slot> </div> </template>
而后若是咱们像这样子建立咱们的子组件:
<child-component> </child-component>
咱们能够看到屏幕上会呈现“Some default message”。
具名插槽和常规插槽很是相似,惟一的差异就是你能够在你的目标组件多个位置传入你的文本。
咱们把子组件升级一下,让它有多个具名插槽
<template> <div> <slot>Some default message</slot> <br/> <slot _name_="top"></slot> <br/> <slot _name_="bottom"></slot> </div> </template>
这样,在咱们的子组件中就有了三个插槽。其中 top 和 bottom 插槽是具名插槽。
让咱们更新父组件以使用它。
<child-component _v-slot:top_> Hello there! </child-component>
注意 —— 咱们在这里使用新的 Vue 2.6 语法来指定咱们想要定位的插槽:v-slot:theName
。
你如今认为会在屏幕上看到什么呢?若是你说是“Hello Top!”,那么你就只说对了一部分。
由于我没有为没有具名的插槽赋予任何值,咱们所以也还会获得默认值。因此咱们真正会看到的是:
Some default message
Hello There!
其实真正意义上没有具名的插槽是被看成‘default’,因此你还能够这么作:
<child-component _v-slot:default_> Hello There! </child-component>
如今咱们就只会看到:
Hello There!
由于咱们已经提供了值给默认(也就是未具名)插槽,所以具名插槽‘top’和‘bottom’也都没有默认值。
你发送的并不必定只是文本,还能够是其余组件或者 HTML。你能够发送任意你想展现的内容。
我认为插槽和具名插槽相对简单,一旦你稍微玩玩就能够掌握。可另外一方面,做用域插槽虽然名字类似但又有些不一样之处。
我倾向于认为做用域插槽有点像一个放映机(或者是一个我欧洲朋友的投影仪)。如下是缘由。
子组件中的做用域插槽能够为父组件中的插槽的显示提供数据。这就像一我的带着放映机站在你的子组件里面,而后在父组件的墙上让一些图像发光。
这有一个例子。在子组件中咱们像这样设置了一个插槽:
<template> <div> <slot _name_="top" _:myUser_="user"></slot> <br/> <slot _name_="bottom"></slot> <br/> </div> </template> <script> data() { _return_ { user: "Ross" } } </script>
注意到咱们的具名插槽‘top’如今有了一个名为‘myUser’的属性,而后咱们绑定了一个动态的值在‘user’中。
在咱们的父组件中就像这样子设置子组件:
<div> <child-component _v-slot:top_="slotProps">{{ slotProps }}</child-component> </div>
咱们在屏幕上看到的就是这样子:
{ “myUser”: “Ross” }
仍是使用放映机的类比,咱们的子组件经过 myUser 对象将其用户字符串的值传递给父组件。它在父组件上投射到的墙就被称为‘slotProps’。
我知道这不是一个完美的类比,但当我第一次尝试理解这个机制的时候,它帮助我以这种方式思考。
Vue 的文档很是好,并且我也已经看到了一些其余关于做用域插槽工做机制的说明。但不少人采起的方法彷佛是将父组件中的全部或部分属性命名为与子组件相同,我认为这会使得数据很难被追踪。
在父组件中使用 ES6 解构,咱们这样子写还能够将特定 user 对象从插槽属性(你能够随便怎么称呼它)解脱出来:
<child-component _v-slot:top_="{myUser}">{{ myUser }}</child-component>
或者甚至就只是在父组件中给它一个新的名字:
<child-component _v-slot:top_="{myUser: aFancyName}">{{ aFancyName }}</child-component>
全部都是经过 ES6 解构,与 Vue 自己并无什么关系。
若是你正开始使用 Vue 和插槽,但愿这可让你起步并解决一些棘手的问题。