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

目录结构

  • 说在前面
  • 关于虚拟DOM
  • 业内大牛如何看待 svelte
  • 关于UI
  • svelte 与其他框架
    • 开始打包
    • 对比大小
    • 性能考核
    • 对比性能
  • 使用svelte 模板
  • 下载依赖
  • 启动项目
  • 打开页面
  • 安装ui
  • 简单了解语法
    • 绑定数据
    • 条件渲染
    • 循环渲染
    • 事件绑定
    • 组件
      • 传值
    • 动画
    • 生命周期
  • 案例
  • 注解
  • 参考文献

说在前面

svelte 不知道大家有没有了解过,最近一次偶然刷文章,看到一篇《都快2020年,你还没听说过SvelteJS?》 [0] 的文章,看了svelte与其他框架的对比

svelte 中文 doc [1]

对比各框架开发的项目的尺寸

对比各框架开发的项目的尺寸对比各框架开发的项目的尺寸

对比各项目的 Lighthouse 性能评分

对比各项目的 Lighthouse 性能评分对比各项目的 Lighthouse 性能评分

说实话属实有点惊讶到我。 ** 真的假的?

于是我抱着试试就试试的心态来做个评测人

关于虚拟DOM

svelte 的作者 Rich Harris 在一篇名为《虚拟DOM纯粹是开销》 [2] 的文章中指出,为什么不使用虚拟dom

虚拟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/svelte-material-ui

SVELTESTRAP

https://sveltestrap.js.org/

https://github.com/bestguy/sveltestrap

svelte 与其他框架

老严闲来的时候找到了 一个叫做 Realworld 存储库中有24种conduit实现As ,也就是用来对比性能的以及大小的;

今天一起来对比一下 vue/react/svelte 这三个框架的

  • 项目打包后压缩包大小
  • 项目网页性能分析对比

vue:https://github.com/gothinkster/vue-realworld-example-app

react:https://github.com/gothinkster/react-redux-realworld-example-app

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

感兴趣的同学也可以看看其他框架 https://github.com/gothinkster/realworld

开始打包

这三个项目,打包顺序基本上在同一时间执行 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-20201130113222571image-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 {srcalt="">
<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 = [
        { id1title'拜登呼吁必须停止把对手当敌人' },
        { id2title'江苏响水致78死爆炸案一审宣判' },
        { id3title'嫦娥五号将择机实施月面软着陆' }
    ];
</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-20201205140934477image-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({
  durationd => Math.sqrt(d * 200),

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

   };
  }
 });

 let uid = 1;
 // 默认数据
 let todos = [
  { id: uid++, donefalsedescription'write some docs' },
  { id: uid++, donefalsedescription'start writing blog post' },
  { id: uid++, donetrue,  description'buy some milk' },
  { id: uid++, donefalsedescription'mow the lawn' },
  { id: uid++, donefalsedescription'feed the turtle' },
  { id: uid++, donefalsedescription'fix some bugs' },
 ];
 // 新增待办
 function add(input{
  const todo = {
   id: uid++,
   donefalse,
   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-columns1fr 1fr;
  grid-gap1em;
  max-width36em;
  margin0 auto;
 }

 .board > input {
  font-size1.4em;
  grid-column1/3;
 }

 h2 {
  font-size2em;
  font-weight200;
  user-select: none;
  margin0 0 0.5em 0;
 }

 label {
  position: relative;
  line-height1.2;
  padding0.5em 2.5em 0.5em 2em;
  margin0 0 0.5em 0;
  border-radius2px;
  user-select: none;
  border1px solid hsl(2408%70%);
  background-color:hsl(2408%93%);
  color#333;
 }

 input[type="checkbox"] {
  position: absolute;
  left0.5em;
  top0.6em;
  margin0;
 }

 .done {
  border1px solid hsl(2408%90%);
  background-color:hsl(2408%98%);
 }

 button {
  position: absolute;
  top0;
  right0.2em;
  width2em;
  height100%;
  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-size1.4em 1.4em;
  border: none;
  opacity0;
  transition: opacity 0.2s;
  text-indent: -9999px;
  cursor: pointer;
 }

 label:hover button {
  opacity1;
 }
</style>

当你可以手动写出这个todolist的时候,你就已经出师了,因为老严也就这点能耐 哈哈

最后代码,我提交到了git 有需要的同学可以去下载噢

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

注解

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

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

[2] https://svelte.dev/blog/virtual-dom-is-pure-overhead

[3] https://www.zhihu.com/question/53150351

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

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

参考文献

  • https://www.firecat.run/docs
  • https://zhuanlan.zhihu.com/p/97825481
  • https://iiong.com/sveltejs-study-notes/

- END -

posted @ 2020-12-05 22:10  疯狂的严先生  阅读(183)  评论(0编辑  收藏