首頁  >  文章  >  web前端  >  深入理解Vue中的插槽、內容分發、具名插槽

深入理解Vue中的插槽、內容分發、具名插槽

青灯夜游
青灯夜游轉載
2022-10-12 19:43:322024瀏覽

這篇文章跟大家分享Vue進階技巧,深入理解下Vue中的插槽、內容分發、具名插槽,希望對大家有幫助。

深入理解Vue中的插槽、內容分發、具名插槽

插槽Slots簡介

#Vue中元件的資料可以透過props傳遞,或透過事件的方式進行獲取傳遞,但當需要接收模板內容(任意合法的模板內容,程式碼片段、Vue元件)時,就需要使用插槽來實現了。當然也可以透過函數式程式設計間接實現;【相關推薦:vuejs影片教學

深入理解Vue中的插槽、內容分發、具名插槽

  • 可以將插槽理解為js中的函數進行編譯
// 父元素传入插槽内容
FancyButton('Click me!')

// FancyButton 在自己的模板中渲染插槽内容
function FancyButton(slotContent) {
    return `<button>
      ${slotContent}
    </button>`
}
  • 最好的封裝方式是將共性抽取到元件中,將不同點暴露為插槽- 抽取共性,保留不同
  • 父元件模板的所有東西都會在父元件作用域中編譯,子元件模板的所有東西都會在子元件作用域內編譯- 編譯作用域

slot-scope析

常規的slot可以用於自訂元件的模板,但只是限制於固定的模板,無法自訂內部的具體的某一項,即常規的slot無法實現對組件循環體的每一項進行不同的內容分發,此時可以透過slot-scope進行實現,本質上和slot一樣,不同點在於可以進行參數傳遞

//普通的组件定义
        
  •     {{ book.name }}     
//slot-scope组件定义
        
  •                                   {{ book.name }}              
//父组件使用     

使用slot-scope時,當父元件使用該API,對應的插槽會取代模板中的slot進行展示

常用API淺析

具名插槽

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

深入理解Vue中的插槽、內容分發、具名插槽

  • v-slot 可以簡寫為##,其值對應於插槽中的 name對應的值;
  • 當在一個元件中同時存在預設插槽和具名插槽時,所有位於頂層的非template節點都被隱式的視為預設插槽的內容,因此可以省略預設插槽的template節點標籤;
<com>
    <!-- 隐式的默认插槽 -->
    <!-- <p>A paragraph for the main content.</p>
    <p>And another one.</p> -->
    <template>
        <p>A paragraph for the main content.</p>
        <p>And another one.</p>
    </template>
    <template>
        <p>Here's some contact info</p>
    </template>
</com>
##作用域插槽
普通的插槽,是無法取得其他作用域下的資料的,即

父元件範本中的表達式只能存取父元件的作用域;子元件範本中的表達式只能存取子元件元件的作用域但在某些情況下,插槽中的內容想要同時使用父元件和子元件內的數據,可以透過像元件傳遞資料
props那樣,讓子元件在渲染時將一​​部分資料提供給插槽,這樣在元件外部(父元件)中就可以使用子元件中的資料了-透過slot的方式

#子元件傳入插槽的props 作為了 v-slot 指令的值,可以在插槽內的表達式中訪問,其中name是Vue刻意保留的attribute,不會作為props進行傳遞

    資料傳遞
//子组件
<template> 
    <slot></slot> 
</template>
    #資料接收
    • 預設插槽接收
    //父组件 - 使用方
    <mycom>
      {{ shopInfo }} {{ userInfo }}
    </mycom>
    具名插槽接收
<mycom>
  <template>
    {{ shopInfo }}
  </template>

  <template>
    {{ introduction }}
  </template>

  <template>
    {{ userInfo }}
  </template>
