都快1202 年了,你還不知道 svelte?

目錄結構

  • 說在前面
  • 關於虛擬DOM
  • 業內大牛如何看待 svelte
  • 關於UI
  • svelte 與其餘框架javascript

    • 開始打包
    • 對比大小
    • 性能考覈
    • 對比性能
  • 使用svelte 模板
  • 下載依賴
  • 啓動項目
  • 打開頁面
  • 安裝ui
  • 簡單瞭解語法css

    • 綁定數據
    • 條件渲染
    • 循環渲染
    • 事件綁定
    • 組件html

      • 傳值
    • 動畫
    • 生命週期
  • 案例
  • 註解
  • 參考文獻

說在前面

svelte 不知道你們有沒有了解過,最近一次偶然刷文章,看到一篇《都快2020年,你還沒據說過SvelteJS?》 [0] 的文章,看了svelte與其餘框架的對比前端

svelte 中文 doc [1]vue

對比各框架開發的項目的尺寸java

對比各框架開發的項目的尺寸

對比各項目的 Lighthouse 性能評分node

對比各項目的 Lighthouse 性能評分

說實話屬實有點驚訝到我。 ** 真的假的?react

因而我抱着試試就試試的心態來作個評測人git

關於虛擬DOM

svelte 的做者 Rich Harris 在一篇名爲《虛擬DOM純粹是開銷》 [2] 的文章中指出,爲何不使用虛擬domgithub

虛擬dom的三個步驟

  1. 兩個快照都包含一個元素。在兩種狀況下都是<div>,這意味着咱們能夠保留相同的DOM節點
  2. 咱們列舉了新舊屬性上的全部屬性,<div>以查看是否須要更改,添加或刪除任何屬性。在這兩種狀況下,咱們都有一個屬性-aclassName的值爲"greeting"
  3. 降低到元素中,咱們看到文本已更改,所以咱們須要更新真實的DOM

而 svelte 直接跳過前面兩步,直接執行第三步

if (changed.name) {
  text.data = name;
}

這幾乎就是Svelte生成的更新代碼。與傳統的UI框架不一樣,Svelte是一種編譯器,它在構建時就知道應用程序中的狀況如何變化,而沒必要等着在運行時進行工做。

業內大牛如何看待 svelte

vue 的做者尤雨溪,在知乎回答了個 《如何看待 svelte 這個前端框架?》 [3] 問題

「svelte 的核心思想在於 經過靜態編譯來減小框架運行時的代碼

關於 UI

我覺着這兩個ui仍是比較不錯的

Material UI

https://sveltematerialui.com/

https://github.com/hperrin/sv...

SVELTESTRAP

https://sveltestrap.js.org/

https://github.com/bestguy/sv...

svelte 與其餘框架

老嚴閒來的時候找到了 一個叫作 Realworld 存儲庫中有24種conduit實現As ,也就是用來對比性能的以及大小的;

今天一塊兒來對比一下 vue/react/svelte 這三個框架的

  • 項目打包後壓縮包大小
  • 項目網頁性能分析對比

vue:https://github.com/gothinkste...

react:https://github.com/gothinkste...

svelte:https://github.com/sveltejs/r...

感興趣的同窗也能夠看看其餘框架 https://github.com/gothinkste...

開始打包

這三個項目,打包順序基本上在同一時間執行 npm run build,svelte 直接在我我眨眼的一瞬間打完包 ,啪 很快啊 (有點誇張~幾秒鐘)

靜靜的等待vue和react同時打包完以後,我開始進行統一壓縮靜態文件,壓縮格式爲zip

對比大小

排名以下

  1. svelte — 89.9 KB
  2. vue — 483 KB
  3. react — 490 KB

果真差距仍是確實如傳說同樣恐怖

性能考覈

嚴老溼本次使用 Chrome 的 Lighthouse (谷歌網頁性能分析工具) 來對比性能評分

全局安裝 lighthouse

npm install -g lighthouse

執行 (直接使用的對應的線上地址)

lighthouse https://realworld.svelte.dev/

這是我在下面所測試的截屏

vue

react

svelte

對比性能

