我为未调用 Svelte 调度的问题创建了重现:
打开复制
打开浏览器控制台
使用链接进入“关于”页面
我应该看到消息:“handleInput”,但我没有看到
<script>
import Select from 'svelte-select';
import { createEventDispatcher } from 'svelte';
export let value = undefined;
export let id = undefined;
const dispatch = createEventDispatcher();
let result;
let items = [
{ value: 'one', label: 'One' },
{ value: 'two', label: 'Two' },
{ value: 'three', label: 'Three' },
];
$: if (id !== undefined) {
result = id;
}
$: if (result != undefined) {
value = { value: 'custom', label: 'Custom' };
console.log("this should dispatch!")
dispatch('input', value);
console.log("is it dispatched?")
}
</script>
<Select {value} {items} on:change on:input />
dispatch('input', value)
完全被忽略。
为什么?
复制步骤为:
您的反应式语句在
on:input
事件侦听器附加到 <Select>
组件之前触发。这可能是由于在 DOM(或组件标记)安装之前调用响应式语句,并且在组件安装之后附加事件侦听器。
您的
setTimeout
代码之所以有效,是因为它添加了一个微任务,该微任务可能在事件侦听器设置后注册;因此,当其回调函数触发时,您的 on:input
侦听器将收到调度的事件。同样,使用 await tick()
使您的代码可以出于同样的原因工作:
async function dispatchEvent () {
value = { value: 'custom', label: 'Custom' };
console.log("this should dispatch!")
// wait for all microtasks to complete before continuing
await tick()
dispatch('input', value);
console.log("is it dispatched?")
}
$: if (result != undefined) {
dispatchEvent()
}
话虽如此,有许多反应性的言论是很难遵循的。我建议重构以在您的
CustomSelect.svelte
中使用事件侦听器,它可以与事件转发结合使用:
<Select on:input={internalInputHandler} on:input on:change />
<!-- ^ handle input ^ forward input -->
我还建议使用自定义名称调度事件,而不是覆盖本机事件名称;这样你就可以单独处理它们并期望原生
InputEvent
为 on:input
。您可以为已调度的事件命名 input--id
:
<!-- Component.svelte -->
<script>
function handler() {
dispatch('input:component', { some: 'detail' })
}
</script>
<!-- +page.svelte -->
<Select on:input--id={doSomething} on:input={doSomethingElse} />