</mycom>
使用slot-scope時,用最後一個slot-scope取代模板中的slot
  • <cpm>
        <!-- 不显示 -->
        <div>555</div>
        <!-- 不显示 -->
        <div>
            <div>{{scope.name}}</div>
        </div>
        <!-- 显示 -->
        <div>
            <div>{{scope}}</div>
            <div>{{scope.name}}</div>
            <div>{{scope.age}}</div>
        </div>
    </cpm>
      #使用作用域插槽時,可以實現既可以重複使用子元件slot,又可以使得slot的內容不一致,它允許使用者傳遞一個模板而不是已經渲染好的元素給插槽,所謂作用域是指模板雖然在父級作用域中渲染的,但是卻可以拿到子組件的資料
    • 常規的v-bind需要攜帶參數key值進行傳遞,例如
    • v-bind:info = '123 ';但有時會省略這個key值,直接進行傳遞數據,如v-bind = 'item',這種用法會將整個物件的所有屬性都綁定到當前元素上,適用於需要綁定的屬性過多的場景
    // 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>
        <template>
            <div>{{ shape.name }} <small>({{ shape.sides }} sides)</small>
    </div>
        </template>
    </my-list>
    <my-list>
        <template>
            <div>
                <div></div>
                {{ color.name }}
            </div>
        </template>
    </my-list>
    <div>
        <div>{{ title }}</div>
        <div>
            <div>
                <slot></slot>
            </div>
        </div>
    </div>
    
    
    Vue.component('my-list', {
        template: '#my-list',
        props: [ 'title', 'items' ]
    });
    遞歸元件
    遞歸元件就是指元件在模板中呼叫自己,由於是組件自身調用,就不能像常規組件定義一樣,可以省略組件的name配置,組件的遞歸需要依賴於自身的name配置(name還用於遍歷組件的name選項來查找組件的實例);

    • 满足条件
      • 需要给组件设置一个name属性
      • 需要有一个明确的结束条件
    <template>
        <div>
            <my-component></my-component>
        </div>
    </template>
    <script>
    export default {
        name:&#39;my-component&#39;,
        props: {
            count: {
                type: Number,
                default: 1
            }
        }
    }
    </script>
    动态组件

    有时候我们需要根据一些条件,动态的切换/选择某个组件,在函数式组件中,没有上下文的概念,常用于程序化的在多个组件中选择一个,可以间接的解决动态切换组件的需求,缺点是基于js对象进行开发,不方便开发;
    Vue官方提供了一个内置组件<component></component>和is的属性,用来解决上述的问题

    <component></component>
    //component 就是js import进的组件实例,其值可以是标签名、组件名、直接绑定一个对象等
    • 为了使得组件具有缓存作用,可以使用的内置组件,这样只要不离开当前页面,切换到其他组件后deforeDestory不会执行,因此组件具有了缓存功能

    拓展

    components的第二种写法

    常规的组件components是直接通过引用定义好的组件进行展示的,也可以直接在当前组件内定义,然后通过配置components进行渲染

    <div>
        <cpn></cpn>
    </div>
    <template>
        <div>
            <h2>Lbxin</h2>
            <p>class - 11</p>
        </div>
    </template>
    <script>
    var app = new Vue({
        el: &#39;#app&#39;,
        data: {
            isShow: true
        },
        components: {
            cpn: {
                template: &#39;#com&#39;,
                data() {
                    isShow: false
                }
            }
        }
    })
    </script>

    Web Component <slot></slot> 简介

    HTML的slot元素,是Web Components技术套件的一部分,是Web组件内的一个占位符,该占位符可以在后期使用自己的标记语言进行填充,这样可以创建单独的DOM树,并将其与其他的组件组合在一起 -- MDN

    常见的填充Web组件的shadow DOM的模板有template和slot

    • 模板 - Templates

      • 需要在网页上重复的使用相同的标记结构时,为了避免CV的操作可以通过模板的方式进行实现
      • 需要注意的是模板 - Template 和其内部的内容是不会在DOM中呈现的,可以通过js进行访问并添加到DOM中,从而在界面上进行展示
      <template>
        <p>My paragraph</p>
      </template>
      let template = document.getElementById('my-paragraph');
      let templateContent = template.content;
      document.body.appendChild(templateContent);
      • 可以配合Web Component一起使用,实现纯js自定义的组件
      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));
        }
      })
      
      // 自定义标签使用
      <my-paragraph></my-paragraph>
      • 后续的样式逻辑也需要加在template中,方便通过后续的相关逻辑(如template.content获取到然后打入到指定的容器中)
    • Web Component简介

      • Web Component的一个很重要的属性就是封装 - 可以将标记结构、样式和行为影藏起来,并于界面上的其他代码隔离开来,保证代码的独立性

      • Web Component标准非常重要的一个特性是,使得开发者可以将HTML页面的功能封住成custom elements(自定义标签)

      • customElements 接口用来实现一个对象,允许开发者注册一个custom elements的信息,返回已注册的自定义标签的信息;

      • customElements.define方法用来注册一个custom element,接收三个参数

        • 参数一:表明创建元素的名称,其注册的名称不能简单的单词,需要由短划线进行拼接

        • 参数二:用于定义元素行为的类

        • 参数三:一个包含extends属性配置的配置对象,可选,指定了所创建的自定义元素是继承于哪个内置的元素,可以继承任何内置的元素;

          customElements.define(
              'word-count', 
              WordCount, 
              { extends: 'p' }
          );

          可以使用ES2015的类实现

          class WordCount extends HTMLParagraphElement {
            constructor() {
              // 必须首先调用 super 方法
              super();
              // 元素的功能代码写在这里
              ...
            }
          }
      • 自定义标签的类型

        • 类型一:Autonomous custom elements 是独立的元素,它不继承其他内建的 HTML 元素,可以直接通过标签的方式进行HTML使用<popup-info></popup-info>,也可以通过js的方式进行使用document.createElement("popup-info")
        • 类型二:Customized built-in elements 继承自基本的 HTML 元素。在创建时,你必须指定所需扩展的元素,使用时,需要先写出基本的元素标签,并通过 is属性指定 custom element 的名称;<p is="word-count"></p>document.createElement("p", { is: "word-count" })

        参考文献 - MDN

    • shadow DOM简介

      • 图解Shandow DOM

      深入理解Vue中的插槽、內容分發、具名插槽

      • Shadow host:一个常规 DOM 节点,Shadow DOM 会被附加到这个节点上。

      • Shadow tree:Shadow DOM 内部的 DOM 树。

      • Shadow boundary:Shadow DOM 结束的地方,也是常规 DOM 开始的地方。

      • Shadow root: Shadow tree 的根节点。

      shadow DOM主要是将一个隐藏的、独立的DOM树附加到常规的DOM树上,是以shadow DOM节点为起始根节点,在这个根节点的下方,可以是任意的元素,和普通的DOM元素一致

    如常见的video标签,其内部的一些控制器和按钮等都是通过Shandow DOM进行维护的,开发者可以通过这个API进行自己独立的逻辑控制

    • 基本用法

      • Element.attachShadow()方法可以将一个shadow DOM添加到任何一个元素上,接收一个配置对象参数,该对象有一个mode的属性,值可以是open - 可以通过外部js获取 Shadow DOM和closed - 外部不可以通过js进行获取 Shadow DOM
      let shadow1 = elementRef.attachShadow({mode: 'open'});
      let shadow2 = elementRef.attachShadow({mode: 'closed'});
      let myShadowDom = shadow1.shadowRoot; // 具体内容
      let myShadowDom = shadow2.shadowRoot; //null
      • 当需要将一个shadow DOM添加到自定义的标签上时,可以在自定义的构造函数中添加如下逻辑;
      let shadow = this.attachShadow({mode: 'open'});
      // 将一个shadow DOM添加到一个元素上之后就可以使用DOM API进行操作访问了

    (学习视频分享:web前端开发编程基础视频

    以上是深入理解Vue中的插槽、內容分發、具名插槽的詳細內容。更多資訊請關注PHP中文網其他相關文章!

  • 陳述:
    本文轉載於:juejin.cn。如有侵權,請聯絡admin@php.cn刪除