性能得分排名以下:

  1. svelte — 83
  2. react — 52
  3. vue — 32

svelte 也是不負衆望 穩居第一

使用 svelte 模板

看到上面,每天被逼着作性能優化的同窗,激動起來了 ~ 那咱們一塊兒來簡單學習一下這個性能強悍的 svelte 吧

svelte 模板 [4] ,咱們直接使用一個模板來開工

git clone https://github.com/sveltejs/template
&
cd template-master

下載依賴

yarn install 
or 
npm install

下載完成以後,咱們看看目錄。老嚴的評價就是 簡潔

啓動項目

yarn dev
or
npm run dev

啓動完成以後

Your application is ready~! �

  - Local:      http://localhost:5000
  - Network:    Add `--host` to expose

打開頁面

地址欄輸入 http://localhost:5000

image-20201130113222571

咱們能夠看到這樣的一個頁面 hello world

安裝ui

這裏咱們使用 sveltestrap

npm install --save sveltestrap 
npm install --save bootstrap

在 main.js 中引入

import 'bootstrap/dist/css/bootstrap.min.css';

在頁面中引入組件

<script>
    import { Button } from "sveltestrap";
    const handleClick = () => alert("I warned you!");
</script>

<Button color="danger" on:click={handleClick}>Do Not Press</Button>

簡單瞭解語法

在學習以前我以爲有必要簡單瞭解一下其語法

綁定數據

在 vue 中咱們的變量須要寫在 data 中 ,而 svelte 語法更加貼合原生

<!-- vue -->
data() {
    return {
        name: 'hhh',
    };
}

<div>{{name}}</div>

svelte 綁定數據 ,svelte 動態綁定須要加上 {}

<script>
    import { Button } from "sveltestrap";
    // 定義數據
    let name = "hhh";
    let src = 'http://crazy-x-lovemysoul-x-vip.img.abc188.com/images/logo.png';
</script>
<!-- 綁定數據 -->
<!-- 若是kv一致只用寫一個 -->
<img {src} alt="">
<Button>{name}</Button>

條件渲染

vue 中有條件渲染 v-if v-else-if v-else ,svelte 也有

<script>
    let condition = 1;
