Svelte浅谈

探索Svelte

什么是Svelte

Svelte本意是苗条纤瘦的,Svelte是一种构建用户界面的全新方法,它被预测为未来十年可能取代ReactVue等其他框架的新兴技术。作者是前端轮子哥 Rich Harris,同时也是 Rollup 的作者。

他设计 Svelte 的核心思想在于『通过静态编译减少框架运行时的代码量』,也就是说,vuereact 这类传统的框架,都必须引入运行时 (runtime) 代码,用于虚拟dom、diff 算法。Svelted完全溶入JavaScript,应用所有需要的运行时代码都包含在bundle.js里面了,除了引入这个组件本身,你不需要再额外引入一个运行代码。
从2019年开始, Svelte出现在榜单中。刚刚过去的2020年,Svelte在满意度排行榜中超越了react,跃升到了第一位。

Svelte的优势

从容量大小来看,Vue58k,React97.5k,而Svelte只有9.7k。性能方面略逊Vue但是强于React。代码量方面碾压VueReact。同时,Svelte自带数据框架。

Svelte的劣势

  • 没有像AntD那样成熟的UI库。
  • Svelte 原生不支持预处理器,比如说less/scss。
  • Svelte 原生脚手架没有目录划分。
  • 暂时不支持typescript,虽然官方说了会支持, 但是不知道什么时候。

Svelte如何处理渲染问题

众所周知,React采用的虚拟DOM和diff算法来解决渲染问题,但是由于React 采用jsx语法本质不理解数据代表的意义,没有办法做出优化,因此才会出现诸如pureComponent,shouldComponentUpdate,useMemo,useCallback这些生命周期来控制重复渲染问题。

Svelte 采用了Templates语法(类似于Vue 的写法),更加严格和具有语义性,可以在编译的过程中就进行优化操作。

1
2
3
4
5
6
7
<template>
<div>
<p>{{name}}</p>
<p>8888</p>
<p>8888</p>
</div>
</template>

编译器针对这块template代码可以很清楚地知道哪些代码是会变动,哪些代码不会变动。

Svelte实例代码

  • 小demo

App.svelte

1
2
3
4
5
6
7
<script>
import Button from './button.svelte'
let name = 'world';
</script>

<h1>Hello {name}!</h1>
<Button/>

button.svelte

1
2
3
4
5
6
7
8
9
10
<script>
let count = 0;
function handleClick() {
count += 1;
}
</script>

<button on:click={handleClick}>
Clicked {count} {count === 1 ? 'time' : 'times'}
</button>

  • $:响应式语句
1
2
let count = 0;
$: doubled = count * 2;

Svelte 中,以 $: 开头的语句就是响应式语句,Svelte 会自动分析响应式语句所依赖的变量,当依赖变量发生变化时,Svelte 就会重新执行相应的响应式语句。当 Svelte 看到任何带有 $: 前缀的语句时,它就知道要将右边的变量赋值给左边的变量,而不需要使用let将一个变量的值绑定到另一个变量;并且Svelte可以以响应式的方式运行任何语句。

1
2
3
4
5
6
7
8
9
$: console.log(`the count is ${count}`);
$: {
console.log(`the count is ${count}`);
alert(`I SAID THE COUNT IS ${count}`);
}
$: if (count >= 10) {
alert(`count is dangerously high!`);
count = 9;
}

但是Svelte的响应是基于赋值操作的,数组的 pushsplice 等操作不会触发响应式更新。

  • 接收Props
1
2
3
4
<script>
export let answer;
// export let answer = 'a mystery'; 初始化value
</script>
  • 生命周期

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    <script>
    import { onMount,onDestroy,beforeUpdate,afterUpdate,tick } from 'svelte';

    let photos = [];

    onMount(async () => {
    const res = await fetch(`https://jsonplaceholder.typicode.com/photos?_limit=20`);
    photos = await res.json();
    });

    onDestroy(() => alert('gg'));
    </script>
  • 逻辑判断
    由于HTML没有类似于逻辑判断的语法,因此Svelte加了个这个东西。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    <script>
    let user = { loggedIn: false };

    function toggle() {
    user.loggedIn = !user.loggedIn;
    }
    </script>

    {#if user.loggedIn}
    <button on:click={toggle}>
    Log out
    </button>
    {/if}

    {#if !user.loggedIn}
    <button on:click={toggle}>
    Log in
    </button>
    {/if}
    //或
    {#if user.loggedIn}
    <button on:click={toggle}>
    Log out
    </button>
    {:else}
    <button on:click={toggle}>
    Log in
    </button>
    {/if}
    //或
    {#if x > 10}
    <p>{x} is greater than 10</p>
    {:else if 5 > x}
    <p>{x} is less than 5</p>
    {:else}
    <p>{x} is between 5 and 10</p>
    {/if}
  • 遍历

    1
    2
    3
    4
    5
    {#each cats as cat}
    <li><a target="_blank" href="https://www.youtube.com/watch?v={cat.id}">
    {cat.name}
    </a></li>
    {/each}
  • await

    1
    2
    3
    4
    5
    6
    7
    {#await promise}
    <p>...waiting</p>
    {:then number}
    <p>The number is {number}</p>
    {:catch error}
    <p style="color: red">{error.message}</p>
    {/await}

demo

  • 事件绑定
    1
    2
    3
    4
    5
    6
    <button on:click|once={handleClick}>
    Click me
    </button>
    <button on:click={handleClick}>
    Click me
    </button>

自定义事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<script>
import Inner from './Inner.svelte';

function handleMessage(event) {
alert(event.detail.text);
}
</script>
<Inner on:message={handleMessage}/>


<script>
import { createEventDispatcher } from 'svelte';

const dispatch = createEventDispatcher();

function sayHello() {
dispatch('message', {
text: 'Hello!'
});
}
</script>
<button on:click={sayHello}>
Click to say hello
</button>
  • Store
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    store.js

    import { writable,readable,derived } from 'svelte/store';
    export const count = writable(0);//writable类型的store有update和set两种subscribe方法

    export const time = readable(new Date(), function start(set) {
    const interval = setInterval(() => {
    set(new Date());
    }, 1000);

    return function stop() {
    clearInterval(interval);
    };
    });
    //readable无法从外部进行更新,没有set()或update()方法。一旦设置了初始状态,便无法从外部进行修改。

    export const elapsed = derived(
    time,
    $time => Math.round(($time - 100*Math.random()) / 1000)
    );
    //derived允许您创建依赖于现有存储的值的新存储值

    app.svelte

    <script>
    import { count } from './stores.js';
    import Incrementer from './Incrementer.svelte';
    import Decrementer from './Decrementer.svelte';
    import Resetter from './Resetter.svelte';

    let count_value;

    const unsubscribe = count.subscribe(value => {
    count_value = value;
    });
    </script>

    <h1>The count is {count_value}</h1>

综上。

觉得不错的话可以打赏哦