带你走马观花,细看新版变化。
注意:原文发表于2018-04-18,随着框架不断演进,部分内容可能已不适用。
大约是一年之前,我们首次在 Svelte 的 issue 跟踪器上讨论过 v2 版本,现在是时候进行一些重大变更了。
我们的座右铭是“循序渐进,破旧立新”。
……好吧,我错了,看来我要改过自新了。
这篇博文阐述了新版本的变化,都变了哪些地方、为什么要变以及应对的策略。
长话短说,先看梗概
我们会不厌其详地描述每一个变更细项,如果你还是遇到了困难,请在我们气氛友好的 Discord 聊天室 中寻求帮助。
- 从 npm 安装 Svelte v2
- 用 svelte-upgrade 升级你的模板
- 删除对
component.observe
方法的调用,或者从 svelte-extras 中添加observe
方法 - 将对
component.get('foo')
的调用重写为component.get().foo
- 从你的自定义事件处理程序中返回
destroy
,而不是teardown
- 确保没有将值是数字类型的字符串作为 props 传递给组件
最新的模板语法
最明显的变化是:我们对模板语法做了一些改进。
我们经常听到的反馈是,“哎呀,又是Mustache”或者“哎呀,这不Handlebars嘛”。
在 Web 开发的较早时期,许多开发者使用基于字符串的模板系统,但他们似乎对模板深痛恶绝。
由于 Svelte 也采用了这种 {{表达式}}
的语法,因此许多人以为我们也在某种程度上有那些相同的局限性,比如奇怪的作用域规则,或者无法随意使用 JavaScript 表达式。
提示:如果你需要显示一个 '{' 字符,那么它可以简单地用 '{' 来表示。
除此以外,JSX 证明了使用双大括号其实大可不必。
所以我们使得模板更加的 …… 怎么说呢,
Svelte 采用单个大括号括起表达式。
应该说结果似乎看起来更轻松了,打字时也更愉快了:
Hello {name}!
当然也还有一些其他的更新的。
好消息是你不需要手动去一个一个地改,只需要在代码库上运行 svelte-upgrade 就行:
npx svelte-upgrade v2 src
这假定 src
目录下的任何 .html
文件都是一个小组件。
源目录和目标目录均可以任君自由指定,例如,你可以使用 npx svelte-upgrade v2 routes
更新 Sapper 应用。
要查看完整的变更列表,请移尊步到 svelte-upgrade 的 README 文档。
计算属性
人们经常对 Svelte 感到困惑的一件事情是计算属性的工作方式。
回顾一下,如果你有这么一个组件……
export default {
computed: {
d: (a, b, c) => a = b + c
}
};
……Svelte 首先检查函数的参数,以便计算出 d
所依赖的参数是什么,然后它会自动编写好代码,在这些值发生改变时,通过将新值注入到函数中,从而更新 d
。
很酷吧!
因为它允许你从组件的输入中获取复杂的值,而不必担心何时需要重新计算它们,但这用法也怪里怪气的。
JavaScript 语法不支持这么写。
在 v2,我们用解构来代替:
export default {
computed: {
d: ({ a, b, c }) => a = b + c
}
};
Svelte 编译器仍然可以知道 d
依赖哪个值,但不再注入值,而是将整个组件状态对象丢给每个计算的属性中。
友情提示:你同样不需要手动进行此更改,只需要对组件运行 svelte-upgrade,如上所示。
IE11,不好意思,好自为之
Svelte v1 生成的是 ES5 的代码,这样你就不会被迫使用转译器。
但现在都 2018 年了,几乎所有浏览器都支持现代 JavaScript。如果能抛弃 ES5 的束缚,我们就可以生成更精简的代码。
不过你如果还需要友好地支持 IE11,你还是可以用 Babel 或者 Bublé 之类的转译器的。
新的生命周期 Hook
除了 oncreate
和 ondestroy
外,Svelte v2 还添加了两个生命周期函数来响应状态更改:
export default {
onstate({ changed, current, previous }) {
// 在 oncreate 之前以及状态变更时触发
},
onupdate({ changed, current, previous }) {
// 在 oncreate 之后触发, 并且状态变更后更新了 DOM 时触发
}
};
你还可以通过编写代码的方式监听这些事件:
component.on('state', ({ changed, current, previous }) => {
// ...
});
component.observe
使用新的生命周期函数,我们不再需要 component.observe(...)
方法:
// 之前
export default {
oncreate() {
this.observe('foo', foo => {
console.log(`foo is now ${foo}`);
});
}
};
// 之后
export default {
onstate({ changed, current }) {
if (changed.foo) {
console.log(`foo is now ${current.foo}`);
}
}
};
这可以减少 Svelte 生成的代码量,并为你提供了更大的灵活性。
例如,现在可以十分容易在几个属性中的任何一个发生变更时响应这些动作,比方说在不释放观察者的情况下进行重绘 canvas。
不过如果你实在喜欢使用 component.observe(...)
,你可以通过 svelte-extras 来支持这玩意。
import { observe } from 'svelte-extras';
export default {
methods: { observe }
};
component.get
这个方法不再接收可选的 key
参数 —— 相反,它总数返回整个 state 对象:
// 之前
const foo = this.get('foo');
const bar = this.get('bar');
// 之后
const { foo, bar } = this.get();
初时,这种改变可能看起来很烦人,但这是正确的方向:
除了其他特殊情况外,将来我们会更充分地探索这个方面,它可能会在类型系统中发挥更好的作用。
event_handler.destroy
如果你的应用程序具有自定义的事件处理器,那么它必须返回一个带有 destroy
方法,而不是 teardown
方法。这样事件处理器就和组件的 API 对齐了。
不再严格要求类型
以前,传递给组件的数字类型的值会被视为纯数字:
这可能会导致一些意外行为。现在已经被更改了。
如果你需要传递数字的字面量,可以直接用表达式:
编译器方面的变更
在大多数情况下,你是永远不需要直接和编译器打交道的,因此编译器方面你其实不需要什么对策的。
不管怎么说,值得注意的是:编译器的 API 也是有变更的。
现在编译器将返回 js
,css
,ast
和 stats
,而不是有一大堆属性的对象:
const { js, css, ast, stats } = svelte.compile(source, options);
js
和 css
都是 {code, map}
对象,其中 code
是代码字符串,map
代表 sourcemap。
ast
是组件的抽象语法树,并且 stats
对象包含有关组件的元数据以及编译信息。
以前是有一个 svelte.validate
方法来检查你的组件是否有效的。
不过它已经被删掉了,如果你只需检查组件,而不实际对其进行编译的话,那么仅仅传递一个 generate: false
选项即可。
我的应用还有问题要寻求帮助
希望以上的内容已经覆盖了所有可能的问题,并且更新对你来说,应该比较轻松从容的。
如果你发现错误或者本文未尽事项,请进入 Discord 聊天室 里头转转看,或者在 issue 跟踪器 反馈给我们。
< The End >
- 窗明几净,静候时日变迁 -