Vue: Detailed explanation of slots

1. Default slot

1. Code demonstration

Insert image description here

Through the above code, we understand at least the following two points:
1. The slot can have default content,
2. The default slot, The content of the component will all be replaced in the slot
2. The data of the parent component can also be displayed in the child component (the scope of the data will be used later in the scope slot)

2. Grammar

fixed tank<slot>插槽的默认内容</slot>

Using tank:<组件> 内容全部替换到插槽中 </组件>

2. Named slot

1. Code demonstration

Insert image description here

Named slot: To understand simply, it is to name each<slot> to distinguish it.
Note: The default slot also has name, name='default'

2. Grammar

fixed tank<slot name="one"></slot>

Using tank:<template v-slot:one> <div>{ { msg }}</div> </template>

Short copy<template #one> <div>{ { msg }}</div> </template>

3. Dynamic slot name

Insert image description here

Dynamic slot name:
The slot names defined now are all hard-coded, and Vue also supports defining slot names as variables.

fixed tank<slot :name="name"></slot>

Using tank:<template #[name]> <div>动态插槽名</div> </template>

3. Scope slot

1. Rendering scope

Insert image description here

Rendering scope:
All content in the parent template is compiled in the parent scope
All content in the child template They are all compiled in child scopes

Therefore, a problem also arises:
Assume that in the first scenario, you need to write a product card component and display multiple cards through a loop,
And it is required to jump to the product details page in response to the click event on each card. How would you write it?

Insert image description here

I would use the following processing method,

  • First write the product card as a componentcard.vue,
  • Use one incardList.vue to handle the display of the product card list. v-for
  • card.vueThe component passes$emit to the parent componentcardClick and carries product data,
  • The parent component can obtain the data in theonClick method and perform business processing,
  • This completes a basic data transfer from child to parent.
// cardList.vue
<template>
  <div class="card">
    <Card v-for="item in cardData" :key="item" @cardClick="onClick()"></Card>
  </div>
</template>


// card.vue
<template>
  <div class="div" @click="onClick()">卡片</div>
</template>
<script>
export default {
      
      
  methods: {
      
      
    onClick () {
      
      
      this.$emit('cardClick')
    }
  }
}
</script>

What if we abstract it further?
For example, if there are multiple operating columns, such as the Taobao homepage has two columns: "Have Good Products" and "Love Shopping", each column needs to have a list of product cards, then the product card ListcardList.vue is about to draw components. As for this vue component that contains multiple operating columns, I assume it is called finalList.vue, in which the component is called through v-for. cardList.vue
Insert image description here

Note:
Here comes the demand—>I hope to handle the business of clicking on product cards infinalList.vue. How to deal with it?

method 1:

  • When the product button is clicked,
  • card.vueFor configuration$emitNotificationcardList.vue,
  • cardList.vueContinue to use$emitToss up, notifyfinalList.vue
  • finalList.vueUse event reception and processing.

There is absolutely no problem in doing this, but it seems that the sub-component is very impure and has nothing to do with the business.

2. Scope slot (practical application)

So how to solve the above problem elegantly? At this time, the scope slot really comes in handy.

Let’s first look at how to solve the above problem through scope slots.

(1)finalList.vue

// src\views\06slot\finalList.vue
<template>
  <div>
    <div v-for="item in '123'" :key="item">
      <div style="text-align: left;">第{
   
   { item }}个</div>
      <CardList :cardData="cardData" class="cardlist">
        <template v-slot="scope">
          <Card :cardObj="scope.row" @click.native="cardClick(scope.row)" class="card"></Card>
        </template>
      </CardList>
    </div>
  </div>
</template>

<script>
import Card from './card.vue'
import CardList from './cardList.vue'
export default {
      
      
  components: {
      
      
    Card,
    CardList
  },
  data () {
      
      
    return {
      
      
      cardData: [
        {
      
       name: 'zs', age: 18 },
        {
      
       name: 'ls', age: 19 }
      ]
    }
  },
  methods: {
      
      
    cardClick (row) {
      
      
      console.log('卡片点击了:' + row.name + '--' + row.age)
    }
  }
}
</script>

<style scoped>
.cardlist {
      
      
  display: flex;
}
.card {
      
      
  margin: 10px 20px;

}
</style>

(2)cardList.vue

// src\views\06slot\cardList.vue
<template>
  <div>
    <div v-for="(item, index) in cardData" :key="index">
      <slot :row="item"></slot>
    </div>
  </div>
</template>

<script>
export default {
      
      
  props: {
      
      
    cardData: {
      
      
      type: Array
    }
  }
}
</script>
<style  scoped>
</style>

(3)card.view

// src\views\06slot\card.vue
<template>
  <div class="div">
    <div>{
   
   { cardObj.name }}</div>
    <div>{
   
   { cardObj.age }}</div>
  </div>
</template>

<script>
export default {
      
      
  props: {
      
      
    cardObj: {
      
      
      type: Object,
      default: () => {
      
       }
    }
  }
}
</script>
<style  scoped>
.div {
      
      
  width: 100px;
  height: 100px;
  background-color: pink;
}
</style>

(4) Final effect

Insert image description here

summary

About scope slots:
Simple understanding: Scope slots are简化subcomponents passing $emit to parent components< a i=3>Another representation of data Applicable scenarios: It contains at least three levels of component levels, which is an excellent componentization solution! 多层传递

3. Simple application demo

  • The parent component accesses the data of the child component:
    • The parent component obtains the component slot attribute:v-slot="slotProps",
    • Child components bind data into dynamic properties:<slot :item="item"></slot>
  • Display data in the form expected by the parent component:
    • Define slot slot in subcomponent:<slot :item="item" :index="index"></slot>
    • The parent component replaces the slot content of the child component through the slot.
      Insert image description here

4. Multi-layer nesting of slots

1. Demand

There are three components A, B, and C. The content of the slot of component A is passed to component B, and component B is passed to component C.

2. Code demonstration

// src\views\06slot\parent.vue
<template>
  <div>
    <Children1>
      <template v-slot:one>
        <div>根节点信息</div>
      </template>
    </Children1>
  </div>
</template>

// src\views\06slot\children1.vue
<template>
  <div>
    <div>children1</div>
    <Children2>
      <slot name="one" slot="two"></slot>
    </Children2>
  </div>
</template>

// src\views\06slot\children2.vue
<template>
  <div>
    <div>children2</div>
    <slot name="two"></slot>
  </div>
</template>

3. Code effect

Insert image description here

4. Core points

  1. A component usesv-slot:one to pass content to B component
  2. B component uses name="one" to receive the content of the slot, and passes the content to C component through slot="two". That is:<slot name="one" slot="two"></slot>
  3. C component uses<slot name="two"></slot> to receive the content of A component

Guess you like

Origin blog.csdn.net/Litt_White/article/details/128885511