1×3 精读Vue官方文档 – 插槽

精读 Vue 官方文档系列 ?

插槽 Slot 其设计灵感源自 Web Components 规范草案,将 <slot> 元素作为承载分发内容的出口。

关于内容分发,我们可以类比于 $attrs 实例属性分发所有的 Attribute;$listeners 实例属性可以分发所有的事件一样。

插槽作用在组件的内部,用来接收自定义元素(自定义组件)开始标签与结束标签之间的内容,然后在组件内容指定位置进行输出,如果自定义组件的模板不含有 <slot> 元素,那么自定义元素的内容将会被抛弃。

Vue.component('custom-element', {
    template:'<p></p>'
});
Vue.component('custom-element-2', {
    template:'<p><slot></slot></p>'
});
复制代码
<!-- This is custom element content 并不会显示 -->
<custom-element>This is custom element content</custom-element>

<!-- 正常显示 -->
<custom-element-2>This is custom element content</custom-element-2>
复制代码

插槽可以接受任何类型的内容,也包括另一个组件。

编译作用域

父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的。

插槽的内容定义在父级,编译在父级,属于父级的一部分,编译后的内容会传入到插槽元素所在的组件中由该组件执行后展示,遵循于 JavaScript 词法作用域的规定,插槽内容只能访问父级作用域里面的数据,而不能访问插槽元素所在子组件内的数据。

后备内容

插槽的默认值会在插槽没有接收到任何内容时默认被渲染。

Vue.component('base-button', {
    template:'<slot>button</slot>'
});
复制代码

父级会将内容放置在自定义元素的开始与结束标签之间来传递值,然后在自定义组件内部中通过 <slot> 元素来分发内容。

具名插槽

当需要多个插槽来分发内容时,可以为 <slot> 元素命名,用来锚定内容输出所对应的插槽。

顾名思义,“具名插槽”就是存在多个插槽时为插槽命名以作区别。

使用 name 属性为多个插槽命名,一个不带 name 的出口会带有隐含的名字“default”。

<script id="base-layout-template">
    <slot></slot>
    <slot name="other"></slot>
</script>
<script>
Vue.component('base-layout', {
    template:'#base-layout-template',
});
</script>
复制代码

实际使用时我们会通过 <template> 元素进行分组,每个 <template> 元素上绑定一个 v-slot 指令,并以插槽名称作为指令参数,来为锚定的具名插槽提供一块完整的内容输出。

<base-layout>
    <p>Content</p>
    <template v-slot:header>Header & Menu & Nav</template>
    <template v-slot:footer>Footer</template>
</base-layout>
复制代码

图示:

slot.png

作用域插槽

从插槽的编译作用域可知,定义在父组件作用域中的插槽内容是无法获取插槽元素 <slot> 所在组件内的数据。具有作用域的插槽就是为了打通插槽由内到外的数据传递,让插槽内容也能访问插槽元素 <slot> 所在组件内的数据。

步骤如下:

  1. 使用 v-bind 指令来为当前组件内的 <slot> 元素绑定插槽 Prop,这个 Prop 编译后就会作为参数(组件内的数据)传递到作用域插槽中。
  2. 在父作用域的插槽内容 <template> 元素上使用 v-slot 指令并以插槽名称作为指令参数来接收上一步 <slot> 元素所绑定的插槽 Prop,从而实现在插槽中获取插槽所在组件内的数据。
Vue.component('mouse-move', {
    template:'<slot name="default" v-bind:pos="{x:xAxis, y:yAxis}"></slot>,
    data(){
        return {
            xAxis:0,
            yAxis:0
        }
    },
    mounted(){
        window.addEventListener('mousemove',e=>{
            this.xAxis = e.clientX;
            this.yAxis = e.clientY;
        },{passive:true});
    }
})
复制代码
<mouse-move>
    <template v-slot:default="slotProps">
        <ul>
            <li>xAxis:{{slotProps.x}}</li>
            <li>yAxis:{{slotProps.y}}</li>
        </ul>
    </template>
</mouse-move>
复制代码

如果存在多个具名插槽,分别单独接收每个插槽绑定的 Prop 即可,默认的插槽名称为 default 或者直接为空。

<slot-example>
    <template v-slot="slotProps">{{slotProps.value}}</template>
    <template v-slot:other="otherSlotProps">        {{otherSlotProps.value}}</template>
</slot-example>
复制代码

独占默认插槽的写法

若组件只提供了一个默认插槽,那么便可以直接将 v-slot=”slotProps“ 指令添加在组件的自定义元素上。

<slot-example v-slot="slotProps"></slot-example>
复制代码

等价于

<slot-example>
    <template v-slot:default="slotProps"></template>
</slot-example>
复制代码

可以实现省去一个 <template> 元素的效果。

如果组件内部存在多个插槽,那么插槽内容必须要严格使用 <template> 元素并添加 v-slot:[slotName]="{{slotName}}SlotProps" 方式锚定需要输出的目标具名插槽。

<slot-example>
    <template v-slot="slotProps"></template>
    <template v-slot:other="otherSlotProps"></template>
</slot-example>
复制代码

注意默认插槽的名称为 default,可省去不写。

解构插槽

插槽内容是在父级中编译,编译后的插槽内容会被包裹在一个拥有单个参数的函数里,再传递到子组件中,由子组件执行,当子组件执行时会同插槽 Prop 的值一同传入。

Vue 会将 <slot> 元素上绑定的所有 Props 以键值对的形式组合在 slotProps 对象中,然后作为参数传递给包裹插槽内容的方法里,这意味着,我们可以通过 ES6 的解构语法在模板中以更简洁的方式取得插槽 Prop 中的值。

<slot-example v-slot="{x, y}"></slot-example>
复制代码

动态插槽名称

具名插槽的名称可以是一个动态的值,这与动态指令参数的效果相同。

<!--Definition-->
<slot :name="slotName" :values="vals"></slot>

<!--Usage-->
<slot-example>
    <template v-slot:[slotName]="slotProps">
    </template>
</slot-example>
复制代码

具名插槽简写

v-onv-bind 指令一样,我们可以使用 # 来缩写 v-slot 指令

<template #default></template>
<template #other="otherSlotProps"></template>
复制代码

缩写 v-slot 指令时必须具有指令参数。

其它应用

当我们进行可复用组件设计时,既想基于子组件绑定的插槽Prop来渲染出不同的内容,又想让父组件也可以自定义部份布局,那么使用”作用域插槽“的模式将会很有效果。

下面是一些基于“作用域插槽”这思想实现的可复用的 Vue 组件。

总结

使用 <slot> 元素的 name 属性来定义一个具名插槽,其中 name 的值可缺省,默认为 default ; 插槽的 <slot> 元素还可以通过 v-bind 指令将插槽所在组件内的数据绑定到 Prop 中,在插槽内容被执行时作为参数传递进入。

在父作用域中使用具有插槽元素的组件时,便可以通过为其绑定 v-slot:[name]="slotProps" 指令来接收对应具名插槽绑定的 Prop。

  • # 可用于替代 v-slot 指令进行缩写,并且必须含有指令参数。
  • 插槽默认名称为 default,可省略不写。
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享