Svelte从入门到精通——生态
发表于 阅读时长7分钟
目录
尽管 Svelte 的生态环境和 React、Vue 这两大框架相比稍显得不够庞大,但对于基本的开发已经覆盖全面。为了展现其全面性,会继续从三大框架的各个方面进行对比。
对比
Svelte 5
Svelte 宣布了一项新特性 "runes",这个特性将在 Svelte5 中大幅改变开发者的体验。Rune 是一种可以影响 Svelte 编译器的符号,Svelt5 中的 runes 使用函数语法实现,达到和现有的声明式语法等效的效果,如 $state 用于声明响应式状态。Rune 的引入,可以让你的 .svelte 文件之外的其他文件也拥有响应式能力。相较于现有的 store API,rune 可以更简单地处理更复杂的事物。
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
countordoubledchange,after the DOM has been updated.
因此,$effect相当于$: {}和onMount、afterUpdate的结合体。笔者对此改动表示热烈欢迎,因为本人始终觉得在有些框架中,一个组件对外提供一大串又丑又长的生命周期,着实加大了开发者的心智负担。
<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 的新特性前瞻