前言

最近 ref 的语法糖引起了极大的争议,很多人也是没看 RFC 就间接开喷,尽管我也不喜爱这种语法,但还是有必要让大家看一看在 GitHub 上的提案,看看国外开发者们广泛都是些什么态度,是否和咱们持有同样的观点,提案是 RFC 228,但 RFC 228 其实是为了不便与另一个提案辨别开而新开的,原提案是 RFC 222,它最终被分解成了 RFC 227 和 RFC 228,所以咱们先从 RFC 222 开始翻译。

译文

尤雨溪

简介

  • 在单文件组件(xxx.vue)中引入了一个新的 script 类型:<script setup> ,这种写法会主动将所有顶级变量申明裸露给 <template> 应用。
  • 介绍一个基于编译器的语法糖,这种语法糖能够在<script setup>中让你的 ref 不必再写 .value 属性了。
  • 留神,本提案意在代替 RFC 182 提出的 <script setup> 写法。

根本用法

  1. <script setup> 间接向 <template> 裸露顶级变量
⚠️译者注: 顶级变量就是没申明在块级作用域外面的变量
<script setup>// 引入的 Foo 组件能够间接在 template 里应用了!import Foo from './Foo.vue'  import { ref } from 'vue'// 就像在一般的 setup() 中一样编写 Composition API 代码,// 无需手动返回所有内容const count = ref(0)const inc = () => { count.value++ }</script><template>  <Foo :count="count" @click="inc" /></template>

????下面的这段代码将会编译成上面这样????:

