Svelte:动态语句中的代码不会更新组件
Svelte : code in dynamic statement doesn't update components
我有三个组件:应用程序、键盘和按键。
键盘组件根据具有这种结构的变量“键”加载多个按键组件:{ char: string, isPressed: boolean }[]
关键组件有一个布尔值 pressed
道具,除其他外还用于样式设置。
我希望能够从 App 组件重置所有这些 isPressed
属性,并在按下某些键时相应地更新视图。
使用 Vue.js 我可能使用了全局事件,在这里我尝试使用绑定的道具和动态语句。
所以我在键盘组件中有一个动态语句,它在我想要的时候执行,但只在你按下另一个键之前起作用。
有趣的是,当我使用“清除”按钮时它工作正常。
我在这里回复了:https://svelte.dev/repl/b7c11d9f0e494195884be0994387ba4c?version=3.35.0
应用程序
<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>
键盘
<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>
密钥
<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>
感谢您的帮助。
您遇到的问题是由某处的某些竞争条件引起的。
Svelte 不会完全 'instantaneously' 更新 DOM 而是安排分批更改。您的代码中发生的事情是设置要按下的键的代码与类似的信号冲突 'unsetting' 它。
您可以通过使用 await tick()
告诉 Svelte 明确等待,直到 在 应用当前计划的更改(打勾是 Svelte 呈现到 DOM)
import { tick } from 'svelte'
async function clearKeyboard() {
await tick()
console.log('clear keyboard');
keys = keys.map(key => ({ ...key, isPressed: false }));
pressed = [];
}
在上面的代码中,首先应用当前的更改,然后将键全部设置为 false。
如果在混音中添加延迟,您可以通过在 await tick()
之后添加以下行来可视化发生的情况
await new Promise(res => setTimeout(res, 2000)) // will pause execution for two seconds
我有三个组件:应用程序、键盘和按键。
键盘组件根据具有这种结构的变量“键”加载多个按键组件:{ char: string, isPressed: boolean }[]
关键组件有一个布尔值 pressed
道具,除其他外还用于样式设置。
我希望能够从 App 组件重置所有这些 isPressed
属性,并在按下某些键时相应地更新视图。
使用 Vue.js 我可能使用了全局事件,在这里我尝试使用绑定的道具和动态语句。
所以我在键盘组件中有一个动态语句,它在我想要的时候执行,但只在你按下另一个键之前起作用。
有趣的是,当我使用“清除”按钮时它工作正常。
我在这里回复了:https://svelte.dev/repl/b7c11d9f0e494195884be0994387ba4c?version=3.35.0
应用程序
<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>
键盘
<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>
密钥
<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>
感谢您的帮助。
您遇到的问题是由某处的某些竞争条件引起的。
Svelte 不会完全 'instantaneously' 更新 DOM 而是安排分批更改。您的代码中发生的事情是设置要按下的键的代码与类似的信号冲突 'unsetting' 它。
您可以通过使用 await tick()
告诉 Svelte 明确等待,直到 在 应用当前计划的更改(打勾是 Svelte 呈现到 DOM)
import { tick } from 'svelte'
async function clearKeyboard() {
await tick()
console.log('clear keyboard');
keys = keys.map(key => ({ ...key, isPressed: false }));
pressed = [];
}
在上面的代码中,首先应用当前的更改,然后将键全部设置为 false。
如果在混音中添加延迟,您可以通过在 await tick()
await new Promise(res => setTimeout(res, 2000)) // will pause execution for two seconds