vue組件---插槽


(1)插槽內容

    Vue 實現了一套內容分發的 API,這套 API 的設計靈感源自 Web Components 規范草案,將 <slot> 元素作為承載分發內容的出口。

    在父級組件里可以這樣寫

    <div class="slot_area">
        <navigation-link v-bind:url="url">
            Your Profile你的個人簡介資料
        </navigation-link>
    </div>

    然后在 <navigation-link> 組件模板中:

        Vue.component('navigation-link',{
            props:['url'],
            template:`<a v-bind:href="url" class="nav-link">
                        <span class="slot_span"></span>
                        <slot></slot>
                    </a>`
        });

          new Vue({
              el:'.slot_area',
              data:{
                  url:'http://www.baidu.com'
              }
          })

 
        

    當組件渲染的時候,<slot></slot> 將會被替換為“Your Profile你的個人簡介資料”。

    

    插槽內可以包含任何模板代碼,包括 HTML:

        Vue.component('navigation-link',{
            props:['url'],
            template:`<a v-bind:href="url" class="nav-link">
<!-- 添加一個 Font Awesome 圖標 --> <span class="fa fa-user"></span> <slot></slot> </a>` });

    

    插槽也可以是其他組件

    <div class="slot_area">
        <navigation-link v-bind:url="url">
            Your Profile你的個人資料簡介
            <slot-component></slot-component>
        </navigation-link>
    </div>
    
    <script type="text/javascript">
        Vue.component('navigation-link',{
            props:['url'],
            template:`<a v-bind:href="url" class="nav-link">
                        <!-- 添加一個 Font Awesome 圖標 -->
                        <span class="slot_span"></span>
                        <slot></slot>
                    </a>`
        });
        Vue.component('slot-component',{
            template:'<h4>插槽可以是其他模板</h4>'
        })
        new Vue({
            el:'.slot_area',
            data:{
                url:'http://www.baidu.com'
            }
        })
    </script>

    結果:

  

    注意:如果 <navigation-link> 沒有包含一個 <slot> 元素,則該組件起始標簽和結束標簽之間的任何內容都會被拋棄。即如果模板中沒有slot插槽元素,則在父級組件里加的內容都會被拋棄。

(2)編譯作用域

    父組件模板內容是在父組件作用域中編譯的,子組件模板內容是在子組件里編譯的。

    先來個簡單的案例:

<parent-scrop>
{{message}}
</parent-scrop>
Vue.component('parent-scrop',{
    template:`<div>
                子組件模板內容
                <slot></slot>
            </div>`
});
new Vue({
    el:".parent_scrop",
    data:{
        message:"父組件模板內容"
    }
});

    這里的message就是一個slot,但是其綁定的是父組件的數據,而不是子組件模板的數據。

    再來看個案例:

    <div class="parent_scrop">
        <parent-scrop v-show="showStatus"></parent-scrop>
    </div>
    Vue.component('parent-scrop',{
        template:`<div>
                    子組件模板內容
                </div>`
    });
    new Vue({
        el:".parent_scrop",
        data:{
            showStatus:true
        }
    })

   這里的showStatus綁定的是父級組件的數據,如果想在子級組件上綁定,應該是

    <div class="parent_scrop">
        <parent-scrop></parent-scrop>
    </div>
    Vue.component('parent-scrop',{
        template:`<div v-show="showStatus">
                    子組件模板內容
                </div>`,
        data:function(){
            return {
                showStatus:false
            }
        }
    });
    new Vue({
        el:".parent_scrop"
    })

結果:

   

    因此,slot分發的內容,作用域是在父組件上的。

(3)slot用法

    ①單個slot

    在子組件內使用特殊的<slot>元素就可以為這個子組件開啟一個slot(插槽),在父組件模板里,插入在父組件標簽內的所有內容都將替代子組件的<slot>標簽及它的內容。

    demo1:

    <div class="single_slot">
        <single-slot></single-slot>
    </div>
        Vue.component('single-slot',{
            template:`
                    <div>
                        <slot>
                            <p>如果父組件沒有插入內容,將會作為默認值出現</p>
                        </slot>
                    </div>
            `
        });
        new Vue({
            el:".single_slot"
        })

    結果:

   

    demo2:父組件插入內容

    <div class="single_slot">
        <single-slot>
            <p>父組件插入內容</p>
            <p>分發更多內容</p>
        </single-slot>
    </div>
        Vue.component('single-slot',{
            template:`
                    <div>
                        <slot>
                            <p>如果父組件沒有插入內容,將會作為默認值出現</p>
                        </slot>
                    </div>
            `
        });
        new Vue({
            el:".single_slot"
        })

結果:

    

 (4)后備內容/備用內容

    結合上例,<single-slot>模板里定義了<slot>元素,並用了<p>作為默認內容。在父組件沒有使用slot即未插入內容時,會渲染這段默認文本;如果寫入了slot,那么就會替換整個<slot>。

    注意:子組件<slot>中的后備內容,其作用域是子組件本身。

(5)具名插槽

    給<slot>元素指定一個name后,可以分發多個內容,具名插槽可以與單個插槽共存。

    用法簡單demo1:

父級組件里:
<solt-area>
    <h2 slot="header">標題</h2>
    <p slot="footer">底部</p>
</slot-area>

子級模板里:
Vue.component('slot-area',{
    template:`
            <div class="main_area">
                    <div class="header"><slot name="header"></slot></div>
                    <div class="footer"><slot name="footer"></slot></div>
            </div>
          `
})

    demo2:

    <!-- 具名slot -->
    <div class="slot_name">
        <slot-name>
            <h2 slot="header">文章標題</h2>
            <p>內容展示區域1,文章具體內容1... ...</p>
            <p>內容展示區域2,文章具體內容2... ...</p>
            <p slot="footer">作者:Tony 發布日期:2020.6.8</p>
        </slot-name>
    </div>
    <style type="text/css">
        .main_area{
            padding: 20px;
            background-color: rgba(0,0,0,0.1);
        }
        .main_area h2{
            margin: 10px 0;
            text-align: center;
        }
        .main_area .footer{
            text-align: right;
            font-weight: 600;
            margin: 10px 0;
        }
        .main_area .main{
            padding: 10px;
            background-color: rgba(0,0,0,.1);
        }
    </style>
        /* 3、具名slot */
        Vue.component('slot-name',{
            template:`
                <div class="main_area">
                    <div class="header"><slot name="header"></slot></div>
                    <div class="main"><slot></slot></div>
                    <div class="footer"><slot name="footer"></slot></div>
                </div>
            `
        })
        new Vue({
            el:".slot_name"
        })

結果:

        

    子組件里聲明了3個<slot>元素,其中在<div class="main"></div>內的slot沒有使用name特性,所以他將作為默認slot出現,父組件里沒有使用slot特性的元素與內容都將出現在這里。

    如果沒有指定默認的匿名slot,父組件里多余的內容片段都將會被拋棄。在組合使用組件時,內容分發API至關重要。

    注意:自2.6.0開始有所跟新,將原先的slot方法更新為v-slot 指令即

    <div class="slot_name">
        <slot-name>
            <template v-slot:header> <h2>文章標題</h2> </template> <template v-slot:default> <p>內容展示區域1,文章具體內容1... ...</p> <p>內容展示區域2,文章具體內容2... ...</p> </template> <template v-slot:footer> <p>作者:Tony 發布日期:2020.6.8</p> </template>
        </slot-name>
    </div>

    現在 <template> 元素中的所有內容都將會被傳入相應的插槽。任何沒有被包裹在帶有 v-slot 的 <template> 中的內容都會被視為默認插槽的內容。然而,如果你希望更明確一些,仍然可以在一個 <template> 中包裹默認插槽的內容,如上所示v-slot:default。

(6)作用域插槽

    正常情況下,父級組件的插槽內容無法訪問子級模板中的數據,例如

    <div class="scrop_slot">
        <scrop-slot>
            姓:{{user.firstName}},名:{{user.lastName}}
        </scrop-slot>
    </div>
        /* 4、作用域插槽 */
        Vue.component('scrop-slot',{
            template:`
                    <div class="show_area">
                        <slot>
                            <p>姓:{{user.firstName}},名:{{user.lastName}}</p>
                        </slot>
                    </div>
                    `,
            data:function(){
                return {
                    user:{firstName:"",lastName:""}
                };
            }
        })
        new Vue({
            el:".scrop_slot"
        })
        /* 4、作用域插槽 */

    此時,控制台會出現報錯提示

   

    為了讓 user 在父級的插槽內容可用,我們可以將 user 作為一個 <slot> 元素的特性綁定上去:

<slot v-bind:user="user">
        <p>姓:{{user.firstName}},名:{{user.lastName}}</p>
</slot>

    綁定在 <slot> 元素上的特性被稱為插槽 prop。現在在父級作用域中,我們可以給 v-slot 帶一個值來定義我們提供的插槽 prop 的名字:

    <div class="scrop_slot">
        <scrop-slot v-slot:default="slotDefault">
            <template>
                姓:{{slotDefault.user.firstName}},名:{{slotDefault.user.lastName}}
            </template>
        </scrop-slot>
    </div>

    在這個例子中,選擇將包含所有插槽 prop 的對象命名為 slotProps,也可以使用任意你喜歡的名字。

(7)獨占默認插槽的縮寫語法

    <div class="scrop_slot">
        <scrop-slot v-slot:default="slotDefault">
            <template>
                姓:{{slotDefault.user.firstName}},名:{{slotDefault.user.lastName}}
            </template>
        </scrop-slot>
    </div>

   在上述情況下,當被提供的內容只有默認插槽時,組件的標簽才可以被當作插槽的模板來使用。這樣我們就可以把 v-slot 直接用在組件上:

    <div class="scrop_slot">
        <scrop-slot v-slot:default="slotDefault">
            姓:{{slotDefault.user.firstName}},名:{{slotDefault.user.lastName}}
        </scrop-slot>
    </div>

    這種寫法還可以更簡單。就像假定未指明的內容對應默認插槽一樣,不帶參數但 v-slot 被假定對應默認插槽:

    <div class="scrop_slot">
        <scrop-slot v-slot="slotDefault">
            姓:{{slotDefault.user.firstName}},名:{{slotDefault.user.lastName}}
        </scrop-slot>
    </div>

    注意:注意默認插槽的縮寫語法不能和具名插槽混用,因為它會導致作用域不明確。如下所示

<scrop-slot v-slot="slotDefault">
     姓:{{slotDefault.user.firstName}}
     <template v-slot:other="otherSlot">
          名:{{slotDefault.user.lastName}}
     </template>
</scrop-slot>

此時,控制台出現報錯:譯為---為避免范圍模糊,當存在其他命名槽時,默認槽也應使用<template>語法。

<scrop-slot>
    <template v-slot:datault="slotDefault">
        姓:{{slotDefault.user.firstName}}
    </template>
    <template v-slot:other="otherSlot">
        名:{{otherSlot.user.lastName}}
    </template>
</scrop-slot>

    只要出現多個插槽,請始終為所有的插槽使用完整的基於 <template> 的語法。

(8)解構插槽Prop

    可以使用 ES2015 解構來傳入具體的插槽 prop,如下:

    <div class="scrop_slot">
        <scrop-slot v-slot="{user}"> {{user.firstName}} </scrop-slot>
    </div>
        Vue.component('scrop-slot',{
            template:`
                    <div class="show_area">
                        <slot v-bind:user="user">
                            <p>姓:{{user.firstName}},名:{{user.lastName}}</p>
                        </slot>
                    </div>
                    `,
            data:function(){
                return {
                    user:{firstName:"",lastName:""}
                };
            }
        })
        new Vue({
            el:".scrop_slot"
        })

    這樣可以使模板更簡潔,尤其是在該插槽提供了多個 prop 的時候。它同樣開啟了 prop 重命名等其它可能,例如將 user 重命名為 person

<scrop-slot v-slot="{user:person}">
    {{person.firstName}}
</scrop-slot>

 (9)動態插槽名(待驗證

(10)具名插槽縮寫

    跟 v-on 和 v-bind 一樣,v-slot 也有縮寫,即把參數之前的所有內容 (v-slot:) 替換為字符 #。例如 v-slot:header 可以被重寫為 #header

    <div class="slot_name">
        <slot-name>
            <template #header>
                <h2>文章標題</h2>
            </template>
            <template #default>
                <p>內容展示區域1,文章具體內容1... ...</p>
                <p>內容展示區域2,文章具體內容2... ...</p>
            </template>
            <template #footer>
                <p>作者:Tony 發布日期:2020.6.8</p>
            </template>
        </slot-name>
    </div>

 

 

 

 

 

 

.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM