Svelte 前端框架探索

Svelte 的做者也是 rollup 的做者 Rich Harris,前端界的轮子哥。sevlte 项目首次提交于 2016 年 11 月 16 日,目前版本是 3.6.1(2019-06-27),v3 版本进行了大改动,跟以前的版本有很大的差异(v一、v2 版本 API 用法跟 vue 很像,v3 彻底属于本身的风格)。html

看下 2016-12-02,尤雨溪大神对此框架的评价(固然已通过时了,可是核心的思想仍是一致的):前端

这个框架的 API 设计是从 Ractive 那边传承过来的(天然跟 Vue 也很是像),但这不是重点。Svelte 的核心思想在于『经过静态编译减小框架运行时的代码量』。举例来讲,当前的框架不管是 React Angular 仍是 Vue,无论你怎么编译,使用的时候必然须要『引入』框架自己,也就是所谓的运行时 (runtime)。可是用 Svelte 就不同,一个 Svelte 组件编译了之后,全部须要的运行时代码都包含在里面了,除了引入这个组件自己,你不须要再额外引入一个所谓的框架运行时!

什么是 Svelte?

Svelte 跟 vue 和 react同样,是一个数据驱动组件框架。可是也有很大的不一样,它是一个运行时框架,无需引入框架自己,同时也没用到虚拟 DOM(运行时框架特性决定了这个框架跟虚拟 DOM 无缘)。vue

Svelte runs at build time, converting your components into highly efficient imperative code that surgically updates the DOM. As a result, you're able to write ambitious applications with excellent performance characteristics.

虽然没使用到虚拟 DOM,但同样能够达到出色的性能,并且对开发者编写代码是十分便捷。react

与 React 和 Vue 有和不一样?

那么咱们先看下 svelte 的由于意思:苗条的。苗条的框架正是做者的初始目的,苗条包括代码编写量、打包大小等等。webpack

总结一下这个框架的优点,即做者开发新框架的目的。git

  • 静态编译,无需引入框架自身

    一个 Svelte 组件是静态编译,全部须要的运行时代码都包含在里面了,除了引入这个组件自己,你感受不到框架存在。github

  • 编写更少代码

    svelte 模板提供一些简便的用法,在维护和编写上都变得更简单,代码量更少(维护的代码),这些模板会编译为最终的js 代码。web

  • 只会打包使用到的代码

    即 tree shaking,这个概念原本也是做者首先提出来的,webpack 是参考了 rollup。前端框架

  • 无需虚拟 DOM 也可进行响应式数据驱动
  • 更便捷的响应式绑定

    既有响应式数据的优势,v3 版本也解决了 vue 数据绑定缺点,用起来十分方便。app

简单用法对比

react hook

import React, { useState } from 'react';
export default () => {
  const [a, setA] = useState(1);
  const [b, setB] = useState(2);
  function handleChangeA(event) {
    setA(+event.target.value);
  }
  function handleChangeB(event) {
    setB(+event.target.value);
  }
  return (
    <div>
      <input type="number" value={a} onChange={handleChangeA}/>
      <input type="number" value={b} onChange={handleChangeB}/>
      <p>{a} + {b} = {a + b}</p>
    </div>
  );
};

vue

<template>
  <div>
    <input type="number" v-model.number="a">
    <input type="number" v-model.number="b">
    <p>{{a}} + {{b}} = {{a + b}}</p>
  </div>
</template>

<script>
  export default {
    data: function() {
      return {
        a: 1,
        b: 2
      };
    }
  };
</script>

svelte

<script>
  let a = 1;
  let b = 2;
</script>

<input type="number" bind:value={a} />
<input type="number" bind:value={b} />
<p>{a} + {b} = {a + b}</p>

都不用多说,一眼就看出来,svelte 简单多了。

为何不使用虚拟 DOM?

在 react 和 vue 盛行的时代,你会据说虚拟 DOM 速度快,并且还可能被灌输一个概念,虚拟 DOM 的速度比真实 DOM 的速度要快。

因此若是你有这个想法,那么你确定疑惑 svelte 没用到虚拟 DOM,它的速度为何会快?

其实虚拟 DOM 并非何时都快,看下粗糙的对比例子。

对比例子

这里并无直接统计渲染的时间,经过不少条数据咱们就能够感觉出来他们直接的性能。特别是点击每条数据的时候,明显感受出来(因为是在线上的例子,因此首次渲染速度不许确,主要看点击的响应速度)。

固然这仅仅是在 50000 条数据下的测试,对比一下框架所谓的速度,实际的状况下咱们是不会一次性展现这么多数据的。因此在性能还可行的状况下,更多的选择是框架所带来的的便利,包括上手难度、维护难度、社区大小等等条件。

svelte

https://svelte.dev/repl/367a2...

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

  const  = [];
  for (let i = 0; i < 50000; i++) {
    list.push(i);
  }
  const beginTime = +new Date();
  let name = "world";
  let data = list;
  function click(index) {
    return () => {
      data[index] = "test";
    };
  }
  onMount(() => {
    const endTime = +new Date();
    console.log((endTime - beginTime) / 1000, 1);
  });
</script>

