2

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

为此,我创建了一个名为 Spreadsheet 的组件,它有两个道具,数据和列,类似于 Quasar 为Tables所做的事情。

是带有示例的 REPL。

这个想法是用户更改列上的值,并通过公式反应性females, males and area地更改列的值。densitypoblationDensity

/* 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>
4

1 回答 1

1

很好的例子!

因此,首先要做的是实际连接您的计算功能,即连接poblationDensity到显示的内容。我们可以像这样更改您的<input >字段的值:

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

我已经稍微调整了您的功能以使其工作:

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

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

在 Svelte 中,获取 an 值的最常见方法<input />双向绑定。它也适用于对象属性!

在我们的例子中,我们需要绑定到字段的值,所以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}

还有……好吧,我们来了!缺失完成!更新了 REPL

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

另一种方法是使用一个中间数组来保存计算值。为此,Svelte 提供了响应式声明和语句。他们的外星人外观让他们一开始有点吓人,但一旦你习惯了他们,他们就会感觉像魔法一样!

于 2019-12-09T15:54:58.077 回答