Vue 内容分发
Vue 实现了一套内容分发的 API,其设计灵感源自 Web Components 规范草案,将 <slot>元素作为承载分发内容的出口。
插槽,实质上是,子组件中的提供给父组件使用的一个占位符,用 <slot></slot> 元素表示( 位于子组件中 )。
- 插槽内容:父组件可以在这个占位符中填充任何内容,如 HTML、组件等
- 具名插槽( 父:v-slot 指令,子:<slot name=""></slot> )
- 插槽的使用:填充的内容会替换子组件的<slot></slot>标签
- ( 子组件 )默认插槽( 又称为:后备内容 )
- 作用域插槽:让父组件的插槽内容,能够访问子组件中已有的数据
使用场景:一般用于子组件的“模板结构”类似,而内容不同的情形( 通过父组件进行内容分发 )
基本用法
// 声明一个子组件 <div id="app"> <child-component></child-component> </div> <script> Vue.component('child-component',{ template:‘<div>Hello,World!</div>’ }) </script>我们可能需要向这个子组件中传递内容,像下面这样,结果会是怎样呢?
<child-component> 你好 // 可以是任何内容 </child-component>输出内容还是在组件中的内容,在 <child-component>内写的内容没起作用。怎么办呢?
还好,Vue 自定义的 <slot>元素( 插槽 )让这变得非常简单:
插槽,实际上就是调用组件时,放在( 父 )组件标签中传递内容的相应的子组件内部,
需要有 <slot> 标签来接收传递过来的内容,否则传递过来的任何内容都会被抛弃。
// 父组件 <template> <div id="app"> <div>父组件的内容</div> <!-- 引用子组件并传递内容 --> <Child>HelloWorld</Child> </div> </template> // 子组件 <template> <div id="content"> <div>子组件内容</div> <!-- 通过插槽接收内容 --> <slot></slot> </div> </template>
插槽的使用
- 默认插槽,又称为后备内容
后备内容放在 slot 标签中,有时为一个插槽设置具体的后备内容是很有用的,它只会在没有提供内容的时候被渲染。
// 父组件 <template> <div id="app"> <div>父组件的内容</div> <!-- 引用子组件:如果父组件中没有提供任何插槽内容,则"后备内容"将会被渲染 --> <Child></Child> <!-- 如果父组件中提供了插槽内容,则插槽内容将会替代“后备内容”被渲染 --> <!-- <Child>点击</Child> --> </div> </template> // 子组件 <template> <div id="content"> <!-- 默认插槽:后备内容放在 slot 标签中 --> <button><slot>Submit</slot></button> </div> </template>
- 具名插槽
自 2.6.0 起有所更新,已废弃使用。slot特性的语法<template slot="header"> <div>头部的内容</div> </template>
有时候,可能需要使用多个插槽。在向具名插槽提供内容的时,可以在一个
<template>元素上使用v-slot指令,并以v-slot的参数的形式提供其名称// 父组件 baseLayout.vue <template> <div id="app"> <div>父组件的内容</div> <!-- 引用子组件并传递内容 --> <Child> <template v-slot:header> <div>头部的内容</div> </template> <div>主体的内容</div> // 不具名,则其插槽的 name 值默认为“default” // v-slot: 可以简写为 # <template #footer> <div>底部的内容</div> </template> </Child> </div> </template>
<slot>元素有一个特殊的特性:name,可以用来定义额外的插槽// 子组件 <template> <div id="content"> <!-- 具名插槽 --> <div class="header"> <slot name="header"></slot> </div> // 一个不带name的<slot>默认会带有一个隐含的名字“default”,即:<slot name="default"></slot> <slot></slot> <div class="footer"> <slot name="footer"></slot> </div> </div> </template>
- 作用域插槽
自 2.6.0 起有所更新。已废弃使用。slot-scope特性的语法
关于插槽的作用域有一条基本规则:
父级模板里的所有内容都是在父级作用域中编译的,子模板里的所有内容都是在子作用域中编译的,二者相互隔离。
但有时候,让插槽内容能够访问子组件中已有的数据是很有用的。
插槽 prop 允许我们将插槽转换为可复用的模板,这些模板可以基于输入的 prop 渲染出不同的内容。
<!-- 子组件 Child.vue --> <template> <div id="content"> <!-- 绑定在 <slot>元素上的特性被称为插槽 prop --> <slot :person="person"></slot> </div> </template> <script> export default{ data(){ return{ person:{ name:'小明', age:20 } } } } </script>// 父组件 <template> <div id="app"> <div>父组件的内容</div> <!-- 引用子组件并传递内容 --> <!-- 在父级作用域中,我们可以给 v-slot带一个值来定义我们提供的插槽 prop 的名字 --> <!-- slotProps可以自定义 --> <Child v-slot:default='slotProps'> {{slotProps.person.name}} <!-- 小明 --> </Child> </div> </template>