简体   繁体   English

Svelte:动态语句中的代码不会更新组件

[英]Svelte : code in dynamic statement doesn't update components

I have three components: App, Keyboard and Key.我有三个组件:应用程序、键盘和键。

Keyboard component loads multiple Key components based on a variable "keys" with such structure: { char: string, isPressed: boolean }[] Key component has a boolean pressed prop that is used among other things for styling.键盘组件基于具有以下结构的变量“keys”加载多个 Key 组件: { char: string, isPressed: boolean }[] Key 组件有一个 boolean pressed的道具,用于造型。

I'd like to ba able to reset all those isPressed properties from the App component and get the view updated accordingly when some keys are pressed.我希望能够从 App 组件中重置所有这些isPressed属性,并在按下某些键时相应地更新视图。 With Vue.js I might have used a global event, here I tried with binded props and dynamic statements.使用 Vue.js 我可能使用了全局事件,这里我尝试使用绑定道具和动态语句。 So I have a dynamic statement in Keyboard component that executes when I want but works only until you press another key.所以我在键盘组件中有一个动态语句,它在我想要的时候执行,但只有在你按下另一个键之前才有效。 The funny thing is that it's working fine when I use the "clear" button.有趣的是,当我使用“清除”按钮时它工作正常。

I made a repl here: https://svelte.dev/repl/b7c11d9f0e494195884be0994387ba4c?version=3.35.0我在这里做了一个repl: https://svelte.dev/repl/b7c11d9f0e494195884be0994387ba4c?version=3.35.0

App应用程序

<main>
  <Keyboard on:pressed-change="{checkKeys}"
            bind:clear={clear} />
</main>

<script>
import Keyboard from './Keyboard.svelte';

let clear = false;
const text = 'AC'; 

function checkKeys({ detail: keys }) {
    console.log('check keys')
  if (keys.sort().join('') === text) {
        console.log('clear')
    clear = true;
  }
}
</script>

Keyboard键盘

<main>
  <div>
    <section class="keys">
      {#each keys as { char, isPressed }, i}
        <Key char="{char}"
             bind:pressed={isPressed}
             on:key-press={handleKeyPress} />
      {/each}
    </section>

    <section>
      { pressed.join(' | ') }
    </section>
    <button on:click={clearKeyboard}>
      clear
    </button>
  </div>
</main>

<script>
import { createEventDispatcher } from 'svelte';
import Key from './Key.svelte';

export let clear;
let pressed = [];

const dispatch = createEventDispatcher();
    
let keys = [
    { char: "A", isPressed: false },
  { char: "B", isPressed: false },
  { char: "C", isPressed: false },
  { char: "D", isPressed: false },
  { char: "E", isPressed: false },
  { char: "F", isPressed: false },
  { char: "G", isPressed: false },
];

function handleKeyPress({ detail: char }) {
  const keyIndex = pressed.indexOf(char)
  if (keyIndex >= 0) {
    const tempArr = [...pressed];
    tempArr.splice(keyIndex, 1);
    pressed = tempArr;
    return;
  }
  pressed = [...pressed, char];
}

function clearKeyboard() {
  console.log('clear keyboard');
  keys = keys.map(key => ({ ...key, isPressed: false }));
  pressed = [];
}

$: if (clear) {
  clearKeyboard()
  clear = false;
}
$: dispatch('pressed-change', pressed);
</script>

Key钥匙

<div class="key"
     class:pressed
     on:click="{ press }">
  { char }
</div>

<script>
import { createEventDispatcher } from 'svelte';

export let char;
export let pressed;

const dispatch = createEventDispatcher();

function press() {
  pressed = !pressed;
  dispatch('key-press', char);
}
</script>

Thanks for the help.谢谢您的帮助。

The issue you are having is caused by some race condition somewhere.您遇到的问题是由某处的某些竞争条件引起的。

Svelte does not entirely 'instantaneously' update the DOM but rather schedules changes in batches. Svelte 并不完全“即时”更新 DOM,而是分批安排更改。 What is happening in your code is that the code setting the key to be pressed is conflicting with a similar signal 'unsetting' it.您的代码中发生的情况是设置要按下的键的代码与“取消设置”它的类似信号冲突。

You can tell Svelte to explicitly wait until after the currently scheduled changes have been applied by using await tick() (the tick is when Svelte renders to the DOM)您可以使用await tick()告诉 Svelte 显式等待,直到应用当前计划的更改之后(tick 是 Svelte 渲染到 DOM 的时间)

import { tick } from 'svelte'

async function clearKeyboard() {
  await tick()
  console.log('clear keyboard');
  keys = keys.map(key => ({ ...key, isPressed: false }));
  pressed = [];
}

In the code above, first the current changes will be applied, then the keys are all set to false.在上面的代码中,首先将应用当前更改,然后将键全部设置为 false。

You can visualize what is happening if you add a delay in the mix, by adding the following line just after await tick()如果您在混合中添加延迟,您可以通过在await tick()之后添加以下行来可视化正在发生的情况

await new Promise(res => setTimeout(res, 2000)) // will pause execution for two seconds

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM