preface

I have searched a lot of explanations about slot-scope on the Internet, but I don’t think they are very specific. I think it is necessary to have a deep understanding of componentization to touch on this issue. Here, I would like to share my own understanding of slot-scope.

  • A slot is a hole in the child component. The parent component decides what to put in the slot.
// child <template> <slot> </slot> </template> // parent <template> <child> <! <span> </span> </child> </template>Copy the code
  1. Pass plain text to the slot

  1. An image processing component is passed to the slot
  • For example, if there are multiple slots, I, as the parent component, want to distinguish between slots in the child component by using the name attribute of the slot tag. The parent component, to decide what to put in what slot, assigns the name value to the slot attribute and passes it to the corresponding slot. If a slot does not have a name attribute, it is an anonymous slot, and the contents of a parent component that does not specify a slot attribute are thrown into an anonymous slot.
// Subcomponent <template> <section> <slot name="article-title"> Here put title </slot> <slot> here put author </slot> <slot name="article-content"> Here put the article content </slot> </section> </template> // parent component <template> <section> <slot-child> <h1 slot="article-title"> < span style = "box-sizing: border-box; color: RGB (74, 74, 74); </h1> <p slot="article-content"Seem to understand > < / p > < div > fifty < / div > < / slot - child > < section > < / template >Copy the code
  • The hardest thing to understand is the scope slot. In the scope slot, the parent component can access the data of the child component. Sub-components can bind attribute values to slot labels, such as:
<slot :nickName="'Tusi'"></slot>
Copy the code

The parent component obtains the nickName value from the slot-scope bound object.

<template>
    <section>
        <slot-child>
            <template slot-scope="scope">
                <div>{{scope.nickName}}</div>
            </template>
        </slot-child>
    </section>
</template>
Copy the code

I think you all have questions here. What’s the use? I am child components with $emit transfer data to the parent component not line?

A little understanding of scoped slots

I think it’s important to think about scope slots in terms of the flow of data between components.

Suppose the first scenario requires you to write a product card component, loop through multiple cards, and ask to jump to the product details page in response to the click event of the picture or other content on each card. What would you write?

I would use the following treatment, first write the item card as a component commodityList.vue, and then use a V-for to display the item card list in commodityList.vue.

<commodity v-for="(item,index) in commodities" @clickCommodity="onCommodityClick"></commodity>
Copy the code

The Commodity component passes the clickCommodity event to the parent component through the $Emit and carries the Commodity data. The parent component can get the data in the onCommodityClick method for business processing, thus completing a basic data transfer from child to parent.

What if I abstracted a little bit more? For example, I have a number of operation columns, such as Taobao home page has “good goods”, “love shopping” such two columns, each column needs to have a commodity card list, then commodity card list CommodityList. Vue will take out components. The vUE component with multiple operation columns I’ll assume is columnList. vue, where the CommodityList component is called with v-for.

Note: Business is coming in and I want to place the business of clicking on a product card in columnList.vue. Can you imagine how to do that? The Commodity component $emit notifies CommodityList.vue when the Commodity button is clicked. CommodityList then throws the event up using the $emit, and columnList. vue handles the click event. This is perfectly fine, but the child component is not pure enough to be relevant to the business.

So how to gracefully solve this problem? This is where the scope slots really come in handy.

Elevate the item card click business onCommodityClick that should be handled by CommodityList to ColumnList through the scope slot.

<el-row :gutter="20">
        <el-col :span="12" v-for="(column, index) in columnList" :key="index">
            <el-card class="box-card card-column">
                <div slot="header" class="clearfix">
                    <span>{{column.columnName}}</span>
                </div>
                <commodity-list :commodities="column.commodityList">
                    <template slot-scope="scope"> <! We just need to pass in data to the Commodity component and respond to the Commodity's clickCommodity event. <commodity :modityData= <commodity :modityData= <commodity :modityData= <commodity :modityData="scope.row" @clickCommodity="onCommodityClick(scope.row)"></commodity>
                    </template>
                </commodity-list>
            </el-card>
        </el-col>
</el-row>
Copy the code

In CommodityList, the slot receives the card component from the parent component, which does not involve the business of the component, but only focuses on other business and layout. The end result is the separation of components and businesses, which is the essence of componentization. Did I help you?

<el-row :gutter="20">
        <el-col :span="8" v-for="(item, index) in commodities" :key="index" style="margin-top:20px;">
            <slot :row="item"></slot>
        </el-col>
</el-row>
Copy the code

Here’s what I’ve done, ignore the style, you know the principle, how hard is it to make a nice card?

In summary, scoped slots are an excellent componentization solution for scenarios that contain at least three levels of component hierarchy!