【Svelte从入门到精通】展望篇——生态

837 阅读2分钟

尽管Svelte的生态环境和React、Vue这两大框架相比稍显得不够庞大,但对于基本的开发已经覆盖全面。为了展现其全面性,会继续从三大框架的各个方面进行对比。

对比

SvelteReactVue
cli旧版:svelte-cli
目前:Vite
create-react-appVue Cli
Vite
路由routify
svelte-spa-router
svelte-routing
react-routervue-router
状态管理svelte/storereduxvuex
pinia
SSRSvelteKitNext.jsNuxt
静态/文档SvelteKit
Elder.js
Next.js
Gatsby
Docusaurus
VuePress
VitePress
UI组件shadcn-svelte
svelte-material-ui
Flowbite Svelte
Melt UI
Ant Design
MUI
chakra
Element Plus
Ant Design Vue
Vant
测试svelte-testing-libraryreact-testing-library
Enzyme
vue-testing-library
Vue Test Utils
Vitest
dev toolsSvelte DevToolsReact Developer ToolsVue.js devtools
webpack loadersvelte-loaderbabel-loadervue-loader
Rollup pluginrollup-plugin-svelte@rollup/plugin-babelrollup-plugin-vue
Vite plugin@sveltejs/vite-plugin-svelte@vitejs/plugin-react@vitejs/plugin-vue
NativeSvelte NativeReact NativeWeex
小程序tarojs-plugin-svelteTarompvue
社区sveltesocietyreact communityvue community

Svelte 5

Svelte 宣布了一项新特性 "runes",这个特性将在 Svelte5 中大幅改变开发者的体验。Rune 是一种可以影响 Svelte 编译器的符号,Svelt5 中的 runes 使用函数语法实现,达到和现有的声明式语法等效的效果,如 $state 用于声明响应式状态。Rune 的引入,可以让你的 .svelte 文件之外的其他文件也拥有响应式能力。相较于现有的 store APIrune 可以更简单地处理更复杂的事物。

Runes

Svelte 5最大的改动便是引入了Runes。Runes是一组函数式的符号,无需额外引入,可以直接使用,是Svelte5语言的特性,目前有以下Runes,文章里会挑选比较重要的几个进行讲解:

  • $state
  • $derived
  • $effect
  • $props

$state

<script>
	let count = $state(0);
</script>

<button on:click={() => count++}>
click
</button>
{count}

对比之前的数据声明,多了$state

使用$state声明的数组可以直接操作了。

<script>
  const arr = $state([1,2]);

  const onAdd = () => {
    arr.push(1);
  }

  const onSub = () => {
    arr.pop();
  }
</script>

<p>
  <button on:click={onAdd}>增加</button>
  <button on:click={onSub}>减少</button>
</p>
数组:{arr.join(',')}

$derived

$derived接收一个参数,这个参数是一个没有副作用的表达式。

<script>
  let count = $state(0);
  let double = $derived(count * 2);

  const onClick = () => {
    count++;
  }
</script>

  
<button on:click={onClick}>更新</button><br />
count: {count}
double: {double}

我们可以传count * 2,但是不能传count++。 在Svelte4中,我们要声明一个派生属性,需在$: 里进行。

$effect

runs when the component is mounted, and again whenever count or doubled change,after the DOM has been updated.

因此,$effect相当于$: {}onMountafterUpdate的结合体。笔者对此改动表示热烈欢迎,因为本人始终觉得在有些框架中,一个组件对外提供一大串又丑又长的生命周期,着实加大了开发者的心智负担。

<script>
  let width = $state(10);

  $effect(() => {
    console.log('width改变', width);
  });
</script>

width: <input type="number" bind:value={width} />

$props

和明显,用来接收props的Runes。

<script>
  export let value;
</script>

子组件:{value}
<script>
  let { value } = $props();
</script>

子组件:{value}

Snippets

俗称片段。使用Snippets可以进行内容复用。

<script>
  let arr = $state([{
    name: 'carter',
    age: 18,
    gender: '男'
  }, {
    name: 'lily',
    age: 19,
    gender: '女'
  }]);
</script>

{#snippet person({ name, age, gender })}
  <p>
  <span>姓名:{name}</span>
  <span> 年龄:{age}</span>
  <span>性别:{gender}</span>
  </p>
{/snippet}

{#each arr as item, i}
{@render person(item)}
{/each}

使用{#snippet snippetName()}...{/snippet}来定义我们要复用的片段,使用{@render snippetName()}来复用定义好的片段。

在之前,如果我们要复用这一段代码,只能把它放入到另一个svelte文件中,当成组件来引用。

事件

事件监听

在演示Runes和Snippets时,笔者在使用到数据绑定时,仍旧使用的是Svelte4on:eventname的形式。其实在Svelte5中,关于方法的使用也有更新:从原来on:eventname的形式转变为oneventname的形式。

<script>
  const onClick = () => {
    console.log('click');
  }
</script>

- <button on:click={onClick}>click</button>
+ <button onclick={onClick}>click</button>

组件事件

使用$props()来接收方法。终于不用使用难用的createEventDispatcher了。

<script>
  let { onClick, onClick2 } = $props();
</script>

<button onclick={onClick}>click</button>
<button onclick={e => onClick2('hello svelte')}>click2</button>
<script>
  import Svelte5 from './Svelte5.svelte';
	
  const onClick = (event) => {
    console.log('event', event);
  }
	
  const onClick2 = (value) => {
    console.log('value', value);
  }
</script>

<Svelte5 {onClick} {onClick2} />

除了接收方法,我们还能接收插槽内容。没错,在Svelte5中,插槽的使用转而投向了jsx的写法,通过let { children } = $props()来接收插槽内容。

<script>
  let { children } = $props();
</script>

<div>
  <header>头部</header>
  <main>{@render children() }</main>
  <footer>底部</footer>
</div>
<script>
  import Svelte5 from './Svelte5.svelte';
</script>

<Svelte5>
  内容
</Svelte5>

这里的{@render ...}和后面介绍的Snippets有关。思考:如何接收具名插槽?

方法

untrack

<script>
  let width = $state(10);
  let height = $state(10);
  let area;

  $effect(() => {
    console.log('width or height change', width, height);
  });
</script>

width: <input type="number" bind:value={width} />,
height: <input type="number" bind:value={height} />

如果我们只想在width执行时输出console,那就需要不追踪height的依赖。

<script>
  import { untrack } from 'svelte';
	
  let width = $state(10);
  let height = $state(10);

  $effect(() => {
    console.log('width or height change', width, untrack(() => height));
  });
</script>

width: <input type="number" bind:value={width} />,
height: <input type="number" bind:value={height} />

mount

import { mount } from 'svelte';
import App from './App.svelte';

const app = mount(App, {
  target: document.querySelector('#app'),
  props: { some: 'property' }
});

Svelte4

import App from './App.svelte'

const app = new App({
  target: document.getElementById('app'),
})

export default app

更多详细内容参考Svelte5 抢先看

小结

本章我们学习了:

  • Svelte对比其他框架的生态优劣
  • Svelte5的新特性前瞻