{#each data as d, i}
  <h1 on:click={click(i)}>
    <span>
      <span>
        <span>
          <span>Hello {name} {i} {d}!</span>
        </span>
      </span>
    </span>
  </h1>
{/each}

vue

http://jsrun.net/kFyKp/edit

<div id="component-demo" class="demo">
  <div v-for="(d, i) in list" @click="click(i)"> 
    <span>
      <span> 
        <span>
          <span>
            Hello {{name}} {{i}} {{d}}!
          </span>
        </span>
      </span>
    </span>
  </div>
</div>
const list  = []
for(let i = 0; i < 50000; i++) {
  list.push(i);
}
const beginTime = +new Date();
new Vue({
  el: '#component-demo',
  data: {
    list: list,
    name: 'Hello'
  },
  methods:{
    click(index){
      const list = new Array(50000);
      list[index] = 'test'
      this.list = list
    }
  },
  mounted(){
    const endTime = +new Date();
      console.log((endTime - beginTime) / 1000,1);
  }
})

react

http://jsrun.net/TFyKp/edit

const list  = []
for(let i = 0; i < 50000; i++) {
  list.push(i);
}
class App extends React.Component {
  constructor(props){
    super(props);
    this.state = {
      list
    } 
  }
  click(i) {
    return ()=>{
      list[i] = 'test'
      this.setState({
        list,
      })
    }
  }
  render() {
    return (
      <div>
        {this.state.list.map((v,k)=>{
          return(
            <h1 onClick={this.click(k)}>
              <span>
                <span>
                  <span>
                    <span>
                      Hello wolrd {k} {v}!
                    </span>
                  </span>
                </span>
              </span>
            </h1>
          )
        })}
      </div>
    )
  }
}

function render() {
  ReactDOM.render(
    <App />,
    document.getElementById('root')
  );
}

render();

总结

首先虚拟 DOM 不是一个功能,它只是实现数据驱动的开发的手段,没有虚拟 DOM 咱们也能够实现数据驱动的开发方式,svelte 正是作了这个事情。

单纯从上面的对比例子来看,svelte 的速度比虚拟 DOM 更快(不一样框架虚拟 DOM 实现会有差异)。虽然没有进行更深层次的对比,可是若是认为虚拟 DOM 速度快的观点是不彻底对的,应该说虚拟 DOM 能够构建大部分速度还能够的 Web 应用。

Svelte 有哪些好用的特性?

  • 彻底兼容原生 html 用法

    编写代码是那么的天然,以下面就是一个组件。

    <script>
      const content = 'test';
    </script>
    <div>
      { test }
    </div>
  • 响应式也是那么的天然

    <script>
        let count = 0;
        function handleClick () {
            // calling this function will trigger an
            // update if the markup references `count`
            count = count + 1;
        }
    </script>
    <button on:click="handleClick">+1</button>
    <div>{ count }</div>
  • 表达式也能够是响应式的

    这个就牛逼了,更加的天然,这种特性只有静态编译才能作到,这个就是 svelte 目前独有的优点。

    <script>
        let numbers = [1, 2, 3, 4];
        function addNumber() {
            numbers.push(numbers.length + 1);
        }
        $: sum = numbers.reduce((t, n) => t + n, 0);
    </script>
    <p>{numbers.join(' + ')} = {sum}</p>
    <button on:click={addNumber}>Add a number</button>
  • 自动订阅的 svelte store

    这个其实就是订阅发布模式,不过 svelte 提供了自身特有的便捷的绑定方式(自动订阅),用起来是那么的天然,那么的爽。

    这种特性只有静态编译才能作到,这个就是 svelte 目前独有的优点。

    stores.js

    import { writable } from 'svelte/store';
    export const count = writable(0);

    A.svelte

    <script>
        import { count } from './stores.js';
    </script>
    <h1>The count is {$count}</h1>

    B.svelte

    <script>
        import { count } from './stores.js';
      function increment() {
            $count += 1;
        }
    </script>
    <button on:click={increment}>增长</button>
  • 全部组件均可以单独使用

    能够直接在 react、vue、angular 等框架中使用。

    // SvelteComponent.js 是已经编译后的组件
    import SvelteComponent from './SvelteComponent';
    
    const app = new SvelteComponent({
        target: document.body,
        props: {
            answer: 42
        }
    });

Svelte 有什么缺点?

svelte 是一个刚起步不久的前端框架,不管在维护人员仍是社区上都是大大不如三大框架,这里列举一下本人认为的 svelte 存在的缺点。

  • props 是可变的

    固然这也是这个框架故意这样设计的,这样 props 也是能够响应式的。

    <script>
      export let title;
      title = '前缀' + title
    </script>
    <h1>
      { title }
    </h1>
  • props 目前没法验证类型

    <script>
      export let propOne;
      export let propTwo = 'defaultValue';
    </script>
  • 没法经过自定义组件自己直接访问原生 DOM

    须要利用 props 的双向绑定特性,这就可能致使深层次组件的须要层层传递 DOM 对象(是子父传递,不是父子传递)。

    App.svelte

    <script>
      export let customDOM;
    </script>
    <A bind:dom={customDOM} />
    <!--bind:this 是无用的,只有再原生才有用-->

    A.svelte

    <script>
      export let dom;
    </script>
    
    <div bind:this={dom}>
      test
    </div>
  • 只有组件才支持 svelte 的静态模板特性

    js 文件是不支持 sevelte 静态模板特性的,像下面这样是会报错的。

    import { count } from './stores.js';
    function increment() {
      $count += 1;
    }
  • 组件不支持 ts 用法

    找了一下,没找到能够支持 ts 的解决方案,若是有解决方案能够评论下。


学习和总结文章同步发布于 https://github.com/xianshanna...,有兴趣能够关注一下,一块儿学习和进步。
相关文章
相关标签/搜索