如何从Svelte组件导出一个函数,该函数会更改该组件中的值?

时间:2019-10-08 13:48:44

标签: javascript svelte svelte-component

我有一个名为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>

都不行。

如何从Svelte组件导出一个函数以更改该组件中的值?

3 个答案:

答案 0 :(得分:4)

<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?version=3.12.1

答案 1 :(得分:1)

嗯,这是一个该死的好问题!

我的第一次尝试:

我已经尝试了@Rich Harris答案(从组件内部导出函数,将组件与onMount事件侦听器一起使用时将其绑定)。这个概念确实很扎实,但是我的问题有点复杂-我试图传递一个带有参数的事件以从外部调用。是的-此参数是使用{#await}伪造的..所以...用这种方法运气不好


我的第二次尝试:

在了解了更多关于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来响应其他事件-让您为组件构建完整的生命周期

令人惊叹!

答案 2 :(得分:0)

Rich 答案的简化版:

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}

时间.svelte

<script>
export var time = 0;
export function spendTime() {
  time += 50;
}
</script>

这里的关键是 export function