svelte响应式核心——赋值

1、触发反应性的核心——赋值

Svelte 的核心是功能强大的响应式系统,用于使 DOM 与你的应用程序状态保持同步,例如响应事件。

<script>
  let count = 0;

  function handleClick() {
    // 事件处理代码写在这儿
  }
</script>

<button>
  Clicked {count} {count === 1 ? 'time' : 'times'}
</button>

为了演示它,我们首先需要连接一个事件处理程序。用以下内容替换 button 的开始标记:

<button on:click={handleClick}>

handleClick函数里,我们要编写代码更改count的值:

function handleClick() {
  count += 1;
}

Svelte 会针对这个赋值生成一些代码,该代码告诉 DOM 什么地方需要更新。

2、声明

当组件的状态更改时,Svelte 会自动更新 DOM。

通常,组件状态的某些部分需要从 其他 部分中计算得出(例如,fullname 系由 firstname 和 lastname 组合而成),并在每次更改时重新计算。

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

  let count = 0;
  $: doubled = count * 2;

完整代码:

<script>
  let count = 0;
  $: doubled = count * 2;

  function handleClick() {
    count += 1;
  }
</script>

<button on:click={handleClick}>
  Clicked {count} {count === 1 ? 'time' : 'times'}
</button>
如果这看起来有点陌生,请不要担心。它是 有效的(只不过没那么常见的)JavaScript,Svelte 能理解代码的意思:“只要任何引用的值发生更改,都要重新运行此代码”。一旦习惯了,你就再也回不了头了。

现在让我们在标记中再加一个doubled

<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>

当然,您可以只在标记中编写{count * 2},而不必使用响应式值。当您需要多次引用它们,或者您的值依赖于其他响应式的值时,响应式的值变得特别有用。

3、语句

我们不仅限于声明响应式的,我们还可以响应式地运行任意语句。 例如,只要更改count的值,我们就可以在控制台输出它的值:

<script>
  let count = 0;
  $: doubled = count * 2;
	
  // 只要更改count 的值,我们就可以在控制台输出它的值
  $: console.log(`the count is ${count}`);

  function handleClick() {
    count += 1;
  }
</script>

<button on:click={handleClick}>
  Clicked {count} {count === 1 ? 'time' : 'times'}
</button>

<p>{count} doubled is {doubled}</p>

你可以轻松将一组语句放在一个块里:

$: {
	console.log(`the count is ${count}`);
	alert(`I SAID THE COUNT IS ${count}`);
}

你甚至可以将$:放在一个if语句之前:

$: if (count >= 10) {
	alert(`count is dangerously high!`);
	count = 9;
}

4、更新数组和对象

Svelte 的响应性是由赋值触发的,因此使用诸如 pushsplice 等数组方法不会引起自动更新。

正如下方示例,点击按钮后界面不会有任何变化:

<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>

解决这个问题的其中一个办法是写一行多余的赋值给自身的表达式:

function addNumber() {
  numbers.push(numbers.length + 1);
  numbers = numbers;
}

但还有一个更常用的方案:

function addNumber() {
  numbers = [...numbers, numbers.length + 1];
}

你可以使用类似的办法来替代 popshiftunshift 和 splice

此外,赋值给数组和对象的 属性,例如 obj.foo += 1 或 array[i] = x,其实与直接赋值给自身的方式是一样的。

function addNumber() {
	numbers[numbers.length] = numbers.length + 1;
}

这里有一个简单的规则:更新变量的名称,必须出现在赋值的左侧。例如这个...

const foo = obj.foo; foo.bar = 'baz';

...不会更新对 obj.foo.bar 的引用,除非后面加上 obj = obj

例如下方的代码可以触发更新:

<script>
  let obj = { a: { b: { c: 10 } } }
</script>

<button on:click={ () => obj.a.b.c = 20 }>update</button>
<p>c = {obj.a.b.c}</p>

但是下方代码不会更新:

<script>
  let obj = { a: { b: { c: 10 } } }

  function handleClick() {
    let b = obj.a.b
    b.c = 20   // 不会触发更新

    // 除非有一个赋值操作,尝试取消下面这行注释:
    // obj = obj;
  }
</script>

<button on:click={ handleClick }>update</button>
<p>c = {obj.a.b.c}</p>

总结

赋值——是触发 Svelte 反应性的核心,Svelte 编译器根据赋值来确定是否需要更新相应的值。

除了常规的赋值语句外,$ 符号是另一种十分强大的反应性声明,它类似 Vue 的 computed 属性,不仅支持普通表达式,还可以是大括号括起的语句,甚至是 if 语句。

需要特别注意的是,数组的 push、pop、shift、unshift、splice 方式,不会触发反应性,可以通过两种方式来让 Svelte“认为”此处需要进行更新,第一种是使用数组的方法,然后使用看起来十分“呆板”的 numbers = numbers;第二种实际上也是赋值,不过它通过 ... 解构后重组了整个数组,然后赋值回了给 numbers 引用。

同样地,对象的子属性单独拿出来使用,也不会触发反应性。

猜你喜欢

转载自blog.csdn.net/ramblerviper/article/details/124923052