简体   繁体   English

如何从更改组件中的值的 Svelte 组件导出 function?

[英]How can I export a function from a Svelte component that changes a value in the component?

I have a component called WastedTime.svelte with a value wastedTime .我有一个名为WastedTime.svelte的组件,其值为wastedTime There's also a function to change the value to 50 (in my real code, this does an animation but this is a reduced test case for Stack Overflow).还有一个 function 将值更改为50 (在我的实际代码中,这是一个 animation 但这是堆栈溢出的简化测试用例)。

To allow the child function to be called from a parent, I have used <script context="module"> per the Svelte docs:为了允许从父级调用子 function,我在 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>

The parent calls the function in the child from onMount :父级从 onMount 调用子级中的onMount

<script>

    import { onMount } from 'svelte';
    import WastedTime, {changeNumber } from './WastedTime.svelte';

    onMount(() => {
        changeNumber()
    });
</script>

<WastedTime />

The problem is that since wastedTime is referred to in <script context="module"> , it can't seem to change wastedTime .问题是,由于在<script context="module">中引用了wastedTime ,它似乎无法更改wastedTime The exported function runs, but wastedTime stays at 0.导出的 function 运行,但wastedTime保持为 0。

Copy of this on Svelte REPL在 Svelte REPL 上的副本

I have tried: - Putting var wastedTime = 0 in <script context="module"> - Putting var wastedTime = 0 in <script>我尝试过: - 将var wastedTime = 0放入<script context="module"> - 将var wastedTime = 0放入<script>

Neither works.两者都不起作用。

How can I export a function from a Svelte component that changes a value in the component?如何从更改组件中的值的 Svelte 组件导出 function?

<script context="module"> isn't reactive — changes to variables inside this block won't affect individual instances (unless you were changing a store value, and every instance was subscribed to that store). <script context="module">不是响应式的——更改此块内的变量不会影响单个实例(除非您更改了存储值,并且每个实例都订阅了该存储)。

Instead, export the changeNumber function directly from the instance, and get a reference to it with bind:this :相反,直接从实例中导出changeNumber function,并使用bind:this获取对它的引用:

WastedTime.svelte浪费时间.svelte

<script>
    var someNumber = 0;
    export function changeNumber(){
        console.log('changing number')
        someNumber = 56
    }
</script>

<h1>Wasted time: {someNumber}</h1>

App.svelte App.svelte

<script>
    import { onMount } from 'svelte';
    import WastedTime from './WastedTime.svelte';

    let wastedTimeComponent;

    onMount(() => {
        wastedTimeComponent.changeNumber()
    });
</script>

<WastedTime bind:this={wastedTimeComponent} />

Demo here: https://svelte.dev/repl/f5304fef5c6e43edb8bf0d25d634f965此处演示: https://svelte.dev/repl/f5304fef5c6e43edb8bf0d25d634f965

Simplified version of Rich's answer:丰富的答案的简化版本:

App.svelte 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时间.svelte

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

The key here is export function .这里的关键是export function

Well, that's a damn good question!嗯,这是一个该死的好问题!

My First Attempt:我的第一次尝试:

I've tried @Rich Harris answer (export a function from within the component, bind it when using the component with onMount event listener).我已经尝试过@Rich Harris 的答案(从组件中导出 function,在使用带有onMount事件侦听器的组件时绑定它)。 The concept is indeed solid, but my problem was a little bit more complex - I've tried to pass an event with parameter to be invoked from the outside.这个概念确实很可靠,但我的问题有点复杂——我试图传递一个带有参数的事件,以便从外部调用。 And yes - this parameter is forged using {#await} .. so... no luck with that approach是的 - 这个参数是使用{#await}伪造的......所以......这种方法不走运


My Second Attempt:我的第二次尝试:

After learning more about how svelte handles events (I'm a newbie to svelte and learning as I progress), I've found this great article.在了解了有关 svelte 如何处理事件的更多信息(我是 svelte 的新手并随着我的进步而学习)之后,我发现了这篇很棒的文章。 In short: let's make our component truly-event oriented!简而言之:让我们的组件真正面向事件! In your question - you actually trying to implement onload event... so.. why shouldn't we do just that?在你的问题中 - 你实际上试图实现onload事件......所以......为什么我们不应该这样做?

component.svelte组件.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应用程序.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} />

So - yep, I've learned something today: Also:所以 - 是的,我今天学到了一些东西:另外:

  • This is a more elegant way to code (event-driven)这是一种更优雅的编码方式(事件驱动)
  • Component expose itself with proper usage of Svelte events life-cycle组件通过正确使用 Svelte 事件生命周期来暴露自己
  • dispatch can be triggered in response to other events - letting you constuct a complete life-cycle for your component dispatch可以被触发以响应其他事件——让你为你的组件构建一个完整的生命周期

AMAZING!惊人!

A Simpler Solution更简单的解决方案

Parent component:父组件:

<script>
    import Counter from './Counter.svelte'
    let counterElement
</script>

<Counter bind:this={counterElement} />

<button on:click={_=> counterElement.add()}>Add</button>

Child component:子组件:

<script>
    export const add =_=> count += 1
    let count = 0
</script>

<div>Count: {count}</div>

Check it out:一探究竟:

https://svelte.dev/repl/70cff59aee444dd3ab772a244bd8fa36?version=3.48.0 https://svelte.dev/repl/70cff59aee444dd3ab772a244bd8fa36?version=3.48.0

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM