溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Vue中的插槽、內(nèi)容分發(fā)、具名插槽應(yīng)用實例分析

發(fā)布時間:2022-10-13 09:11:14 來源:億速云 閱讀:130 作者:iii 欄目:編程語言

今天小編給大家分享一下Vue中的插槽、內(nèi)容分發(fā)、具名插槽應(yīng)用實例分析的相關(guān)知識點,內(nèi)容詳細(xì),邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。

插槽 Slots簡介

Vue中組件的數(shù)據(jù)可以通過props進(jìn)行傳遞,或者通過事件的方式進(jìn)行獲取傳遞,但當(dāng)需要接收模板內(nèi)容(任意合法的模板內(nèi)容,代碼片段、Vue組件)時,就需要使用插槽來實現(xiàn)了。當(dāng)然也可以通過函數(shù)式編程間接實現(xiàn)。

Vue中的插槽、內(nèi)容分發(fā)、具名插槽應(yīng)用實例分析

  • 可以將插槽理解為js中的函數(shù)進(jìn)行編譯

// 父元素傳入插槽內(nèi)容
FancyButton('Click me!')

// FancyButton 在自己的模板中渲染插槽內(nèi)容
function FancyButton(slotContent) {
    return `<button class="fancy-btn">
      ${slotContent}
    </button>`
}

  • 最好的封裝方式是將共性抽取到組件中,將不同點暴露為插槽 - 抽取共性,保留不同

  • 父組件模板的所有東西都會在父組件作用域中編譯,子組件模板的所有東西都會在子組件作用域內(nèi)編譯 - 編譯作用域

slot-scope淺析

常規(guī)的slot可以用于自定義組件的模板,但只是限制于固定的模板,無法自定義內(nèi)部的具體的某一項,即常規(guī)的slot無法實現(xiàn)對組件循環(huán)體的每一項進(jìn)行不同的內(nèi)容分發(fā),此時可以通過slot-scope進(jìn)行實現(xiàn),本質(zhì)上和slot一樣,不同點在于可以進(jìn)行參數(shù)傳遞

//普通的組件定義
<ul>
    <li v-for="book in books" :key="book.id">
    {{ book.name }}
    </li>
</ul>


//slot-scope組件定義
<ul>
    <li v-for="book in books" :key="book.id">
        <slot :book="book" name="bookInfo">
            <!-- 默認(rèn)內(nèi)容 -->
            {{ book.name }}
        </slot>
    </li>
</ul>

//父組件使用
<book-list :books="books">
    <template slot-scope="slotProps" slot="bookInfo">
        <span v-if="slotProps.book.sale">限時優(yōu)惠</span>
        {{ slotProps.book.name }}
    </template>
</book-list>

使用slot-scope時,當(dāng)父組件使用該API,對應(yīng)的插槽會替換模板中的slot進(jìn)行展示

常用API淺析
具名插槽

在組件中定義多個插槽出口可以兼容多個不同需求的兼容性,使得多個插槽內(nèi)容傳入到各自的插槽出口中;當(dāng)插槽中配置了name屬性時,此插槽就被稱為具名插槽(named slots),沒有提供name的插槽會隱式命名為「default」

Vue中的插槽、內(nèi)容分發(fā)、具名插槽應(yīng)用實例分析

  • v-slot 可以簡寫為#,其值對應(yīng)于插槽中的name對應(yīng)的值;

  • 當(dāng)在一個組件中同時存在默認(rèn)插槽和具名插槽時,所有位于頂級的非template節(jié)點都被隱式的視為默認(rèn)插槽的內(nèi)容,因此可以省略默認(rèn)插槽的template節(jié)點標(biāo)簽;

<Com>
    <!-- 隱式的默認(rèn)插槽 -->
    <!-- <p>A paragraph for the main content.</p>
    <p>And another one.</p> -->
    <template #default>
        <p>A paragraph for the main content.</p>
        <p>And another one.</p>
    </template>
    <template #footer>
        <p>Here's some contact info</p>
    </template>
</Com>

作用域插槽

普通的插槽,是無法獲取其他作用域下的數(shù)據(jù)的,即父組件模板中的表達(dá)式只能訪問父組件的作用域;子組件模板中的表達(dá)式只能訪問子組件的作用域
但在某些情況下,插槽中的內(nèi)容想要同時使用父組件和子組件內(nèi)的數(shù)據(jù),可以通過像組件傳遞數(shù)據(jù)props那樣,讓子組件在渲染時將一部分?jǐn)?shù)據(jù)提供給插槽,這樣在組件外部(父組件)中就可以使用子組件中的數(shù)據(jù)了-通過slot的方式

子組件傳入插槽的 props 作為了 v-slot 指令的值,可以在插槽內(nèi)的表達(dá)式中訪問,其中name是Vue特意保留的attribute,不會作為props進(jìn)行傳遞

  • 數(shù)據(jù)傳遞

//子組件
<template> 
    <slot :shopInfo="shopInfo" :userInfo="userInfo"></slot> 
</template>

  • 數(shù)據(jù)接收

    //父組件 - 使用方
    <MyCom v-slot="{shopInfo,userInfo}">
     {{ shopInfo }} {{ userInfo }}
    </MyCom>
  • <MyCom>
      <template v-slot:header="shopInfo">
        {{ shopInfo }}
      </template>

      <template #default="introduction">
        {{ introduction }}
      </template>

      <template #footer="userInfo">
        {{ userInfo }}
      </template>
    </MyCom>
    • 具名插槽接收

    • 默認(rèn)插槽接收

  • 使用slot-scope時,用最后一個slot-scope替換模板中的slot

<cpm>
    <!-- 不顯示 -->
    <div>555</div>
    <!-- 不顯示 -->
    <div slot-scope="scope">
        <div>{{scope.name}}</div>
    </div>
    <!-- 顯示 -->
    <div slot-scope="scope">
        <div>{{scope}}</div>
        <div>{{scope.name}}</div>
        <div>{{scope.age}}</div>
    </div>
</cpm>

  • 使用作用域插槽時,可以實現(xiàn)既可以復(fù)用子組件slot,又可以使得slot的內(nèi)容不一致,它允許使用者傳遞一個模板而不是已經(jīng)渲染好的元素給插槽,所謂作用域是指模板雖然在父級作用域中渲染的,但是卻可以拿到子組件的數(shù)據(jù)

  • 常規(guī)的v-bind需要攜帶參數(shù)key值進(jìn)行傳遞,例如v-bind:info = '123';但是有時候會省略這個key值,直接進(jìn)行傳遞數(shù)據(jù),如v-bind = 'item',這種用法會將整個對象的所有屬性都綁定到當(dāng)前元素上,適用于需要綁定的屬性過多的場景

// data: {
//     shapes: [
//         { name: 'Square', sides: 4 },
//         { name: 'Hexagon', sides: 6 },
//         { name: 'Triangle', sides: 3 }
//     ],
//     colors: [
//         { name: 'Yellow', hex: '#F4D03F', },
//         { name: 'Green', hex: '#229954' },
//         { name: 'Purple', hex: '#9B59B6' }
//     ]
// }
<my-list title="Shapes" :items="shapes">
    <template scope="shape">
        <div>{{ shape.name }} <small>({{ shape.sides }} sides)</small></div>
    </template>
</my-list>
<my-list title="Colors" :items="colors">
    <template scope="color">
        <div>
            <div class="swatch" :style="{ background: color.hex }"></div>
            {{ color.name }}
        </div>
    </template>
</my-list>
<div id="my-list">
    <div class="title">{{ title }}</div>
    <div class="list">
        <div v-for="scope in items">
            <slot v-bind="scope"></slot>
        </div>
    </div>
</div>


Vue.component('my-list', {
    template: '#my-list',
    props: [ 'title', 'items' ]
});

遞歸組件

遞歸組件就是指組件在模板中調(diào)用自己,由于是組件自身調(diào)用,就不能像常規(guī)組件定義一樣,可以省略組件的name配置,組件的遞歸需要依賴于自身的name配置(name還用于遍歷組件的name選項來查找組件的實例);

  • 滿足條件

    • 需要給組件設(shè)置一個name屬性

    • 需要有一個明確的結(jié)束條件

<template>
    <div>
        <my-component :count="count + 1" v-if="count
        <= 5"></my-component>
    </div>
</template>
<script>
export default {
    name:'my-component',
    props: {
        count: {
            type: Number,
            default: 1
        }
    }
}
</script>

動態(tài)組件

有時候我們需要根據(jù)一些條件,動態(tài)的切換/選擇某個組件,在函數(shù)式組件中,沒有上下文的概念,常用于程序化的在多個組件中選擇一個,可以間接的解決動態(tài)切換組件的需求,缺點是基于js對象進(jìn)行開發(fā),不方便開發(fā);
Vue官方提供了一個內(nèi)置組件<component>和is的屬性,用來解決上述的問題

<component :is="component"></component>
//component 就是js import進(jìn)的組件實例,其值可以是標(biāo)簽名、組件名、直接綁定一個對象等

為了使得組件具有緩存作用,可以使用的內(nèi)置組件,這樣只要不離開當(dāng)前頁面,切換到其他組件后deforeDestory不會執(zhí)行,因此組件具有了緩存功能

拓展

components的第二種寫法

常規(guī)的組件components是直接通過引用定義好的組件進(jìn)行展示的,也可以直接在當(dāng)前組件內(nèi)定義,然后通過配置components進(jìn)行渲染

<div id="app">
    <cpn v-show="isShow"></cpn>
</div>
<template id="com">
    <div>
        <h3>Lbxin</h3>
        <p>class - 11</p>
    </div>
</template>
<script>
var app = new Vue({
    el: '#app',
    data: {
        isShow: true
    },
    components: {
        cpn: {
            template: '#com',
            data() {
                isShow: false
            }
        }
    }
})
</script>

Web Component <slot> 簡介

HTML的slot元素,是Web Components技術(shù)套件的一部分,是Web組件內(nèi)的一個占位符,該占位符可以在后期使用自己的標(biāo)記語言進(jìn)行填充,這樣可以創(chuàng)建單獨的DOM樹,并將其與其他的組件組合在一起 -- MDN

常見的填充Web組件的shadow DOM的模板有template和slot

  • 模板 - Templates

  • <template id="my-paragraph">
     <p>My paragraph</p>
    </template>
  • let template = document.getElementById('my-paragraph');
    let templateContent = template.content;
    document.body.appendChild(templateContent);
  • customElements.define('my-paragraph',
      class extends HTMLElement {
        constructor() {
          super();
          let template = document.getElementById('my-paragraph');
          let templateContent = template.content;

          const shadowRoot = this.attachShadow({mode: 'open'})
            .appendChild(templateContent.cloneNode(true));
      }
    })

    // 自定義標(biāo)簽使用
    <my-paragraph></my-paragraph>
    • 后續(xù)的樣式邏輯也需要加在template中,方便通過后續(xù)的相關(guān)邏輯(如template.content獲取到然后打入到指定的容器中)

    • 可以配合Web Component一起使用,實現(xiàn)純js自定義的組件

    • 需要在網(wǎng)頁上重復(fù)的使用相同的標(biāo)記結(jié)構(gòu)時,為了避免CV的操作可以通過模板的方式進(jìn)行實現(xiàn)

    • 需要注意的是模板 - Template 和其內(nèi)部的內(nèi)容是不會在DOM中呈現(xiàn)的,可以通過js進(jìn)行訪問并添加到DOM中,從而在界面上進(jìn)行展示

  • Web Component簡介

    • 類型一:Autonomous custom elements 是獨立的元素,它不繼承其他內(nèi)建的 HTML 元素,可以直接通過標(biāo)簽的方式進(jìn)行HTML使用<popup-info>,也可以通過js的方式進(jìn)行使用document.createElement("popup-info")

    • 類型二:Customized built-in elements 繼承自基本的 HTML 元素。在創(chuàng)建時,你必須指定所需擴(kuò)展的元素,使用時,需要先寫出基本的元素標(biāo)簽,并通過 is屬性指定 custom element 的名稱;<p is="word-count">document.createElement("p", { is: "word-count" })

    • 參數(shù)一:表明創(chuàng)建元素的名稱,其注冊的名稱不能簡單的單詞,需要由短劃線進(jìn)行拼接

    • 參數(shù)二:用于定義元素行為的類

    • 參數(shù)三:一個包含extends屬性配置的配置對象,可選,指定了所創(chuàng)建的自定義元素是繼承于哪個內(nèi)置的元素,可以繼承任何內(nèi)置的元素;

    • customElements.define(
         'word-count',
         WordCount,
         { extends: 'p' }
      );
    • 可以使用ES2015的類實現(xiàn)

    • class WordCount extends HTMLParagraphElement {
       constructor() {
         // 必須首先調(diào)用 super 方法
         super();
         // 元素的功能代碼寫在這里
         ...
       }
      }
    • Web Component的一個很重要的屬性就是封裝 - 可以將標(biāo)記結(jié)構(gòu)、樣式和行為影藏起來,并于界面上的其他代碼隔離開來,保證代碼的獨立性

    • Web Component標(biāo)準(zhǔn)非常重要的一個特性是,使得開發(fā)者可以將HTML頁面的功能封住成custom elements(自定義標(biāo)簽)

    • customElements 接口用來實現(xiàn)一個對象,允許開發(fā)者注冊一個custom elements的信息,返回已注冊的自定義標(biāo)簽的信息;

    • customElements.define方法用來注冊一個custom element,接收三個參數(shù)

    • 自定義標(biāo)簽的類型

      參考文獻(xiàn) - MDN

  • shadow DOM簡介

    Vue中的插槽、內(nèi)容分發(fā)、具名插槽應(yīng)用實例分析

    shadow DOM主要是將一個隱藏的、獨立的DOM樹附加到常規(guī)的DOM樹上,是以shadow DOM節(jié)點為起始根節(jié)點,在這個根節(jié)點的下方,可以是任意的元素,和普通的DOM元素一致

    • Shadow host:一個常規(guī) DOM 節(jié)點,Shadow DOM 會被附加到這個節(jié)點上。

    • Shadow tree:Shadow DOM 內(nèi)部的 DOM 樹。

    • Shadow boundary:Shadow DOM 結(jié)束的地方,也是常規(guī) DOM 開始的地方。

    • Shadow root: Shadow tree 的根節(jié)點。

    • 圖解Shandow DOM

如常見的video標(biāo)簽,其內(nèi)部的一些控制器和按鈕等都是通過Shandow DOM進(jìn)行維護(hù)的,開發(fā)者可以通過這個API進(jìn)行自己獨立的邏輯控制

  • 基本用法

  • let shadow1 = elementRef.attachShadow({mode: 'open'});
    let shadow2 = elementRef.attachShadow({mode: 'closed'});
    let myShadowDom = shadow1.shadowRoot; // 具體內(nèi)容
    let myShadowDom = shadow2.shadowRoot; //null
  • let shadow = this.attachShadow({mode: 'open'});
    // 將一個shadow DOM添加到一個元素上之后就可以使用DOM API進(jìn)行操作訪問了
    • 當(dāng)需要將一個shadow DOM添加到自定義的標(biāo)簽上時,可以在自定義的構(gòu)造函數(shù)中添加如下邏輯;

    • Element.attachShadow()方法可以將一個shadow DOM添加到任何一個元素上,接收一個配置對象參數(shù),該對象有一個mode的屬性,值可以是open - 可以通過外部js獲取 Shadow DOM和closed - 外部不可以通過js進(jìn)行獲取 Shadow DOM

以上就是“Vue中的插槽、內(nèi)容分發(fā)、具名插槽應(yīng)用實例分析”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學(xué)習(xí)更多的知識,請關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

vue
AI