Runes
#state
svelte 的状态,横向对比 Vue 的 ref,react 的 state
和 Vue React 不同的是 svelte 的值可以直接修改,UI即可响应,并且 $state 深度响应,你可以使用对象或者数组的 api 来更改值,如果不想深度响应就用 $state.raw
| 12
 3
 4
 
 | let a = $state([1,2,3])let b = $state.snapshot([1,2,3])
 console.log("代理的", a);
 console.log("静态的", b);
 
 | 

使用 $state.snapshot 不会被代理
$derived
| 12
 3
 4
 
 | <script>let count = $state(0);
 let doubled = $derived(count * 2);
 </script>
 
 | 
计算属性,当计算过程中的 state 值发生变化会重新计算,使用 $derived 计算不能传入带有副作用的计算表达式,并且在传入的计算表达式中不能修改 state 的值
如果计算过程有点复杂,无法用一个表达式解决问题,还可以使用 $derived.by 支持传入一个有返回值 function,
$effect
$effect 会在组件安装到 DOM 后执行,$effect 不是必须放在最顶层,他可以放在任何地方。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 
 | <script>let count = $state(0);
 let milliseconds = $state(1000);
 
 
 function testEffect () {
 $effect(() => {
 const interval = setInterval(() => {
 count += 1;
 }, milliseconds);
 
 return () => {
 clearInterval(interval);
 };
 });
 }
 testEffect()
 </script>
 
 <h1>{count}</h1>
 
 | 
这么写虽然没什么意义,但可以证明 $effect 即使在一个 function 里也不会有任何问题
$effect 会自动识别内部的 $state、$props、$derived 并作为依赖项,当他们更新时 $effect 会重新执行
$effect 可以返回一个 function,该 function 会在销毁时执行,不过以下这种情况
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 
 | <script>let count = $state({
 name: 'jack'
 });
 
 $effect(() => {
 console.log(count);
 })
 </script>
 
 <h1>{count.name}</h1>
 <button onclick={() => count.name = 'lucy'}>click</button>
 
 | 
当点击 button 更改 state 的 name 时,$effect 是没办法识别到深层的更新的,处理这个问题有两种方式,第一种就是直接在 $effect 使用 count.name ,另外一种就是使用 $derived 计算属性
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 
 | <script>let count = $state({
 name: 'jack'
 });
 let name = $derived(count.name)
 $effect(() => {
 console.log(name);
 })
 </script>
 
 <h1>{count.name}</h1>
 <button onclick={() => count.name = 'lucy'}>click</button>
 
 | 
还有一种情况是
| 12
 3
 4
 5
 6
 7
 
 | <script>$effect(() => {
 if (a || b) {
 console.log('inside if block');
 }
 });
 </script>
 
 | 
分别将 a 和 b 修改为 true ,但是打印只会执行一次,文档给出的解释是 effect 的执行效果取决于上次读到的值,大概就是说 a 已经为 true, b 不会对 effect 的执行产生更改,所以更改 b 不会触发 effect 执行
如果想在 DOM 更新前做点事,可以使用 $effect.pre,用法和 $effect 完全一致
另外 svelte 不建议直接在 $effect 同步状态,也就是修改 state 的值。
$props
用来接收父组件传来的值,该值一般来说不希望被修改,并且修改一般是没作用的,唯一特殊的情况是传来的值是 $state 值虽然被修改但是会抛出警告该值不是属于你的
$bindable
想允许自组件修改父组件的值,需要使用 $bindable
子组件
| 12
 3
 4
 5
 
 | <script lang="ts">let { value = $bindable() } = $props();
 </script>
 
 <input bind:value={value} />
 
 | 
父组件
| 12
 3
 4
 5
 6
 7
 
 | <script>import FancyInput from "../FancyInput.svelte";
 let message = $state('hello');
 </script>
 
 <FancyInput bind:value={message}/>
 <p>{message}</p>
 
 | 
如果想给 $bindable 设置一个默认值,直接给 $bindable 入参即可 $bindable(默认值)
$inspect
在参数发生变化时,会在控制台打印。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 
 | <script lang="ts">const obj = $state( {
 name: 'jack',
 age: 18,
 hobby: ['run', 'jump']
 })
 
 const addHobby = () => {
 obj.hobby.push('ball')
 }
 
 $inspect(obj.hobby)
 </script>
 
 <main>
 <div>{obj.hobby.join(',')}</div>
 <button onclick={addHobby}>addHobby</button>
 </main>
 
 | 
以上代码,在初始化时,$inspect 会输出 init 的值,当点击按钮进行更新时,会再次输出 update 的值

$inspect 执行返回一个 with 方法,该方法接收一个函数,函数有两个参数,一个是 type 初始化值为 init,更新时值为 update,第二个参数就是新的值
Template syntax
$snippet
使用 $snippet 声明代码片段,通过 @render 渲染使用代码片段
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 
 | {#snippet figure(image)}<figure>
 <img src={image.src} alt={image.caption} width={image.width} height={image.height} />
 <figcaption>{image.caption}</figcaption>
 </figure>
 {/snippet}
 
 {#each images as image}
 {#if image.href}
 <a href={image.href}>
 {@render figure(image)}
 </a>
 {:else}
 {@render figure(image)}
 {/if}
 {/each}ß
 
 |