美文网首页
Vue插槽学习理解

Vue插槽学习理解

作者: YouthInXian | 来源:发表于2019-06-05 15:19 被阅读0次

    阅读之前

    本文主要参照了Vue官方文档的插槽部分说明,中间加入的自己的理解,写的比较简洁易懂。各位看官可以对照官方文档和本文的介绍来理解slot插槽语法。

    Vue 插槽(2.60版本以后)

    插槽可以让通用组件更加多样化,它类似React中的children。

    声明:以下所有内容以父级(通用)组件和应用(调用)组件的关系举例说明。

    • 最简单的使用

    比如你想声明一个带有特殊border的div作为一个通用组件BorderedDiv。

    <template>
      <div class="some-border-class">
        // 这里是包裹的不同的内容
        // 可能你很想使用this.props.children(如果你曾是React使用者)
      </div>
    </template>
    

    在使用该组件时

    <bordered-div>
      <p>被包裹的文字</p>
    </bordered-div>
    

    这时你会想到:这个文字如何传递给父级组件呢?

    直接这样写就好:

    <template>
      <div class="some-border-class">
        // 这里是包裹的不同的内容
        <slot></slot>
      </div>
    </template>
    
    • 作用域

    <common-component :data="[1,2,3]">
        {{ data }}
        <!-- 
        这里的 `data` 会是 undefined,因为数组是 **传递给**  
        <common-component> 的而不是 在 <common-component> 组件
        **内部**定义的
        -->
    </common-component >
    

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

    简单来说:你不能在写children的时候直接使用父级组件中的数据,考虑当前环境。

    • 后备内容

    在<slot></slot>标签中的内容将在没有匹配到插槽内容时渲染

     <slot>如果没有children,我就会渲染</slot>
    

    如果父级模板中声明了插槽,但是应用组件却没有包裹任何内容,它便会渲染为备用内容。

    • 具名

    可以给<slot></slot> 传递name属性

    <div class="container">
    <header>
        <slot name="header"></slot>
    </header>
    <main>
        <slot name="default"></slot>
    </main>
    <footer>
        <slot name="footer"></slot>
    </footer>
    </div>
    

    然后这样向对应的插槽传递内容:

    <base-layout>
        <template v-slot:header>
            <h1>Here might be a page title</h1>
        </template>
        // 可以不用包裹template 直接传递给default slot
        <template v-slot:default>
            <p>A paragraph for the main content.</p> 
            <p>And another one.</p>
        </template>
        
        <template v-slot:footer>
            <p>Here's some contact info</p>
        </template>
    </base-layout>
    

    其中:<template v-slot:default>父节点可以省略。

    注意:

    v-slot指令只能使用在<template>上,除非只需要传递默认插槽。(也就是你的父级模板中只有一个没有name属性的插槽)
    这时它可以用在父组件上。
    尽管如此,它也只是<template v-slot:default></template>的缩写。
    在传递多个插槽时,还是需要使用完整的语法。

    • 作用域插槽

    在通用组件中声明的模板如下:

    <span>
        // 给slot声明了一个属性 
        // 该属性可以在对应的插槽内容中访问
        // 省略了 name = "default"
        <slot v-bind:user="user"></slot>
    </span>
    

    在应用组件中:

    <common-component>
        <!-- v-slot是v-slot:default的缩写 -->
        <template v-slot="slotProps">
            // 插槽上声明的user可以这样访问
            {{ slotProps.user.name }}
        </template>
    </common-component>
    

    在“装载插槽”时,slot上声明的属性绑定的数据会以函数的参数形式传递给插槽

    function (slotProps) {
        // 插槽的内容
    }
    

    因此可以在编写插槽内容时获取到common-component(父组件)中的数据。

    由于slotProps是以函数参数的形式传递的,因此各种简写也就可以理解了。

        // 解构传参
        <template v-slot:default="{ user }">
            {{  user.name }}
        </template>
        // 重命名
        <template v-slot:default="{ user: person }" >
            {{ person.name }}
        </template>
        // 默认值
        <template v-slot:default="{ user={ firstname: 'test' } }">
            {{ user.name }}
        </template>
    
    • 缩写

    在向具名(声明了name属性的)插槽传递内容时,(应用组件中)可以使用缩写:

    <common-layout>
        // 等同于:v-slot:header
       <template #header>
       // 以下模板内容会传递给name = header的插槽
           <p>this is header</p>
       </template>
       // 注意: 不可以 直接#
       <template #default>
       // 以下内容会传递给没有声明name的插槽,也就是默认插槽
           <p>this is default slot</p>
       </template>
    </common-layout>
    

    当然如果common-layout模板中如果只有一个默认插槽的话,你可以直接这样做:

    // 相当于: v-slot:default="slotProps"
    // default不可省略,否则引发警告
    <common-layout #default="slotProps">
       {{ slotProps.user.name }}
    </common-layout>
    
    • 其他示例

    请先看官方给出的示例:todoList示例

    关键点:
    通用组件中这样声明:

    <!--
        我们为每个 todo 准备了一个插槽, 将 `todo` 对象作为一个
        插槽的 prop 传入.
    -->
        <slot name="todo" v-bind:todo="todo">
            <!-- 后备内容 -->
            {{ todo.text }}
        </slot>
    

    应用组件中这样使用:

    <todo-list v-bind:todos="todos">
        // 或者简写为: #todo
        <template v-slot:todo="{ todo }">
            <span v-if="todo.isComplete">✓</span>
            {{ todo.text }}
        </template>
    </todo-list>
    

    这样使用就将li中的内容动态化。

    • 理解

    slot的基本用法简单来说就是(我的理解):

    在你声明一个通用的组件时,将通用的部分声明为模板,动态的内容,也就是各个应用组件不一致的地方,或者说可能需要动态渲染的部分声明为插槽slot,并给该插槽定义name,prop,以方便应用组件获取数据和对号入座。

    参考:

    Vue官方文档: https://cn.vuejs.org/v2/guide/components-slots.html

    相关文章

      网友评论

          本文标题:Vue插槽学习理解

          本文链接:https://www.haomeiwen.com/subject/bizjxctx.html