如何从 Svelte 组件中导出更改组件中的值的函数?
Posted
技术标签:
【中文标题】如何从 Svelte 组件中导出更改组件中的值的函数?【英文标题】:How can I export a function from a Svelte component that changes a value in the component? 【发布时间】:2020-02-05 19:43:46 【问题描述】:我有一个名为WastedTime.svelte
的组件,其值为wastedTime
。还有一个函数可以将值更改为50
(在我的真实代码中,这是一个动画,但这是 Stack Overflow 的简化测试用例)。
为了允许从父级调用子函数,我在 Svelte 文档中使用了 <script context="module">
:
<script context="module">
var wastedTime = 0;
export function changeNumber()
console.log('changing number')
wastedTime = 50
</script>
<script>
// Putting 'var wastedTime = 0' here doesn't work either
</script>
<h1>Wasted time: wastedTime</h1>
父从onMount
调用子中的函数:
<script>
import onMount from 'svelte';
import WastedTime, changeNumber from './WastedTime.svelte';
onMount(() =>
changeNumber()
);
</script>
<WastedTime />
问题在于,由于wastedTime
在<script context="module">
中被引用,它似乎无法更改wastedTime
。导出的函数运行,但wastedTime
保持为0。
Copy of this on Svelte REPL
我尝试过:
- 将var wastedTime = 0
放入<script context="module">
- 将var wastedTime = 0
放入<script>
都不行。
【问题讨论】:
【参考方案1】:<script context="module">
不是响应式的 - 更改此块内的变量不会影响单个实例(除非您更改了存储值,并且每个实例都订阅了该存储)。
相反,直接从实例中导出changeNumber
函数,并使用bind:this
获取对它的引用:
WastedTime.svelte
<script>
var someNumber = 0;
export function changeNumber()
console.log('changing number')
someNumber = 56
</script>
<h1>Wasted time: someNumber</h1>
App.svelte
<script>
import onMount from 'svelte';
import WastedTime from './WastedTime.svelte';
let wastedTimeComponent;
onMount(() =>
wastedTimeComponent.changeNumber()
);
</script>
<WastedTime bind:this=wastedTimeComponent />
在这里演示:https://svelte.dev/repl/f5304fef5c6e43edb8bf0d25d634f965
【讨论】:
谢谢。我发誓我在文档中读过一个示例,上面说<script context="module">
是从组件中导出函数所必需的,但我似乎再也找不到它了。
你可能在想svelte.dev/tutorial/module-exports
t 可以很好地解释 1)“从 context="module" 脚本块导出的任何内容都成为模块本身的导出。”和 2)“更改此块内的变量不会影响个别实例”。我应该使用context="module"
从script
导出变量吗?
这个问题和答案需要进入 Svelte 文档!在不解释这种模式的情况下,与组件进行通信是一个三环马戏团。
另一种方法是将WastedTimeService.js 中的函数与exported
函数或作为单独的js 类分开。这种持续性使得对功能进行单元测试变得更加容易。【参考方案2】:
嗯,这是一个该死的好问题!
我的第一次尝试:
我已经尝试过@Rich Harris 的回答(从组件中导出一个函数,在将组件与onMount
事件侦听器一起使用时绑定它)。这个概念确实很可靠,但我的问题有点复杂——我试图传递一个带有参数的事件,以便从外部调用。是的 - 这个参数是使用 #await
.. 伪造的。所以......这种方法不走运
我的第二次尝试:
在了解了有关 svelte 如何处理事件的更多信息(我是 svelte 的新手并随着我的进步而学习)之后,我发现了 this 很棒的文章。简而言之:让我们的组件真正面向事件!在你的问题中 - 你实际上试图实现onload
事件......所以......为什么我们不应该这样做?
component.svelte
<script>
import createEventDispatcher, onMount from 'svelte';
const dispatch = createEventDispatcher();
function doSomething() console.log('wowza!')
// wait for onMount to trigger, then dispatch event named "load"
onMount(() => dispatch('load',
data: 'yay',
doSomething
));
</script>
app.svelte
<script>
import Component from './component.svelte';
function component_load(event)
console.log(event.detail.data);
event.detail.doSomething();
</script>
<Component on:load=component_load />
所以 - 是的,我今天学到了一些东西!另外:
这是一种更优雅的编码方式(事件驱动) 组件通过正确使用 Svelte 事件生命周期来暴露自己dispatch
可以触发以响应其他事件 - 让您为组件构建完整的生命周期
太棒了!
【讨论】:
【参考方案3】:里奇回答的简化版:
App.svelte
<script>
import Time from './Time.svelte';
let timeComponent;
let time;
</script>
<Time bind:this=timeComponent bind:time />
<h1>Spent time: time ms</h1>
#if timeComponent
<button on:click=() => timeComponent.spendTime() >Click me</button>
:else
Loading...
/if
Time.svelte
<script>
export var time = 0;
export function spendTime()
time += 50;
</script>
这里的关键是export function
。
【讨论】:
以上是关于如何从 Svelte 组件中导出更改组件中的值的函数?的主要内容,如果未能解决你的问题,请参考以下文章