<script setup>import Foo from './Foo.vue'import { ref } from 'vue'export default {  setup() {    const count = ref(1)    const inc = () => { count.value++ }    return {      Foo, // 即便 Foo 组件不是被申明的,也会把它算作顶级变量      count,      inc    }  }}</script><template>  <Foo :count="count" @click="inc" /></template>
  1. ref:语法糖令代码更简洁
<script setup>// 申明一个变量(这个变量将会被编译成一个ref)ref: count = 1function inc() {  // 该变量能够像一般变量那样应用  count++}// 想要获取到本来的变量的话须要在变量后面加一个????符号console.log($count.value)</script><template>  <button @click="inc">{{ count }}</button></template>

????下面的这段代码将会编译成上面这样????:

<script setup>import { ref } from 'vue'export default {  setup() {    const count = ref(1)    function inc() {      count.value++    }    console.log(count.value)    return {      count,      inc    }  }}</script><template>  <button @click="inc">{{ count }}</button></template>

评论之前:

  • 请确保曾经读完残缺的 RFC
  • 请不要简略地答复"我喜爱/我不喜爱"-它不会对探讨做出有意义的奉献。
  • 如果不赞成该提案,请在动机和弊病中提出的观点范畴内进行具体论证。请留神,这中语法是 JavaScript 中的标签语法。咱们只是给 ref: 这个标签提供了不同的语义。这就像在 HTML 写 Vue 指令一样。
⚠️译者注:而后接下来是高赞回复:

耶姆贾森(ycmjason ????????)

只是一个意见:

真的不喜爱这个主见。发明的语法太多了。而且这曾经不再是 JavaScript 了。

尤雨溪(回复)

你这种反馈在咱们的意料之中,我晓得这可能会引起争议,因而对于其余任何评论:

  • 请确保曾经读完残缺的 RFC
  • 请不要简略地答复"我喜爱/我不喜爱"-它不会对探讨做出有意义的奉献。
  • 如果不赞成该提案,请在动机和弊病中提出的观点范畴内进行具体论证。

私人号码(privatenumber ???????? ????????)

编译器会主动将所有导入的 xxx.vue 文件注册为组件吗?

具体来说,我很好奇编译器怎么辨认什么是Vue组件,什么不是。如果我导入一个 xxx.js 模式的组件,那还能够应用吗?

如果咱们用到了高阶组件的话,也可能不心愿这个导入的高阶组件被主动注册成组件。

如果咱们要增加自定义语法,那么 ES2021 的 export default from 语法是否能够施行?

我感觉这种写法可能既简洁又明确:

export { default as Foo } from './Foo.vue';

尤雨溪(回复)

编译器能够通过 setup 上下文来判断。模板编译器会从 script 编译时提取绑定信息判断该组件是否可用。

我认为导入 xxx.vue 并利用高阶组件的模式去包装是十分常见的一种状况。在这种状况下,您能够应用独自的惯例<script>标签用以前的形式去注册组件。

必图(btoo ????????)

我宁愿用 svelte 的 $: 而不是 svelte-ref: 这种模式。

其实也能够通过在变量名前增加一个$前缀来放弃拜访原始 ref 的形式。

⚠️译者注:svelte 是国外另一款特地火的框架,这个提案的灵感就来源于这个 svelte 的写法

约翰逊(johnsoncodehk ????????)

⚠️译者注:这个人不是高赞(????),而是高踩(????),咱们看看也别光看高赞,高踩也挺有意思
$: + let / const 这种写法怎么样怎么样?
就像这样:
$: let foo = 1 // 这个变量代表ref$: const bar = foo + 1 // 这个变量代表computed$: let baz = computed(() => bar + 1)

而后会被编译成这样:

const $foo = ref(1)let foo = unref($foo)const $bar = computed(() => foo + 1)const bar = unref($bar)const $baz = ref(computed(() => bar + 1))let baz = unref($baz)

我感觉大家如同都不想脱离 js 的语义,当然咱们能够有一种齐全基于 js 语义的办法,但这是咱们想要的吗:

import { noValueRef, noValueComputed } from 'vue'let foo = noValueRef(1) // TS类型: number & { raw: Ref<number> }const bar = noValueComputed(() => foo + 1) // TS类型: number & { raw: ComputedRef<number> }useNum(bar.raw)function useNum(num: Ref<number>)

而后会被编译成这样:

import { ref, computed } from 'vue'let foo = ref(1)const bar = computed(() => foo.value + 1)useNum(bar)function useNum(num: Ref<number>)

喜爱的点赞(????),不喜爱就踩(????)

⚠️译者注:下面那句话是他说的不是我说的,果然亚洲都喜爱玩这一套

罗宾鲍乌(RobbinBaauw ????????)

这个 RFC 的毛病(<script setup>自身也是一个毛病,但当初变得更糟)是编写大量雷同内容的 options。经验丰富的 Vue 开发者(例如对此RFC进行评论的这帮人)理解所有的 options,理解它们之间的关系等,然而对于 Vue 的大部分开发者而言,状况并非如此。

在 Vue2 中,只有 Options API,最终咱们会失去一个相似类一样的组件。然而如果用了这个 RFC,咱们将会面临以下抉择:

  • Options API
  • Class API (须要用插件)
  • Composition API (vue2 和 vue3 的写法也不一样)
  • \<script setup> 搭配ref:语法糖
  • \<script setup> 不搭配语法糖

这会让用户群变得十分扩散,让刚入门的小白和有抉择艰难症的人感觉太难了。如果只须要记住:"想要响应式就用 Options API,不便逻辑复用就用 Composition API"的话那就会简略多了。

然而很显著,不少人喜爱这种"神奇的"语法。如果有人再提出个什么自定义的语法说不定当前还会想再扩大语法,能不能在 Vue 以外的第三方库去实现它?如果这是 Vue 的外围语法,那么在当前的 Vue 版本中都将须要反对它。

我认为这个$十分令人纳闷:如果您不齐全理解$前缀的前因后果,我认为这将会令人十分纳闷!也就是说,须要晓得一个这玩意是个 ref 的理论值,并且还须要晓得本人正在解决的是一个加了语法糖的 ref,在这种状况下须要给它加上$前缀,而在其余状况下,则不须要加前缀。我深信这会给许多用户带来很多问题。

尤雨溪(回复)

你说的太夸大了。

Class API 是一个官网插件,但只是一个插件。不是外围API的一部分,仅吸引特地偏爱 Class 的用户。换句话说,它不是"支流"。

⚠️译者注:不是支流那不就是非主流

vue2 和 vue3 的 Composition API 的目标是雷同的,并且即便不是全副,也至多是大多数代码看起来雷同。渺小的技术差别不会将它们视为"做同一件事的两种形式"。

<script setup>就如 RFC 中所倡议的那样,用不含语法糖编写的 Composition API 代码与失常的 Composition API 应用状况 100% 雷同(除了无需手动返回所有内容)。实际上,如果用户应用的是但文件组件的话,因为前者总是只用写更少的代码,所以我真找不到不必新<script setup>的理由。

难道你感觉这么写更好吗:

export default {  components: {...},  setup() { ... }}

ref:是纯语法糖。它不会扭转 <script setup> 外面 Composition API 的工作形式。如果你曾经了解了 Composition API,那么了解ref:语法糖不会超过10分钟。

综上所述-有两个"范例":
(1)Options API
(2)Composition API
<script setup> 和ref:语法糖不是不同的 API 或范例。它们只是 Composition API 的扩大,能够用更少的代码来表白雷同的逻辑。

(援用罗宾方才说的话):如果有人再提出个什么自定义的语法说不定当前还会想再扩大语法,能不能在 Vue 以外的第三方库去实现它?

所以,你也批准很多人都心愿应用ref:语法糖,然而却倡议不要在 Vue 中反对它,而是激励各种第三方库各自实现本人的语法。这不是只会导致更多的碎片化吗?想想 React 生态系统中的CSS-in-JS。

(援用罗宾方才说的话):我认为这个$十分令人纳闷:如果您不齐全理解$前缀的前因后果,我认为这将会令人十分纳闷!也就是说,须要晓得一个这玩意是个 ref 的理论值,并且还须要晓得本人正在解决的是一个加了语法糖的 ref,在这种状况下须要给它加上$前缀,而在其余状况下,则不须要加前缀。我深信这会给许多用户带来很多问题。。

$foo 其实就代表 foo 就好比 foo 就代表 foo.value。真的那么令人蛊惑吗?这会导致什么确切的具体问题?遗记$何时增加?请留神,即便没有语法糖,咱们也遗记什么时候该用.value,后者更可能产生。

你是在要求用户放弃 Composition API 的益处,因为您不喜爱语法糖,因为语法糖会使Composition API 变得不太简短。我真的认为没有情理。

林纳斯·伯格(LinusBorg ????????)

如果 <script setup> 当初间接向 <template> 模板公开顶级变量

那将如何解决两头变量:

const store = inject('my-store')ref: stateICareAbout = computed(() => store.state.myState)function addState(newState) {  store.add(newState)}

即便 store 这个变量不须要公开到 <template> 下来,也会裸露给<template>模板。但这实际上是一个问题吗?

不利的一面是: 它将使生成的代码变大,因为它会使设置返回的对象变大,并且咱们对模板所裸露的内容失去了一些"清晰度"。

从好的方面来说,人们可能会辩论说,明确定义裸露于模板的内容太麻烦啦,感觉 <template> 当初更像是 JSX 了。

尤雨溪(回复)

是的,所有顶级变量都会裸露在外。从技术上讲,如果将其合并,咱们还能够引入另一种模板编译模式,在该模式下,间接从 setup 中 return 一个 render 函数。这使得作用域更加间接,并且防止了 render proxy。

埃勒夫(iNerV ????????)

这太蹩脚了。我不想在 Vue 中看到 svelte。(不想看到不非法的 js 语法)

总结

总体来说,持拥护态度的人占多数,和国内差不多,不过看到这么多不同国籍的人在这里探讨还挺有意思的,然而中国????????的声音却非常少,好不容易看到一个还是香港????????的,大家也能够去 GitHub 上间接舌战群儒。

当然哈,别用中文,毕竟你要让所有国籍的人都能看懂(至多是勉强看懂,我翻译荷兰那小子的英文,感觉说的也不咋地,咱们英文不比他们差),设想一下这些人如果都用本人的母语发表观点的话咱们还怎么读懂。强行用中文的话同胞们看着是难受了,然而会导致咱们在国内上的名声进一步下滑。

大家在去 GitHub 探讨的时候还是要尽量维持一下咱们国家在国内上的形象哈!

该文章首发于公众号:《前端学不动》