对象中的计算值苗条的

时间:2019-12-09 14:05:33

标签: javascript spreadsheet svelte svelte-component

我正在编码一些项目以学习Svelte,并且我一直在尝试制作类似于电子表格的内容,在电子表格中,用户键入或更改数字,并且使用预先定义的公式来进行微积分(用户无法更改公式)。我已经尝试过了,但是我不能做出反应。

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

Here是带有示例的REPL。

这个想法是,用户可以更改females, males and area列上的值,并使用density公式来被动地更改poblationDensity列的值。

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

1 个答案:

答案 0 :(得分:0)

很好的例子!

因此,第一件事是将您的计算功能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了解此更改,并相应地重新渲染受影响的行。此时,将重新计算计算出的值。

另一种方法是使用一个中间数组来保存计算值。为此,斯维尔特提供了reactive declarations & statements。他们外星人的外观乍一看让他们有点吓人,但是一旦您习惯了它们,它们就会像魔术一样!