Svelte 官方入门教程(2) - 反应性

svelte cover

一、赋值

上一讲已经为大家讲了 Svelte 反应性的基础,它的声明方式与声明普通变量极为近似,对于初学者来说非常友好,本章将对反应性进行详尽讲述。

Svelete 的内核是一个强大的反应性系统,能够让 DOM 与你的应用程序状态保持同步,例如,事件响应。

App.svelte:

1
2
3
4
5
6
7
8
9
10
11
12
13
<script>
let count = 0;

function incrementCount() {
// event handler code goes here
}
</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>

实例:

所谓反应性,类比ReactstateVuedata(实际上都是状态)这里推荐一个可以对比学习的网址:

二、声明

当组件的状态改变时,Svelte 会自动更新 DOM。通常,组件状态的某些部分需要通过其它部分的计算而得出(例如 fullname 就是 firstnamelastname 的合体),并在 其它 部分更改时重新计算。

对于这些,我们有 响应式声明。他们看起来像这样:

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 的响应性是由赋值触发的,因此使用诸如 pushsplice 等数组方法不会引起自动更新。

例子

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 编译器根据赋值来确定是否需要更新相应的值。

  • $ 符号是另一种十分强大的反应性声明,它类似 Vuecomputed 属性,不仅支持普通表达式,还可以是大括号括起的语句,甚至是 if 语句。

  • 需要注意的是,数组的 push、pop、shift、unshift、splice 方式,不会触发反应性,可以通过把处理后的数组赋值给数组自身来告诉svelte需要更新。

  • 对象的子属性单独拿出来更新,也不会触发反应性。

推荐对比学习网址


Svelte 官方入门教程(2) - 反应性
http://yoursite.com/2022/07/11/svelte-tutorial-2/
作者
昂藏君子
发布于
2022年7月11日
许可协议