0001-new-slot-syntax

概要

scoped slot 用法的新语法

  • slotslot-scope 合并成了 v-slot 语法
  • v-slot 可能 会统一 slotslot-scope

基础示例

// 普通插槽
<foo v-slot="{ msg }">
    {{ msg }}
</foo>
// 具名插槽
<foo>
    <template v-slot:one="{ msg }">
        {{ msg }}
    </template>
</foo>

起因

我们一开始尝试scoped slots的时候,他非常冗长,因为要用<template slot-scope>

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

为了让他简单点,在2.5版本,我们尝试将slot-scope的能力直接使用在slot元素上

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

也意味着可以用在组件上

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

然而,上面这些用法导致了一个问题,slot-scope的放置不能总是清晰地反应到底是哪个组件实际提供scope变量。
这里的slot-scope作用在<bar />组件上,但是它实际上是由<foo />组件的提供的默认slot能力提供的。

在嵌套结构中,会出现问题

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

他不能随即清晰模板里哪个组件在提供变量
很多人建议我们应该在组件自身上使用slot-scope,去表示他的默认插槽的作用域。

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

不幸的是,他在组件嵌套的时候模棱两可不能工作

<parent>
    <!-- foo到底是parent还是foo的props -->
    <foo slot-scope="foo">
        {{ foo }}
    </foo>
</parent>

这就是为什么我认为在template以外使用slot-scope是个错误。

为什么要用新指令来代替修复slot-scope

如果我们可以时光倒流,我大概会改变slot-scope的语义,但是

  1. 这现在是一个破坏式的改动,也就意味着我们不能用在 vue 2.x
  2. 就算在3.x改变了他,改变一个已经存在的语法,谷歌会成为过时的资料,导致很多未来学习者的混乱。我们想避免这件事,所以我们会采用新的不同于slot-scope的东西。
  3. 在3.x 我们想去统一slot的类型,所以没必要再去区分 scoped 和non-scoped slots(理论上的)。一个插槽可能接收props,也可能不接收,但是他们都是插槽。通过这种概念上的统一,slotslot-scope两种不同属性的就没必要了,并且他在单一的结构下也会更好的去统一语法。

细节设计

介绍新指令:v-slot

  • 可以在 <template> 的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>

如果任意作用域插槽是接收props的作用域插槽,接收的slot props可以声明在使用指令的属性里值里。v-slot 的值与 slot-scope的工作方式相同,因此支持参数结构

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

v-slot 可以直接作用于组件不需要参数,来表明组件默认slot的scoped slot。并且props通过默认slot传递,也可以在属性里声明变量。

比较:New vs. Old

让我们回顾下改提案是否实现了我们概述的目标:

  • 仍然为最通用的scoped slots用法(单默认插槽)提供了简洁的的语法
<foo v-slot="{ msg }">{{ msg }}</foo>
  • 清除了scoped变量与提供他的组件的关联

让我们再看一下使用当前的语法(slot-scope)的深度嵌套,注意<foo>提供而插槽范围变量是如何在<bar>上声明的,bar上提供的变量是如何在<baz>上声明的。

<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>

注意,由组件提供的作用域变量也在该组件本身上声明。新语法显示了插槽变量声明和提供变量的组件之间更清晰的联系。

更多用法比较

有text的默认插槽
<!-- old -->
<foo>
  <template slot-scope="{ msg }">
    {{ msg }}
  </template>
</foo>

<!-- new -->
<foo v-slot="{ msg }">
  {{ msg }}
</foo>
有元素的默认插槽
<!-- 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>

缺点

  • 引入新语法会带来搅动,并且让有关这个话题的学习资料处在一个过时的生态里。(我们需要好的文档去帮助我们升级scoped slots)
  • 默认插槽v-slot="{ msg }"不能准确地传递msg是作为prop被slot传递的。

选择

  • 新的特殊属性 slot-props
  • 指令v-scope代替最初提到的特殊属性
  • 使用&代替v-slot

采纳策略

所做的更改完全向后兼容,所以我们可以在小版本中加入,计划是在2.6

slot-scope已经被软弃用了:这会在文档里被标记,并且我们会鼓励每个人去使用/切换新语法,但是我们不会因为这个弃用消息来影响你,我们知道迁移新语法通常不是最高优的事情。

在3.0里,我们打算最终删除slot-scope,并且只支持新语法。我们会在下一个2.x的小版本发布废弃消息,从而简化迁移3.0。

既然这是一个定义明确的语法更改,我们可以提供一种迁移工具,该工具可以讲模板自动自动转化为新语法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值