注:本文采用vue版本为3.4.0-alpha.3
之前我们提到了vue3.4.0-alpha.1 响应式逻辑的变动。而在今天,vue 发布了vue3.4.0-alpha.2&alpha.3版本,alpha.3版本算是对alpha.2的补充,因此合起来讲。
其实vue3.4.0-alpha.2 的一些功能在之前就已经处于待合并状态,但直到这次发布之前尚未被合并。现在我们有机会深入了解这些功能。
Reactivity Transform 被废弃
Reactivity Transform 可以翻译为响应式语法糖。这个功能在3.3版本被标记为不推荐使用。而在当前版本中,这个功能已经被彻底移除了。
如果有开发者仍希望使用这个功能,可以通过vue-macros来继续使用。
这个功能官网有详细说明,并且被彻底废弃,因此这里不再探讨详细用法以及实现原理,概括来说,可以通过一系列宏命令,实现去掉ref
的.value
以及将ref
转化为响应式对象等功能。
本身Reactivity Transform是为了提供更简洁的语法来改善开发体验,但却发现了不少问题。可以看这个讨论,概括如下:
- 失去了
.value
导致难以确定哪些内容正在被追踪以及哪些代码触发了响应式效果。这增加了在大型代码库中使用时的心智负担。 一些用户选择只在单文件组件内使用 Reactivity Transform,导致了不一致性和不同心智模型之间的切换成本。 - 由于外部函数仍需原始引用(raw refs),在 Reactive Variables 和原始引用之间的转换增加了学习和心智负担,尤其对初学者不友好。
- 存在潜在的碎片化风险,因为一些用户反对这个功能,担心在不同的代码库中工作时可能会遇到使用和不使用该功能的情况,扰乱了 JavaScript 的语义。
因此在这个版本被正式移除。
暴露computed上一个计算结果
这个功能还是响应式逻辑变动的那位老哥进行贡献的。
typescript
import isEqual from 'lodash.isequal';
const a = ref(1);
const b = ref(2);
const c = computed(oldValue => {
const newValue = { a: a.value, b: b.value };
return isEqual(oldValue, newValue) ? oldValue : newValue;
});
现在计算属性存在入参了,入参的值为上次计算结果。
正常来说,我们在使用Vue的过程中,无法通过计算属性本身来获取它上次的计算结果,但实际上,计算属性一直缓存着上一次计算结果_value
。
经过alpha.1响应式逻辑变动,如果标记为脏状态,那么就会使用effect.run()
获取最新计算结果,赋值给_value
,而构建计算属性的effect
的时候,会将_value
传入getter
形成新的getter
函数() => getter(this._value)
,这样会导致,执行effect.run()
的时候,会自动携带_value
,从而实现,在计算属性的入参,获取上次计算结果。
改进语言工具对代码解析的容错性
在之前的情况下,也就是标准的HTML解析中,下面的代码
js
<template><Hello\n</template><script>console.log(1)</script>
会被解析成
html
<template>
<hello\n< template="">
<script>console.log(1)</script>
</hello\n<>
</template>
会忽略斜杠,将<
和template
视为Hello
开放标签的属性,导致<template>
无法关闭,而<script>
被解析为其子元素。
这显然与预期不符。
因此增加了一段特殊处理逻辑
typescript
private peek() {
return this.buffer.charCodeAt(this.index + 1)
}
// 略
if (c === CharCodes.Lt && this.peek() === CharCodes.Slash) {
this.cbs.onopentagend(this.index)
this.state = State.BeforeTagName
this.sectionStart = this.index
}
如果处于处理开放标签状态时,同时遇到<
字符,并且接下来的字符是/
,那么就视为结束标签。
支持 v-bind 的简写语法
我们可以使用v-bind
在标签上绑定属性,并且可以省略v-bind
,使用缩写绑定。
html
<input v-bind:value="value" />
<input :value="value" />
现在,如果绑定是属性与数据同名,那么我们可以进一步省略。
html
<input v-bind:value />
<!-- <input v-bind:value="value" /> -->
<input :value />
<!-- <input :value="value" /> -->
<input .value />
<!-- <input .value="value" /> -->
<input :value.attr />
<!-- <input :value.attr="value" /> -->
<input :value-key.camel />
<!-- <input :value-key.camel="valueKey" /> -->
对应的改动代码也较为简洁
typescript
// 单独从dir解构exp
let { exp } = dir
// 如果exp不存在,并且是SIMPLE_EXPRESSION
if (!exp && arg.type === NodeTypes.SIMPLE_EXPRESSION) {
// 提取属性名
const propName = camelize(arg.content)
// 根据属性名计算出exp,也就是:arg替换成:arg="arg"
exp = dir.exp = createSimpleExpression(propName, false, arg.loc)
}
将生产构建中的错误链接到文档
我们在vue3.4.0-alpha.1 其他变动提到了导出错误代码,现在,Vue在生产环境中,如果发生错误,那么不仅仅抛出对应的错误码或者错误类型,还会附带对应的网址,可以查阅错误详细信息。
typescript
// errors.ts
const msg =
__DEV__ || !__BROWSER__
? (messages || errorMessages)[code] + (additionalMessage || ``)
: code
: `https://vuejs.org/errors/#compiler-${code}`
// errorHandling.ts
const errorInfo = __DEV__
? ErrorTypeStrings[type]
: `https://vuejs.org/errors/#runtime-${type}`