zoukankan      html  css  js  c++  java
  • Vue3 中插槽(slot)的用法

    概要

    Vue3(其实从2.6开始)中引入了一个新的指令v-slot,用来表示具名插槽和默认插槽

    基础示例

    <!-- default slot -->
    <foo v-slot="{ msg }">
        {{ msg }}
    </foo>
    
    <!-- named slot -->
    <foo>
        <template v-slot:one="{msg}">
            {{ msg }}
        </template> 
    </foo>
    

    为什么要这么做

    在v2.5中介绍了slot-scope,可以直接在插槽元素上使用。

    <foo>
        <div slot-scope="{ msg }">
            {{ msg }}
        </div>
    </foo>
    

    同样的,我们也可以在组件上这样使用。

    <foo>
        <bar slot-scope="{ msg }">
            {{ msg }}
        </bar>
    </foo>
    

    然而,上面的示例会导致一个问题:slot-scope的位置不能清晰的反映出这个作用域变量是哪一个 组件提供的。上面例子中slot-scope是写在<bar>组件上,但是实际上这个作用域变量的定义是有<foo>组件的默认插槽提供的。
    当嵌套的层级越深,情况就会变得越糟。

    <foo>
      <bar slot-scope="foo">
        <baz slot-scope="bar">
          <div slot-scope="baz">
            {{ foo }} {{ bar }} {{ baz }}
          </div>
        </baz>
      </bar>
    </foo>
    

    像上面这种情况,我们无法立即分辨出模板上作用域变量是由那一个组件提供的。

    细节设计

    引入一个新的指令v-slot

    我们可以在slot容器<template>上使用v-slot来表示一个传入组件的插槽,通过指令参数来表示插槽的名称。

    <foo>
        <template v-slot:header>
            <div class="header"></div>
        </template>
        <template v-slot:body>
            <div class="body"></div>
        </template>
        <template v-slot:footer>
            <div class="footer"></div>
        </template>
    </foo>
    

    作用域插槽的内部工作原理是将插槽的内容包裹在一个函数里

        function(slotProps){
            // 插槽内容
        }
    

    这就意味着v-slot的值实际上可以是任何能够作为函数定义中的参数的Javascript表达式,所以在支持的环境下 (单文件组件或现代浏览器),你也可以使用 ES2015 解构来传入具体的插槽 prop,如下:

    <foo>
        <template v-slot:header="{ msg }">
            <div class="header">
                Message from header slot: {{ msg }}
            </div>
        </template>
    </foo>
    

    v-slot可以直接用在组件上,如果没有参数,则表示默认的作用域插槽,传递给默认插槽的属性应该作为变量在其属性值声明。

    <foo v-slot="{ msg }">
        {{ msg }}
    </foo>
    

    新旧语法对比

    • 对于常用的场景(只有一个默认的作用域插槽)

      <foo v-slot="{msg}">{{msg}}</foo>
      
    • 作用域变量与组件之间的联系更加的清晰

      <!-- old -->
      <foo>
        <bar slot-scope="foo">
          <baz slot-scope="bar">
            <div slot-scope="baz">
              {{ foo }} {{ bar }} {{ baz }}
            </div>
          </baz>
        </bar>
      </foo>
      

      使用新语法也可以达到同样的效果

      <foo v-slot="foo">
        <bar v-slot="bar">
          <baz v-slot="baz">
            {{ foo }} {{ bar }} {{ baz }}
          </baz>
        </bar>
      </foo>
      

    注意:组件提供的作用域变量依然声明在当前组件上,新的语法更清晰的展示出组件与作用域变量的关系。(父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的。)

    动态插槽名

    动态指令参数也可以用在 v-slot 上,来定义动态的插槽名:

    <foo>
        <template v-slot:[slotName]>
            ...
        </template>
    </foo>
    

    插槽指令的缩写

    v-bindv-on相似,缩写只有在存在参数时才生效,这就意味着v-slot没有参数时不能使用#=,对于默认插槽,可以使用#default来代替v-slot

    <!-- full syntax -->
    <foo>
      <template v-slot:header="{ msg }">
        Message from header: {{ msg }}
      </template>
    
       <template v-slot:footer>
        A static footer
      </template>
    </foo>
    
    <!-- shorthand -->
    <foo>
      <template #header="{ msg }">
        Message from header: {{ msg }}
      </template>
    
       <template #footer>
        A static footer
      </template>
    </foo>
    
    <foo v-slot="{ msg }">
      {{ msg }}
    </foo>
    
    <foo #default="{ msg }">
      {{ msg }}
    </foo>
    

    更多的用例对比

    默认的文本作用域插槽

    <!-- old -->
    <foo>
        <template slot-scope="{ msg }">
            {{ msg }}
        </template>
    </foo>
    
    <!-- new -->
    <foo v-slot="{ msg }">
        {{ msg }}
    </foo>
    

    默认的含DOM节点的插槽

    <!-- old -->
    <foo>
        <div slot-scope="{msg}">
            {{msg}}
        </div>
    </foo>
    
    <!-- new -->
    <foo v-slot="{msg}">
        <div>
            {{msg}}
        </div>
    </foo>
    

    嵌套的默认插槽

    <!-- old -->
    <foo>
        <bar slot-scope="foo">
            <baz slot-scope="bar"> 
                <template slot-scope="baz">
                    {{ foo }} {{ bar }} {{ baz }}
                </template>
            </baz>
        </bar>
    </foo>
    
    <!-- new -->
    
    <foo v-slot="foo">
        <bar v-slot="bar">
            <baz v-slot="baz">
                {{ foo }} {{ bar }} {{ baz }}
            </baz>
        </bar>
    </foo>
    

    命名插槽

    <!-- old -->
    <foo>
        <template slot="one" slot-scope="{ msg }">
            text slot: {{ msg }}
        </template>
        <div slot="two" slot-scope="{ msg }">
            element slot: {{ msg }}
        </div>
    </foo>
    
    <!-- new -->
    <foo>
        <template v-slot:one="{ msg }">
            text slot:{{msg}}
        </template>
        <template v-slot:two="{msg}">
            <div>
                element slot: {{msg}}
            </div>
        </template>
    </foo>
    

    嵌套 & 命名 / 默认

    <!-- old -->
    <foo>
      <bar slot="one" slot-scope="one">
        <div slot-scope="bar">
          {{ one }} {{ bar }}
        </div>
      </bar>
    
      <bar slot="two" slot-scope="two">
        <div slot-scope="bar">
          {{ two }} {{ bar }}
        </div>
      </bar>
    </foo>
    
    <!-- new -->
    <foo>
      <template v-slot:one="one">
        <bar v-slot="bar">
          <div>{{ one }} {{ bar }}</div>
        </bar>
      </template>
    
      <template v-slot:two="two">
        <bar v-slot="bar">
          <div>{{ two }} {{ bar }}</div>
        </bar>
      </template>
    </foo>
    
  • 相关阅读:
    Linux下的C编程实战之文件系统编程
    IPMSG在ubuntu linux上的安装
    NTP服务器
    [Multimedia][MPEG2]MPEG2系统原理
    BitOperation.cs
    android interview 1
    Android USB Host
    android interview 3
    someone's android note
    Android Afianl框架(1)——FinalActivity注解
  • 原文地址:https://www.cnblogs.com/recode-hyh/p/14544808.html
Copyright © 2011-2022 走看看