对象中的计算值 |苗条

Computed values in a object | Svelte

我正在编写一些项目来学习 Svelte,我一直在尝试制作类似于电子表格的东西,用户可以在其中键入或更改数字,然后使用预定义的公式(用户无法更改公式)反应性地进行一些微积分).我试过了,但我不能被动地做。

为此,我创建了一个名为 Spreadsheet 的组件,它有两个属性,数据和列,类似于 Quasar 为 Tables.

做的事情

Here 是带有示例的 REPL。

想法是用户更改 females, males and area 列上的值,然后使用 poblationDensity 公式反应性地更改 density 列的值。

/* App.svelte */
<script>
  import Spreadsheet from "./Spreadsheet.svelte";

    const poblationDensity = (females, males, area) => {
    return (females + males) / area;
  };

  let data = [
        {
      "id": 1,
      "animal": "White-mantled colobus",
      "females": 13,
      "males": 33,
      "area": 109
    },
    {
      "id": 2,
      "animal": "Woodpecker, red-headed",
      "females": 99,
      "males": 88,
      "area": 252
    },
    {
      "id": 3,
      "animal": "White-necked raven",
      "females": 34,
      "males": 36,
      "area": 362
    },
    {
      "id": 4,
      "animal": "Baleen whale",
      "females": 24,
      "males": 67,
      "area": 457
    },
    {
      "id": 5,
      "animal": "Tiger",
      "females": 89,
      "males": 20,
      "area": 476
    },
    {
      "id": 6,
      "animal": "White spoonbill",
      "females": 56,
      "males": 85,
      "area": 358
    },
    {
      "id": 7,
      "animal": "Giant anteater",
      "females": 83,
      "males": 98,
      "area": 236
    },
    {
      "id": 8,
      "animal": "White-fronted capuchin",
      "females": 72,
      "males": 44,
      "area": 163
    },
    {
      "id": 9,
      "animal": "Raccoon, crab-eating",
      "females": 78,
      "males": 61,
      "area": 410
    },
    {
      "id": 10,
      "animal": "Turtle, long-necked",
      "females": 5,
      "males": 77,
      "area": 472
    }
    ];

  const cols = [
    {
      name: "id",
      label: "#"
    },
    {
      name: "animal",
      label: "Animal"
    },
    {
      name: "females",
      label: "Females"
    },
    {
      name: "males",
      label: "Males"
    },
    {
      name: "area",
      label: "Area"
    },
    {
      name: "density",
      label: "Density",
      computed: {
        args: ["females", "males", "area"],
        method: poblationDensity
      }
    }
  ];
</script>

<main>
    <Spreadsheet {data} {cols} />
</main>
/* Spreadsheet.svelte */
<script>
    export let data = [];
  export let cols = [];
</script>

<style>
    .numeric {
        width: 70px;
    }
</style>

<table>
    <tr>
        {#each cols as col}
        <th>{col.label}</th>
        {/each}
    </tr>
    {#each data as item}
    <tr>
        {#each cols as col}
            <td>
                <input type="text" class="{col.name !== 'animal' && 'numeric' }"
                             value={col.computed ? 0 : item[col.name]} 
                />
                </td>
        {/each}
    </tr>
    {/each}
</table>

很好的例子!

因此,第一件事就是将您的计算功能(即 poblationDensity)实际连接到显示的内容。我们可以像这样更改 <input > 字段的值:

value={col.computed ? col.computed.method(item) : item[col.name]}

我对你的函数做了一些调整以完成这项工作:

const poblationDensity = ({ females, males, area }) => {
  return (females + males) / area;
};

有了这个,我们就得到了正确的显示。现在我们需要获取值。

在 Svelte 中,获取 <input /> 值的最常见方法是 two-way binding。它也适用于对象属性!

在我们的例子中,我们需要绑定到字段的值,所以bind:value={...}。让我们将其添加到我们的示例中。为此,我们需要分离只读(计算)值的标记:

{#if col.computed}
  <input
    type="text"
    class={col.name !== 'animal' && 'numeric'}
    value={col.computed.method(item)} />
{:else}
  <input
    type="text"
    class={col.name !== 'animal' && 'numeric'}
    bind:value={item[col.name]} />
{/if}

还有...好吧,我们到了!漏完! Updated REPL

每次更新值时,bind:value 都会在 data 数组中更新它。 Svelte 知道此更改并相应地重新呈现受影响的行。此时,重新计算计算值。

另一种方法是使用一个中间数组来保存计算值。为此,Svelte 提供 reactive declarations & statements。他们外星人的外表让他们一开始有点害怕,但一旦你习惯了他们,他们就会觉得他们很神奇!