问题描述
是否可以使用像原生浏览器事件这样的目标对象来分派一个 svelte 事件(使用 createEventdispatcher
创建)?
即在处理程序端接收 event.target.value
而不是 event.detail。
解决方法
是的,这是可能的,但涉及一些黑客攻击。
您可以查看 svelte 源代码以了解事件调度的工作原理。我将概述以下关键部分。
假设我们有两个组件,Inner
和 Outer
。
<!-- Inner.svelte -->
<script>
import { createEventDispatcher } from 'svelte'
const dispatch = createEventDispatcher()
const dispatchFoo = () => dispatch('foo','bar')
</script>
<button on:click={dispatchFoo}>send</button>
<!-- Outer.svelte -->
<script>
import Inner from './Inner.svelte'
const handleFoo = (e) => { console.log('receive foo',e) }
</script>
<Inner on:foo={handleFoo}></Inner>
仔细想想,事件处理程序 handleFoo
是在 Outer
中创建的,但它实际上是在 Inner
上注册的。
检查你将看到的编译后的 JS 代码:
-
inner.$$.callbacks["foo"]
持有事件处理程序 [src] - 当您单击按钮并调用
dispatch
时,它只会读取潜在处理程序的inner.$$.callbacks["foo"]
,如果找到,则使用CustomEvent
作为参数调用它们 [src]
设置 customEvent.target
的唯一方法是使用 element.dispatchEvent(customEvent)
调度该自定义事件。但是 element.dispatchEvent
并没有贯穿整个过程。
解决方案(黑客)
编写您自己的createEventDispatcher
。
import { get_current_component } from 'svelte/internal'
function createEventDispatcher() {
const component = get_current_component();
return (type,target,detail) => {
const callbacks = component.$$.callbacks[type];
if (callbacks) {
const event = new CustomEvent(type,{ detail });
// the key is to call `dispatchEvent` manually to set `event.target`
target.dispatchEvent(event);
callbacks.slice().forEach((fn) => {
fn.call(component,event);
});
}
};
}
,
根据 hackape 的回答修改
import { get_current_component } from 'svelte/internal'
function createEventDispatcher() {
const component = get_current_component(bubbles = true);
return (type,{ bubbles,detail });
// the key is to call `dispatchEvent` manually to set `event.target`
target.dispatchEvent(event);
/* You have already raised an event,you should not repeat the callbacks to avoid duplication
callbacks.slice().forEach((fn) => {
fn.call(component,event);
});
*/
}
};
}