首发:cc log--开箱Svelte
2019年的最后一天了,前端仍然是React,Vue,Angular三大框架的天下,大概率到了明年此时仍然是它们的天下,不过各路神仙们仍然在孜孜不倦的创造着轮子😄,最有名的”轮子哥“自然是创造了rollup的Rich-Harris了,最近的项目是一个web框架Svelte。
Svelte is a radical new approach to building user interfaces. Whereas traditional frameworks like React and Vue do the bulk of their work in the browser, Svelte shifts that work into a compile step that happens when you build your app.
Svelte不一样在于:
- 所谓“消失即逝”的框架,尽可能通过静态编译减少框架运行时的代码量,这点本文不展开,感兴趣的可以看Vue作者尤大关于Svelte的知乎答案。
- 不使用Virtual Dom
- 真响应式
抛开这些太过官网的说辞,吸引我的是:
- 作者一个超精彩的视频:Rethinking Reactivity
- 超甜的语法(类似Vue)。
- 内置的响应式store方案(类似RxJS,但是精简易学)
……
经过一个比预期漫长,比预期曲折的chrome extension(TODO: Ghost-mde介绍)开发之后,我想写下这篇Svelte开箱,个人的简短观点是:
- 语法惊奇有趣(褒义,就像逍遥派派的功夫较之于少林的功夫)。
- 小型业余项目推荐使用(编写速度和build代码大小是优势)。
- 正式,公司级,中文圈不建议(资料不太多,有些概念有别于React这种“不成文的标准”)。
Svelte基础
Svelte基本使用方式上和Vue很相似,组件的HTML,CSS,JS写在一个.svelte的文件中。
<script>
let count = 0;
function handleClick() {
count += 1;
}
</script>
<style>
button {
background: #ff3e00;
color: white;
border: none;
padding: 8px 12px;
border-radius: 2px;
}
</style>
<button on:click={handleClick}>
Clicked {count} {count === 1 ? 'time' : 'times'}
</button>
模版语法
if
{#if porridge.temperature > 100}
<p>too hot!</p>
{:else if 80 > porridge.temperature}
<p>too cold!</p>
{:else}
<p>just right!</p>
{/if}
循环语法each
{#each items as item, i}
<li>{i + 1}: {item.name} x {item.qty}</li>
{/each}
异步加载await
甚至可以直接在模版中使用promise
{#await promise}
<!-- promise is pending -->
<p>waiting for the promise to resolve...</p>
{:then value}
<!-- promise was fulfilled -->
<p>The value is {value}</p>
{:catch error}
<!-- promise was rejected -->
<p>Something went wrong: {error.message}</p>
{/await}
元素指令
Svelte中的元素指令可以让你很方便的操控元素。
- 事件监听on:eventname:
on:eventname|modifiers={handler} - 属性绑定bind:property:
bind:property={variable}- 甚至可以只读的绑定
clientWidth,clientHeight,offsetWidth,offsetWidth
- 甚至可以只读的绑定
- 组合input(radio, checkbox)属性绑定bind:group={variable}
- 获取DOM节点或组件的实例,bind:this :
bind:this={dom_node} - class绑定,
div class="{active ? 'active' : ''}">...</div>,<div class:active class:inactive={!active} class:isAdmin>...</div> - 以及常用的
slot - ……
总体来说来svelte基础语法实在易用,上手也很容易。更多可以查看Svelte API文档。
神奇的符号 $
Svelte巧妙的使用了一个js中没什么用的$符号,来表达响应。
let a = 0;
$: b = a + 5;
变量b的值会随着a的变化而变化。甚至可以包裹成更复杂代码快。
let a = 1;
let b = 2;
$: {
if (a+b > 10){
// do something
}
}
Svelte 生命周期
web框架,特别是组件化的框架,自然会有生命周期,Svelte也不例外:
- onMound:
onMount(callback: () => () => void) - beforeUpdate:
beforeUpdate(callback: () => void) - afterUpdate:
afterUpdate(callback: () => void) - onDestroy:
onDestroy(callback: () => void)
行为和大家熟知Vue,React的基本一样。
Svelte dispatch, Context
Svelte组件的组合,以及组件的通信和Vue的非常的类似, 属性自上而下通过?props传递,子组件向上dispath事件。
<script>
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher();
</script>
<button on:click="{() => dispatch('notify', 'detail value')}">Fire Event</button>
这样自然也有跨组件通信的问题,Svelte则是提供了context, 不过和Svelte store 结合,使用也挺容易。
import { writable } from "svelte/store";
const nameStore = writable("name");
setContext("name", nameStore);
function changeName() {
nameStore.set("name2");
}
<div>
<p>{$name}</p>
</div>
<script>
import { getContext } from "svelte";
const name = getContext("name");
</script>
so far so good, 下面进入Svelte真正有趣的地方🤓
Svelte store使用
现代的数据驱动框架,绕不开的就是状态管理库,Svelte则是提供了一个相当精巧易用的方案, Svelte store。
Svelte store的思路和响应式框架RxJS很像,但是在保留响应式能力的同时,尽可能降低了使用难度(不会像RxJS那么高的门槛, 甚至也不像redux那么死板),这点给Svelte点赞👍👍👍。
writable
可以使用writable来创建一个可写的store。
store = writable(value: any, (set: (value: any) => void) => () => void)
使用也很简单
<div>{$count}</div>
<script>
import { writable } from 'svelte/store';
const count = writable(0);
count.subscribe(value => {
console.log(value);
}); // logs '0'
count.set(1); // logs '1'
count.update(n => n + 1); // logs '2'
</script>
subscribe方法来订阅store的变化set方法设置值,update方法使用函数来方便拿到store中的值,再设置新的值。- HTML模版中使用
$来引用store。
readable
store = readable(value: any, (set: (value: any) => void) => () => void)
使用readable来创建可以外部不可写的store。
import { readable } from 'svelte/store';
const time = readable(new Date(), set => {
const interval = setInterval(() => {
set(new Date());
}, 1000);
return () => clearInterval(interval);
});
derived
derived才是真正点燃store的地方,它接受store然后转换为一个新的store,这其实RxJS中诸多的Operator做的事情,没有那么强大,但也降低了使用门槛。
store = derived(a, callback: (a: any) => any) // 可以接受单个store
store = derived([a, ...b], callback: ([a: any, ...b: any[]], set: (value: any) => void) => void | () => void, initial_value: any) // 也可以接受多个store
这里不会展开很多,个人认为derived可能是svelte最闪光的地方了,利用好的这个功能,会为你的代码增色不少。
Svelte的一点点不爽
- 不支持Typescript,2020年啦,这个算是个不小的缺陷。
- Svelte stroe在值发生变化时才会“响应”。这点和RxJS不一样。
- 有些不正常的写法可能不会触发响应,譬如,通过函数参数传递响应变量,会导致不响应……,这些初写可能会让你很沮丧😄
- ……
总结
总体来说Svelte提供了一种大三框架之外的思路和开发体验,值得大家学习,也鼓励大家在业余小型项目中使用。