Vue 的作用域插槽是个难点(共计10例)

一段时间不用,很快就忘光了。为方便自己快速回忆,特此记上一笔。

先回忆带槽组件的使用方法

例1、过时的写法
假设有一个 base-layout 组件,它带有一个 header 插槽。我们可以像下面这样使用这个组件

<base-layout>
  <template slot="header">
    <h1>Here might be a page title</h1>
  </template>
</base-layout>

例2、啰里啰唆的写法
注意,上述slot="header"的写法已被废弃,可以改用如下v-slot:header的写法

<base-layout>
  <template v-slot:header>
    <h1>Here might be a page title</h1>
  </template>
</base-layout>

例3、使用井号(推荐写法)
如果觉得这样写很麻烦,可以使用如下所示#header简写形式

<base-layout>
  <template #header>
    <h1>Here might be a page title</h1>
  </template>
</base-layout>

例4、独生槽的精简写法
如果该组件有且只有一个默认插槽(独生槽),则可以去掉<template>标签进一步简写

<base-layout>
    <h1>Here might be a page title</h1>
</base-layout>

再看作用域插槽

先写一个带有作用域插槽的vue组件,取名为 user-list 组件。此组件有3个插槽,一个名叫first,一个名叫last,还有一个是默认插槽default(已省略name="default"

<template>
    <ul class="list-unstyled">
        <li v-for="user in users">
            <slot :user="user">
                {{user.id}}
            </slot>
            <slot name="first" :first="user">
                {{user.firstName}}
            </slot>
            <slot name="last" :last="user">
                {{user.lastName}}
            </slot>
        </li>
    </ul>
</template>

<script>
    export default {
        props: ['users']
    }
</script>

上述代码中 :first 与 :last 的命名很糟糕,它们并没有用来表示用户的姓、名,竟然指向了同一个 user 对象。不过这并不影响我们对作用域插槽的学习。
在本文的末尾,将会采用相对优雅一点的写法改写这个例子。

例5、无视插槽,直接使用组件
在blade模版中敲入代码<user-list :users="{{$users}}"></user-list>,显示如下信息
Vue 的作用域插槽是个难点
例6、格式化 first 插槽(使用了可以随意命名的 props,不推荐)
开始玩花样了,用下面这段代码格式化firstName(改成大写,并放到【】里面)

    <user-list :users="{{$users}}">
        <template #first="props">
            【@{{props.first.firstName.toUpperCase()}}</template>
    </user-list>

@{{props.first.firstName.toUpperCase()}}这行代码将会留给 Vue 解析。这里的 @ 符号提示 blade 模板:不要解析花括号里面的内容,仅仅去掉 @ 符号即可。
:users="{{$users}}"这里面的 {{$users}} 是 blade 模板语法;而 :users=”xxx” 则是 Vue 语法。

效果如下图。这里分析一下这段代码的含义:调用者是blade模板,调用的是user-list组件,调用者调用组件后对组件的first插槽做了点手脚,使得组件呈现的效果有所不同(从而达到格式化的目的)。注意这行<template #first="props">,其中#first是不能变的,这是由插槽的名字决定的;引号里面的props是自由可变的(可以随意命名)。需要注意的是props.first.firstName.toUpperCase()这句代码里面的first是怎么来的?这个first是组件定义插槽时决定的。组件定义插槽时有这么一行<slot name="first" :first="user">,这里面有个:first,就是由这个带冒号的属性决定的。

Vue 的作用域插槽是个难点

作用域插槽的对象解构

例7、格式化 last 插槽(推荐写法)
使用对象解构,会让代码简单一些

    <user-list :users="{{$users}}">
        <template #last="{last}">
            <span class="text-primary"> @{{last.lastName}} </span>
        </template>
    </user-list>

效果如下图。这里面的#last="{last}"就是对象解构,使用的时候就可以直接写成last.lastName了。这比前例的写法要紧凑,前例多了一个自由命名的props
Vue 的作用域插槽是个难点
在定义插槽的时候,不同的插槽要取不同的名字,这点毫无疑问。但是不同插槽的属性名称是没必要区分的,属性名称完全可以取一模一样的名字。
具体来说:<slot :user="user"><slot name="first" :first="user"><slot name="last" :last="user">,其中default插槽取了一个叫做:user的属性名称,first取了一个叫做:first的属性名,最后一个取了一个:last的属性名。这种区分完全没必要。
可以全部写成一样的:user,即<slot :user="user"><slot name="first" :user="user"><slot name="last" :user="user">

例8、插槽默认值的清空方法
再看下面这个例子,默认插槽的对象解构(格式化默认插槽,并清空first插槽及last插槽的默认数据)

    <user-list :users="{{$users}}">
        <template #default="{user}">
            (@{{user.id}}) @{{user.name}}
        </template>
        <template #first><i></i></template>
        <template #last><i></i></template>
    </user-list>

以下为效果图
Vue 的作用域插槽是个难点

独占式作用域插槽

例9、独生带域槽的精简写法
修改user-list组件,将其中的first插槽及last插槽的定义代码全部删除,只保留一个default插槽,形成独占,称之:独占式作用域插槽(也就是组件的“独生带域槽”)。对于独生带域槽,调用的时候可以完全删除<template>标签,但是要将#default="{user}"挪到父标签里面(代码如下,展示效果跟上图一样)

    <user-list :users="{{$users}}" #default="{user}">
        (@{{user.id}}) @{{user.name}}
    </user-list>

为什么要使用作用域插槽?

blade模版对user-list组件说:我给你一批用户数据,你帮我展现出来。
user-list组件说:好的,我用一个for循环依次处理。
blade模版:但是不能完全按你的那一套来,在slot这个地方要改一改。
user-list组件:具体要怎么改?
blade模版:你把材料拿过来,我演示给你看。
user-list组件:好的,给你 :user(这一步早在插槽定义的时候就准备好了的 <slot :user="user">)。
blade模版接过材料:看好了,我给你写个模版,你要照着模版弄(所谓的接过材料,其实就是解构出 user )
<template #default="{user}">
(@{{user.id}}) @{{user.name}}
</template>
user-list组件:好的,没问题。

通过使用作用域插槽,blade模版达到了效果定制的目的;而user-list组件也通过作用域插槽明白了调用者的意图。

为什么 blade 模板需要跟 user-list 组件索要“材料”呢?因为这里涉及到“作用域”的问题。在 blade 调用组件的时候,是访问不到组件内部数据的,但是可以访问组件对外暴露的数据。

组件内部定义插槽 对外暴露 外部使用作用域插槽
<slot :user=”xxx”> user <template #default=”{user}”>
<slot name=”first” :first=”xxx”> first <template #first=”{first}”>
<slot name=”last” :last=”xxx”> last <template #last=”{last}”>
<slot name=”jack” :a=”yyy” :b=”zzz”> a & b <template #jack=”{a, b}”>

改写作用域插槽

首先改写 UserList.vue 文件。这次没有 default 插槽,取而代之的是 name=”id” 的插槽;再将 first 插槽和 last 插槽合并成一个 name=”name” 的插槽;另外,这一个插槽对外暴露了两项数据,此时的 :first 与 :last 已经成了名副其实的用来表示姓、名的变量了。

<template>
    <ul class="list-unstyled">
        <li v-for="user in users">
            <slot name="id" :id="user.id">
                {{user.id}}
            </slot>
            <slot name="name" :first="user.firstName" :last="user.lastName">
                {{user.firstName}} {{user.lastName}}
            </slot>
        </li>
    </ul>
</template>

<script>
    export default {
        props: ['users']
    }
</script>

例10、格式化多属性槽
如此一来,blade 模板的代码也要相应调整,改成下面这样

<div class="card-body">
    <user-list :users="{{$users}}">
        <template #id="{id}">@{{id}}. </template>
        <template #name="{first, last}">
            @{{first.toUpperCase()}} <span class="text-primary">@{{last}}</span>
        </template>
    </user-list>
</div>

效果如下图
Vue 的作用域插槽是个难点

代码库

本文代码 git@gitee.com:zhaiduting/see.git
1、git clone git@gitee.com:zhaiduting/see.git
2、cd see; composer install; npm install; npm run dev
3、配置 .env
4、php artisan migrate –seed
5、搭建服务器
6、使用http://x.xx.x/slot查看效果
7、版本回退,重新编译后再看效果

本作品采用《CC 协议》,转载必须注明作者和本文链接
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!
未填写
文章
48
粉丝
14
喜欢
126
收藏
103
排名:134
访问:3.7 万
私信
所有博文