翻译:
Label
语法源于GOTO
语句,使用它将会令代码变得难以理解、难以维护。—ESLint
不过既然没什么人在用,同时它还是JS
的合法语法,那用它来告诉编译器这里是声明了一个ref
变量岂不是很完美?于是乎尤大也搞了个和Svelte
类似的语法:
<script setup> ref: isLoading = true if (isLoading) { isLoading = false } </script>
那么大家为何会如此反对呢?就是因为label
语法压根儿就不是这么用的,人家原本是为了和break
、continue
配合使用的,虽然在别的地方用也不算是语法错误,但你这么做明显是修改了JS
原本的语意!虽然尤大表示很不服啊:为什么Svelte
用这玩意你们都没说啥,我一用这玩意你们就开喷?!
个人感觉是因为Svelte
从一开始就说自己是一个编译器,没有沉重的历史包袱,而Vue
却恰恰相反。而且Svelte
本身也不是什么主流框架,属于给那帮爱折腾的人玩的。
但Vue
不一样,已经有多少人要靠着Vue
吃饭呢,并不是所有人都那么爱折腾的。
于是在万般无奈之下,尤大只好放弃了这个提案,但这件事在尤大心里始终还是挥之不去、如鲠在喉,于是乎他吸取了第一波语法糖的教学,卷头重来又起草了一份新提案:
第二波语法糖
<script setup> let loading = $ref(true) if (loading) { loading = false } </script>
可以看到我们并没有引入$ref
这个变量,这个变量是从哪来的的呢?是只要在<script>
标签里写了setup
这个属性就会自动注入的一个全局变量(需要先开启实验性语法开关)
尤大心想:你们不是嫌我之前用了不规范的语法么?那我这回这么写应该没问题了吧!想想之前我们定义一个ref
变量,首先需要先把ref
引进来然后才能用:
import { ref } from 'vue' const loading = ref(true)
而新语法不用引,直接就能用,类似于全局变量的感觉。除了$ref
这个特殊的全局变量呢,这次提案还有:$computed
、$fromRefs
和$raw
这几个玩意。我们一个个来看,先看$computed
:
<script setup> import { ref, computed } from 'vue' const num = ref(1) const num_10 = computed(() => num.value * 10) </script> <script setup> let num = $ref(1) const num_10 = $computed(() => num * 10) </script>
$fromRefs
又是个啥呢?这玩意在之前没有啊!只听说过toRefs
:
<script setup> import { fromRefs } from 'vue' // 这个 API 并不存在 import { toRefs } from 'vue' // 这个 API 倒是有 也就是只有 to 没有 from </script>
其实这个$fromRefs
正是为了配合toRefs
而产生的,比方说我们在别的地方写了一个useXxx
:
import { reactive } from 'vue' const state = reactive({ x: 0, y: 0 }) export default = (x = 0, y = 0) => { state.x = x state.y = y return toRefs(state) }
于是我们在使用的时候就:
<script setup> import { useXxx } form '../useXxx.js' const { x, y } = useXxx(100, 200) console.log(x.value, y.value) </script>
这岂不是又要出现尤大最不想看到的.value
属性了吗?所以$fromRefs
就是为了解决这个问题而生的:
<script setup> import { useXxx } form '../useXxx.js' const { x, y } = $fromRefs(useXxx(100, 200)) console.log(x, y) </script>
最后一个 API 就是$raw
了,raw 不是原始的意思嘛!那么看名字也能猜到,就是我们用$ref
所创建出来的其实是一个响应式对象
,而不是一个基本数据类型,但语法糖会让我们在使用的过程中像是在用基本数据类型那样可以改来改去,但有时我们想看看这个对象
长什么样,那么我们就需要用到$raw
了:
<script setup> const loading = $ref(true) console.log(loading) // 其实打印的不是 loading 这个对象 而是它里面的值 相当于 loading.value console.log($raw(loading)) // 这回打印的就是 loading 这个对象了 </script>
改进版
这一版语法糖没过多久就又被改进了,改进版主要是把全局变量改为只有$
和$$
这俩变量了,假如我们不用语法糖时是这么写:
<script setup> import { ref } from 'vue' const loading = ref(true) console.log(loading.value) </script>
用语法糖以后就变成了这样:
<script setup> import { ref } from 'vue' const loading = $(ref(true)) console.log(loading) </script>
如果我们想还原 loading
这个变量,我们就需要用到$$
了:
<script setup> import { ref } from 'vue' let loading = $(ref(true)) console.log($$(loading)) </script>
或者也可以写成这样:
<script setup> import { ref } from 'vue' const loadingRef = ref(true) let loading = $(loadingRef) console.log(loadingRef === $$(loading)) </script>
第三波语法糖
第三波语法糖主要是在第二波语法的基础上又进行了改进,除了许多人觉得要写成$(ref())
的话实在是太那什么了…
另一方面则是实现了props
的语法糖,新的语法主要是为每个能够创建带有.value
变量的方法都有一个$
前缀的等价物,比如:
ref
computed
shallowRef
customRef
toRef
与此同时保留了改进版中的$
变量与$$
变量,用于对props
的解构:
<script setup> const { isLoading } = $(defineProps({ isLoading: Boolean })) </script>
要知道在以前我们是不能对props
进行解构的,而现在还可以利用ES6
的解构默认值写法来为props
设置默认值:
<!-- 以前 --> <script setup> const props = defineProps({ isLoading: { type: Boolean, default: true } })) console.log(props.isLoading) </script> <!-- 现在 --> <script setup> const { isLoading = true } = $(defineProps({ isLoading: Boolean })) console.log(isLoading) </script>
所有语法糖提案的地址
写在最后
链接已经给大家贴上来了,就看大家是一副凑热闹的态度,还是点进去链接勇敢的表达出自己的声音了。当然,如果去GitHub
我们还是要说英文的,虽说用中文的话尤大也可以看得懂,但评论区不全是中国人,Vue
还是有相当一批外国粉丝的。而且也不全是美国人,那些不是英国人美国人的开发者,他们如果也只图自己痛快而说自己国家的母语的话,想必我们就没有办法进行沟通了,同时这也会进一步拉近国人在海外的形象:别人都用英文,就你们中国人用自己的语言,不遵守规则。
来源于公众号:前端学不动 ,作者手撕红黑树