PaulChess / MyBlog

1 stars 0 forks source link

vue系列之插槽 #23

Open PaulChess opened 3 years ago

PaulChess commented 3 years ago

常规组件

// BookList.vue
<ul>
  <li v-for="book in books" :key="book.id">
    {{ book.name }}
  </li>
</ul>

自定义模板(即内容分发),就要用到slot, 但是slot只能是固定的模板,没办法自定义循环体中的一个具体的项

作用域插槽 常规的slot无法实现对组件循环体的每一项内容进行不同的内容分发。slot-scope本质上和slot一样,只不过可以传递参数。如下:

// BookList.vue
<ul>
  <li v-for="book in books" :key="book.id">
    <slot :book="book">
        <!-- 默认内容 -->
        {{  book.name }}
    </slot>
  </li>
</ul>

在slot上,传递了一个自定义的参数book, 它的值绑定时当前循环项的数据book,这样在父级使用时,就可以在slot中访问它了。

// Parent.vue
<BookList :books="books">
  <template v-slot:default="slotProps">
    <span v-if="slotProps.book.sale">显示优惠</span>
    {{ slotProps.book.name }}
  </template>
</BookList>

绑定在元素上的attribute被称为插槽prop。在父级作用域中,我们可以使用带值的v-slot来定义我们提供的插槽prop的名字。

image

PaulChess commented 3 years ago

渲染作用域

  1. 当你想在一个插槽中使用数据时,例如:

    // ✅
    <todo-button>
    Delete a {{ item.name }}
    </todo-button>

    该插槽可以访问与当前模板其余部分相同的实例property, 即相同的作用域 image

  2. 但是插槽不能访问子组件<todo-button></todo-button>的作用域,例如:

    // ❌
    <todo-button action="delete">
    Clicking here will {{ action }} an item
    <!-- `action` 未被定义,因为它的内容是传递*到* <todo-button>,而不是*在* <todo-button>里定义的。  -->
    </todo-button>

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

PaulChess commented 3 years ago

具名插槽

有时候我们的组件里需要多个插槽,此时具名插槽可以帮我们将内容精准地分发到指定的位置 slot元素有一个特殊的attribute: name, 可以用来定义额外的插槽。一个不带name<slot>出口会带有隐含的name -> default 例如这里有一个<base-layout>组件:

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

使用: v-slot:name, 注意: v-slot只能添加在<template>

// Parent.vue
<base-layout>
  <template v-slot:header>
    <h1>Here might be a page title</h1>
  </template>

  <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>

特殊情况 当被提供的内容只有默认插槽时,组件的标签才可以被当作插槽的模板来使用,我们就可以把v-slot直接用在组件上。

<todo-list v-slot:default="slotProps">
  <i class="fas fa-check"></i>
  <span class="green">{{ slotProps.item }}</span>
</todo-list>

更简化写法:

<todo-list v-slot="slotProps">
  <i class="fas fa-check"></i>
  <span class="green">{{ slotProps.item }}</span>
</todo-list>