</script>
{#if condition == 2}
    <p>悲</p>
{:else if condition == 1}
    <p>傷 </p>
{:else if condition == 0}
    <p>日</p>
{:else}
    <p>記</p>
{/if}

循環渲染

循環渲染列表

<script>
    // 定義變量
    let news = [
        { id: 1, title: '拜登呼籲必須中止把對手當敵人' },
        { id: 2, title: '江蘇響水致78死爆炸案一審宣判' },
        { id: 3, title: '嫦娥五號將擇機實施月面軟着陸' }
    ];
</script>


<ul>
    <!-- 有沒有點 ejs的感受 -->
    {#each news as {title}}
        <li>
            <a href="https://www.baidu.com/s?rsv_idx=1&wd={title}">
                {title}
            </a>
        </li>
    {/each}
</ul>


<style>
    ul,li{
        list-style: none;
    }
    a{
        color: #ff3e00;
    }
</style>

咋感受有點像 ejs 循環渲染呢 [5]呢?

事件綁定

svelte 中方法直接寫函數定義函數便可使用

<script>
    import { Button } from "sveltestrap";
    // 定義數據
    let name = "hhh",title = '標題';
    // 定義方法
    const handleClick = () => {
        name = "嚴老溼"
        title = "老嚴帶你入坑 svelte"
    };
</script>
<!-- on:click 綁定方法  {綁定動態值}-->
<Button color="danger" on:click={handleClick}>{name}</Button>
<h1>{title}</h1>

組件

組件是框架必不可少的一個功能

來看看 svelte 中如何建立一個組件吧

app.svelte

<script>
    // 直接引入組件便可使用 無需註冊
    import Child from './components/child.svelte'
    let name = '我是你爹'
</script>

<div>
    {name}
    <Child></Child>
</div>

建立一個 child.svelte 頁面

<script>
    let title = '我是你兒子'
</script>

<div>{title}</div>

image-20201205140934477

那麼組件有了,咱們來看看組件傳值吧!

傳值

app.svelte

<script>
    import Child from './components/child.svelte'
    let name = '我是你爹'
    let childName = "狗剩"
</script>

<div>
    {name}
    <Child {childName}></Child>
</div>

child.svelte

<script>
    export let childName;
</script>

<div>爹給我取的名字是 {childName}</div>

剛剛咱們是簡單的單一傳值

接下來咱們傳一個對象試試

app.svelte

<script>
    import Child from './components/child.svelte'
    let name = '我是你爹'
    let aboutMe = {
        name:'狗剩',
        age:18,
        gender:'man'
    }
</script>

<div>
    {name}
    <!-- 經過... 展開 aboutMe -->
    <Child {...aboutMe}></Child>
</div>

child.svelte

<script>
    export let name,gender,age;
</script>

<div>我取的名字是 {name}</div>
<div>我取的年齡是 {age}</div>
<div>我取的性別是 {gender}</div>

那這多費勁吶?還須要一個個接收。有一話叫存在即合理

動畫

在官方 api 中提到 svelte 提供了一些動畫效果出來給你們使用

咱們直接使用官方示例 淡入淡出動畫

<script>
    import { fade } from 'svelte/transition';
    let visible = true;
</script>

<label>
    <input type="checkbox" bind:checked={visible}>
    visible
</label>

{#if visible}
    <p transition:fade>
        Fades in and out
    </p>
{/if}

生命週期

在 svelte 中的生命週期有onMount 、beforeUpdate 、afterUpdate 、afterUpdate 下面老嚴依次給你們夥列出來

  • onMount (掛載後)

onMount函數做爲將component掛載到DOM後當即執行的回調。它必須在component初始化期間被調用(但沒必要位於component內部;能夠從外部模塊調用它)。

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

    onMount(() => {
        console.log('the component has mounted');
    });
</script>

若是須要onMount返回一個函數,則在卸載 component 時調用該函數。

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

    onMount(() => {
        const interval = setInterval(() => {
            console.log('beep');
        }, 1000);

        return () => clearInterval(interval);
    });
</script>
  • beforeUpdate (更新前)

beforeUpdate任何狀態更改後組件更新以前,回調函數會當即運行。第一次回調運行將在初始onMount以前.

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

    beforeUpdate(() => {
        console.log('the component is about to update');
    });
</script>
  • afterUpdate (更新後)

afterUpdate在組件更新後當即運行回調

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

    afterUpdate(() => {
        console.log('the component just updated');
    });
</script>
  • onDestroy(銷燬後)

在組件卸載後運行回調。在onMount、beforeUpdate、afterUpdate和onDestroy中,這是惟一一個在服務器端組件中運行的組件。4

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

    onDestroy(() => {
        console.log('the component is being destroyed');
    });
</script>

案例

老嚴逛着逛着 正好看到一個 官方示例的 to do list 原本還想着說帶你們作,那既然有現成的,將就一下

沒有什麼框架是寫一個 todolist 還學不會的 ,老嚴在代碼裏面也加了一些代碼註釋

由於樣式代碼 太多,咱們先上效果圖再看代碼

<script>
    import { quintOut } from 'svelte/easing';
    import { crossfade } from 'svelte/transition';
    import { flip } from 'svelte/animate';
    // 動畫
    const [send, receive] = crossfade({
        duration: d => Math.sqrt(d * 200),

        fallback(node, params) {
            const style = getComputedStyle(node);
            const transform = style.transform === 'none' ? '' : style.transform;
            return {
                duration: 600,
                easing: quintOut,
                css: t => `
                    transform: ${transform} scale(${t});
                    opacity: ${t}
                `
            };
        }
    });

    let uid = 1;
    // 默認數據
    let todos = [
        { id: uid++, done: false, description: 'write some docs' },
        { id: uid++, done: false, description: 'start writing blog post' },
        { id: uid++, done: true,  description: 'buy some milk' },
        { id: uid++, done: false, description: 'mow the lawn' },
        { id: uid++, done: false, description: 'feed the turtle' },
        { id: uid++, done: false, description: 'fix some bugs' },
    ];
    // 新增待辦
    function add(input) {
        const todo = {
            id: uid++,
            done: false,
            description: input.value
        };

        todos = [todo, ...todos];
        input.value = '';
    }
    // 刪除方法
    function remove(todo) {
        todos = todos.filter(t => t !== todo);
    }
    // 選中方法
    function mark(todo, done) {
        todo.done = done;
        remove(todo);
        todos = todos.concat(todo);
    }
</script>

<div class='board'>
    <!-- 點擊回車執行add  -->
    <input
        placeholder="what needs to be done?"
        on:keydown={e => e.which === 13 && add(e.target)}
    >
    <!-- 代辦 -->
    <div class='left'>
        <h2>todo</h2>
        {#each todos.filter(t => !t.done) as todo (todo.id)}
            <label
                in:receive="{{key: todo.id}}"
                out:send="{{key: todo.id}}"
                animate:flip
            >
                <!-- 選中表明已作完 -->
                <input type=checkbox on:change={() => mark(todo, true)}>
                {todo.description}
                <!-- 刪除 -->
                <button on:click="{() => remove(todo)}">remove</button>
            </label>
        {/each}
    </div>
    <!-- 已完成 -->
    <div class='right'>
        <h2>done</h2>
        {#each todos.filter(t => t.done) as todo (todo.id)}
            <label
                class="done"
                in:receive="{{key: todo.id}}"
                out:send="{{key: todo.id}}"
                animate:flip
            >
                <!-- 修改狀態爲代辦 -->
                <input type=checkbox checked on:change={() => mark(todo, false)}>
                {todo.description}
                <!-- 刪除 -->
                <button on:click="{() => remove(todo)}">remove</button>
            </label>
        {/each}
    </div>
</div>

<style>
    .board {
        display: grid;
        grid-template-columns: 1fr 1fr;
        grid-gap: 1em;
        max-width: 36em;
        margin: 0 auto;
    }

    .board > input {
        font-size: 1.4em;
        grid-column: 1/3;
    }

    h2 {
        font-size: 2em;
        font-weight: 200;
        user-select: none;
        margin: 0 0 0.5em 0;
    }

    label {
        position: relative;
        line-height: 1.2;
        padding: 0.5em 2.5em 0.5em 2em;
        margin: 0 0 0.5em 0;
        border-radius: 2px;
        user-select: none;
        border: 1px solid hsl(240, 8%, 70%);
        background-color:hsl(240, 8%, 93%);
        color: #333;
    }

    input[type="checkbox"] {
        position: absolute;
        left: 0.5em;
        top: 0.6em;
        margin: 0;
    }

    .done {
        border: 1px solid hsl(240, 8%, 90%);
        background-color:hsl(240, 8%, 98%);
    }

    button {
        position: absolute;
        top: 0;
        right: 0.2em;
        width: 2em;
        height: 100%;
        background: no-repeat 50% 50% url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23676778' d='M12,2C17.53,2 22,6.47 22,12C22,17.53 17.53,22 12,22C6.47,22 2,17.53 2,12C2,6.47 6.47,2 12,2M17,7H14.5L13.5,6H10.5L9.5,7H7V9H17V7M9,18H15A1,1 0 0,0 16,17V10H8V17A1,1 0 0,0 9,18Z'%3E%3C/path%3E%3C/svg%3E");
        background-size: 1.4em 1.4em;
        border: none;
        opacity: 0;
        transition: opacity 0.2s;
        text-indent: -9999px;
        cursor: pointer;
    }

    label:hover button {
        opacity: 1;
    }
</style>

當你能夠手動寫出這個todolist的時候,你就已經出師了,由於老嚴也就這點能耐 哈哈

最後代碼,我提交到了git 有須要的同窗能夠去下載噢

git clone git@github.com:CrazyMrYan/study-svelte.git

註解

[0] https://zhuanlan.zhihu.com/p/...

[1] https://www.firecat.run/

[2] https://svelte.dev/blog/virtu...

[3] https://www.zhihu.com/questio...

[4] https://github.com/sveltejs/t...

[5] https://ejs.bootcss.com/#docs

參考文獻

相關文章
相關標籤/搜索