
一、赋值
上一讲已经为大家讲了 Svelte
反应性的基础,它的声明方式与声明普通变量极为近似,对于初学者来说非常友好,本章将对反应性进行详尽讲述。
Svelete
的内核是一个强大的反应性系统,能够让 DOM
与你的应用程序状态保持同步,例如,事件响应。
App.svelte:
1 2 3 4 5 6 7 8 9 10 11 12 13
| <script> let count = 0;
function incrementCount() { } </script>
<button> Clicked {count} {count === 1 ? 'time' : 'times'} </button>
|
为了演示,我们首先需要添加一个事件处理器。将上面的 <button>
替换为:
1
| <button on:click={incrementCount}>
|
在 incrementCount
函数中,我们需要做的就是改变 count
的值:
1 2 3 4 5 6 7 8 9 10
| <script> let count = 0; function incrementCount() { count += 1; } </script>
<button on:click={incrementCount}> Clicked {count} {count === 1 ? 'time' : 'times'} </button>
|
实例:
所谓反应性,类比React
的state
或Vue
的 data
(实际上都是状态)这里推荐一个可以对比学习的网址:
二、声明
当组件的状态改变时,Svelte
会自动更新 DOM
。通常,组件状态的某些部分需要通过其它部分的计算而得出(例如 fullname
就是 firstname
和 lastname
的合体),并在 其它 部分更改时重新计算。
对于这些,我们有 响应式声明。他们看起来像这样:
1 2
| let count = 0; $: doubled = count * 2;
|
完整代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <script> let count = 0; $: doubled = count * 2;
function handleClick() { count += 1; } </script>
<button on:click={handleClick}> Clicked {count} {count === 1 ? 'time' : 'times'} </button>
<p>{count} doubled is {doubled}</p>
|
1
| 看来其有点陌生,不过别担心。上述是 (非常规)的 `JavaScript` 语句,`Svelte` 会将其解释为 “只要参考值变化了就重新运行此代码”。一旦看习惯了,你就再也戒不掉了。
|
我们在 HTML
标签内来使用 doubled:
1
| <p>{count} doubled is {doubled}</p>
|
当然,你可以在 HTML
标签内书写 {count * 2}
,而不必非得使用反应式声明的语法。但是,当你需要多次引用它们时,或者你需要的值依赖于 其它 响应式声明所计算的来的值时,响应式声明就变得特别有用。
三、语句
我们不仅提供了声明反应式的 值,我们还可以运行反应式的 语句。例如,当 count
的值改变时就输出到日志中:
1
| $: console.log('the count is ' + count);
|
你可以轻松地将一组语句组合成一个代码块:
1 2 3 4
| $: { console.log(`the count is ${count}`); alert(`I SAID THE COUNT IS ${count}`); }
|
你甚至可以将 $:
放在= if
代码块前面:
1 2 3 4
| $: if (count >= 10) { alert(`count is dangerously high!`); count = 9; }
|
完整示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <script> let count = 0;
$: if (count >= 10) { alert(`count is dangerously high!`); count = 9; }
function handleClick() { count += 1; } </script>
<button on:click={handleClick}> Clicked {count} {count === 1 ? 'time' : 'times'} </button>
|
四、更新数组和对象
Svelte
的响应性是由赋值触发的,因此使用诸如 push
、splice
等数组方法不会引起自动更新。
例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <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>
|
在此示例中,单击“添加数字”按钮调用 addNumber
函数,该函数将一个数字附加到数组中,但不会触发 sum
的重新计算。
解决此问题的一种方法是为自身分配数字以告诉编译器它已更改:
1 2 3 4
| function addNumber() { numbers.push(numbers.length + 1); numbers = numbers; }
|
您还可以使用 ES6
扩展语法更简洁地编写此代码
1 2 3
| function addNumber() { numbers = [...numbers, numbers.length + 1]; }
|
你可以使用类似的模式来替换 pop、shift、unshift 和 splice 方法。
赋值给数组和对象的 属性(properties) (例如,obj.foo += 1 或 array[i] = x)与对值本身进行赋值的方式相同。
1 2 3
| function addNumber() { numbers[numbers.length] = numbers.length + 1; }
|
但是,间接赋值 对诸如此类的引用…
1 2
| const foo = obj.foo; foo.bar = 'baz';
|
或者
1 2 3 4
| function quox(thing) { thing.foo.bar = 'baz'; } quox(obj);
|
都不会更新对 obj.foo.bar 的引用,除非使用 obj = obj 方式。
一个简单的经验法则:更新后的变量必须直接出现在赋值的左侧
。
总结
赋值——是触发 Svelte
反应性的核心,Svelte
编译器根据赋值来确定是否需要更新相应的值。
$ 符号是另一种十分强大的反应性声明,它类似 Vue
的 computed
属性,不仅支持普通表达式,还可以是大括号括起的语句,甚至是 if 语句。
需要注意的是,数组的 push、pop、shift、unshift、splice
方式,不会触发反应性,可以通过把处理后的数组赋值给数组自身来告诉svelte
需要更新。
对象的子属性单独拿出来更新,也不会触发反应性。
推荐对比学习网址