[TOC]

官方文档 中文文档

svelte-template

npx degit sveltejs/template my-svelte-project
npm install
npm run dev

npm下载不了模板,可直接点击此处链接下载this .zip file

以下所示列子都可以在官方文档在线联系

基本语法

以下大多都是对比vue的语法写出的例子

// 1. {{ name }}
<script>
    let name = 'world';
</script>
<h1>Hello {name}!</h1>

// 2. v-bind
<script>
    let src = 'https://www.sveltejs.cn/tutorial/image.gif';
</script>
<img src={src} alt="A man dances.">
// name和value一致的情况下可简写为:
<img {src} alt="A man dances.">

// 3. v-html
<script>
    let string = `this string contains some <strong>HTML!!!</strong>`;
</script>

<p>{@html string}</p>  

// 4. v-on
<script>
    function handleClick(event) {
        console.log(event.type)
    }
</script>

<button on:click={handleClick}>
    Click
</button>

// 5. 事件修饰符 @click.once
<script>
    function handleClick() {
        alert('no more alerts')
    }
</script>

<button on:click|once={handleClick}>
    Click me
</button>

// 支持的所有修饰符列表: https://www.sveltejs.cn/tutorial/event-modifiers
// preventDefault
// stopPropagation
// passive 
// capture 
// once 

// 6. computed/watch (反应性能力-声明)
// 参考下章节

逻辑

if

// 1. if 
<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}

 // 2. if else if
<script>
    let x = 7;
</script>

{#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}
{/if}

个人而言非常讨厌handlebars/ejs的模板语法,vue的指令看起来更简洁

each(列表)

<script>
    let cats = [
        { id: 'J---aiyznGQ', name: 'Keyboard Cat' },
        { id: 'z_AbfPXTKms', name: 'Maru' },
        { id: 'OUtn3pvWmpg', name: 'Henri The Existential Cat' }
    ];
</script>

<h1>The Famous Cats of YouTube</h1>

<ul>
<!--     {#each cats as cat, index} -->
    {#each cats as {name, id}, index}
    <li><a target="_blank" href="https://www.youtube.com/watch?v={id}">
        {index + 1}: {name}
    </a></li>
{/each}
</ul>
  1. 遇到数组或类似于数组的对象 (即具有length 属性)。你都可以通过 each […iterable]遍历迭代该对象。
  2. index 作为第二个参数(key)
  3. 对象可解构
  4. 添加key值 官方文档

    await

    直接上官方文档

    反应性能力(Reactivity)

    个人理解也可以理解为vue的响应式 ```javascript // 1.赋值

// 2.声明

{count} doubled is {doubled}

// 3.语句(computed/watch)

// 4.更新数组和对象

// 和vue响应式原理不同的是:Svelte 的反应性是由赋值语句触发的 // 因此对于数组的push等方法是完全不生效的 // eg:

{numbers.join(‘ + ‘)} = {sum}

// 解决办法:变量必须赋值 function addNumber() { numbers.push(numbers.length + 1); numbers = numbers; }

// 总结:Svelte被更新的变量的名称必须出现在赋值语句的左侧

<a name="yJKdc"></a>
# 绑定
> 主要是表单绑定,可类比v-modle 即 v-bind:value 由于列子较多,就不一一赘述,可[参考文档](https://svelte.dev/tutorial/text-inputs)

```javascript
// 1. text or number or textarea
<script>
    let name = 'world';
</script>

<input bind:value={name}>

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

// 2. checkbox
<script>
    let yes = false;
</script>

<label>
    <input type=checkbox bind:checked={yes}>
    Yes! Send me regular email spam
</label>

{#if yes}
    <p>Thank you. We will bombard your inbox and sell your personal details.</p>
{:else}
    <p>You must opt in to continue. If you're not paying, you're the product.</p>
{/if}

<button disabled={!yes}>
    Subscribe
</button>

组件

// App.svelte
<script>
    import Nested from './Nested.svelte';
</script>
<p>This is a paragraph.</p>
<Nested/>
<style>
    p {
        color: purple;
        font-family: 'Comic Sans MS', cursive;
        font-size: 2em;
    }
</style>
// Nested.svelte
<p>This is another paragraph.</p>

和vue基本相似,但不同的是vue需要template包裹模板,同时只能有一个根元素。同时svelte的style天然支持scoped style

props

// App.svelte
<script>
    import Nested from './Nested.svelte';
    const pkg = {
        name: 'svelte',
        version: 3,
        speed: 'blazing',
        website: 'https://svelte.dev'
    };
</script>

<Nested answer={42}/>
// 1. 默认值
<Nested/>
// 2. 
<Nested name={pkg.name} version={pkg.version} speed={pkg.speed} website={pkg.website}/>
// 等同于 v-bind=obj 
<Nested {...pkg}/>
// Nested.svelte
<script>
    export let answer = 'default answer'; // props 默认值
    export let name;
    export let version;
    export let speed;
    export let website;
</script>

<p>The answer is {answer}</p>
<p>name: { name }</p>
<p>version: { version }</p>
<p>speed: { speed }</p>
<p>website: { website }</p>

可以看得出来与vue需要定义props属性不同的是:svelte 需要export 需要传递的属性名,同时不存在单项数据流

event

// App.svelte
<script>
    import Inner from './Inner.svelte';

    function handleMessage(event) {
        alert(event.detail.text);
        console.log(event)
    }
</script>

<Inner on:message={handleMessage}/>
// Inner.svelte
<script>
    import { createEventDispatcher } from 'svelte';

    const dispatch = createEventDispatcher();

    function sayHello() {
        dispatch('message', {
            text: 'Hello!'
        });
    }
</script>


<button on:click={sayHello}>
    Click to say hello
</button>

事件转发
dom事件转发

slot

基本和vue类似,不再赘述 直接看文档

生命周期

基本和vue类似有以下几个钩子函数:参考文档

  1. onMount
  2. onDestroy
  3. beforeUpdate
  4. afterUpdate
  5. tick

    其他特性

    不再赘述…直接看官方文档吧…

    基本原理

    Compiler-as-framework

    首先我们对官方模板进行一次打包,发现最后打出的bundl.js
    s_bundle.png
    行数只有200多行,大小只有5kb多一点,同时代码中有许多直接操作dom的方法,这也侧面说明了其Compiler-as-framework的理念。

在解释Compiler-as-framework的概念之前我们首先看其官网的一张图:
feature.png
中文翻译下来就是以下三个特性:

  1. 减少代码量:重复利用你所掌握的编程语言 - HTML、CSS 和 JavaScript,构建的组件无需依赖模板文件。
  2. 无虚拟 DOM:Svelte 将你的代码编译成体积小、不依赖框架的普通 JS 代码,让你的应用程序无论启动还是运行都变得迅速。
  3. 真正的反应能力:无需复杂的状态管理库,Svelte 为 JavaScript 自身添加反应能力。

那么何为Compiler-as-framework 呢?
首先我们要知道其解决的是什么问题,即我们使用的vue或者react等框架存在的问题:
那就是React和Vue都是基于runtime的框架。所谓基于runtime的框架就是框架本身的代码也会被打包到最终的bundle.js并被发送到用户浏览器。当用户在你的页面进行各种操作改变组件的状态时,框架的runtime会根据新的组件状态(state)计算(diff)出哪些DOM节点需要被更新,从而更新视图。基于runtime框架有什么缺点:那就是打包后的体积过大:以下是github的一个统计:
微信图片_20210725210157.png
以及RealWorld下的一个统计:
image.png
即我们在较少的业务代码情况下,我们常用的框架中最小的vue也要50多kb。那么如何减少runtime的代码,最好的办法当然就是不用runtime!这也正是Svelte要做的事情:它采用了Compiler-as-framework的理念,将框架的概念放在编译时而不是运行时。再具体点来说就是:当数据变化时Svelte直接通过JavaScript去改变原生DOM节点,没有框架那一系列diff和调度(React Fiber)的过程,而同时它又不像Jquery或者原生JS的写法那样将业务代码写的极其冗余复杂不宜维护,而是有更简易优雅的类似vue的语法。

再谈Virtual DOM

一直以来,可能大多数同学的第一印象就是采用虚拟dom(批量操作)比原生JS直接操作dom更高效,或者说它高效的一个原因它更智能:当组件状态变化时它会通过某些diff算法去计算出本次数据更新真实的视图变化,然后只改变“需要改变”的DOM节点。但事实上框架有时候会做很多无用功,这体现在很多组件会被“无缘无故”进行重渲染(re-render)。而Vitual DOM的高效是建立在diff算法上的,而要有diff一定要将组件重渲染才能知道组件的新状态和旧状态有没有发生改变,从而才能计算出哪些DOM需要被更新,但是Vue或者React本身很难避免无用的渲染。那么如何解决这些问题:最有效的解决方案就是不用Virtual DOM!其实作为一个框架要解决的问题是当数据发生改变的时候相应的DOM节点会被更新(reactive),Virtual DOM需要比较新老组件的状态才能达到这个目的,而更加高效的办法其实是数据变化的时候直接更新对应的DOM节点:

这就是Svelte采用的办法。Svelte会在代码编译的时候将每一个状态的改变转换为对应DOM节点的操作,从而在组件状态变化的时候快速高效地对DOM节点进行更新。根据js framework benchmark的统计,Svelte在对一些大列表操作的时候性能比React和Vue都要好。

更多关于Virtual DOM存在的问题,可以看一下官方virtual dom is pure overhead这篇文章。

而我本人对虚拟DOM的理解:其最大的优势并不是在操作dom而是跨平台的优势。

响应式原理

可能说响应式原理不够准确,更准确的来说是Svelte是如何追踪数据的变化来进行视图的更新。说白点:任何一个现代前端框架,都需要记住哪些数据更新了,根据更新后的数据渲染出最新的DOM。关于这块,由于时间关系并没有看Svelte的源码,只是通过这篇新兴前端框架 Svelte 从入门到原理了解到Svelte是使用位掩码(bitMask) 的技术来跟踪哪些值是脏的,即自组件最后一次更新以来,哪些数据发生了哪些更改来进行视图更新的。具体内容看参考此文章,本文就不再赘述了。

缺点及其应用场景

关于最大的缺点我觉得就是其生态环境不太好比如没有像AntD那样成熟的UI库了,应用场景就是编译可独立分发的 Web Components说或者一些业务量较小的SDK代码,关于这点尤大大本人在知乎上的回答可以说是很客观准确了,具体参考这篇回答:如何看待 svelte 这个前端框架

参考文档

都快2020年,你还没听说过SvelteJS?
新兴前端框架 Svelte 从入门到原理
如何看待 svelte 这个前端框架