[译]尤雨溪: Ref语法糖提案
前言
最近 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> 写法。
基本用法
- <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>
ref:
语法糖令代码更简洁<script setup> // 声明一个变量(这个变量将会被编译成一个ref) ref: count = 1 function 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 讨论的时候还是要尽量维持一下咱们国家在国际上的形象哈!
Vue3又出新语法 到底何时才能折腾完?
手撕红黑树赞 1阅读 2.4k
涨姿势了,有意思的气泡 Loading 效果
chokcoco赞 20阅读 2.1k评论 2
在前端使用 JS 进行分类汇总
边城赞 17阅读 1.9k
【已结束】SegmentFault 思否写作挑战赛!
SegmentFault思否赞 20阅读 5.6k评论 10
你可能不需要JS!CSS实现一个计时器
XboxYan赞 21阅读 1.6k评论 1
Vue2 导出excel
原谅我一生不羁放歌搞文艺赞 14阅读 20k评论 9
「彻底弄懂」this全面解析
wuwhs赞 17阅读 2.4k
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。