Svelte - 使用 select 输入和 on:change 事件

Svelte - using select inputs with an on:change event

对 svelte 还是很陌生(但每天都能学到更多!),需要一些帮助。

我正在研究一种兽药剂量计算器,它根据每种药物的浓度、该药物的 mg/kg 剂量和患者的体重(千克)计算每种药物的个体剂量。我有一个用于 lbs <-> kgs 的重量转换器,如果我只有一个浓度,我的计算就会起作用。问题是许多药物有多种浓度,所以我需要一个 select 输入以允许用户更改每种药物的浓度。

这是一个REPL

这是我的代码:

    <div class="row no-gap">
  <div class="col-50  tablet-25">
    <div class="item-content item-input item-input-outline item-input-with-value">
      <div class="item-inner">
        <div class="item-title item-label">Pounds</div>
        <div class="item-input-wrap">
          <input value={l} on:input="{e => setBothFromL(e.target.value)}" min="0" type=number placeholder=" lbs">
        </div>
      </div>
    </div>
  </div>
  <div class="col-50 tablet-25">
    <div class="item-content item-input item-input-outline item-input-with-value">
      <div class="item-inner">
        <div class="item-title item-label">Kilogram</div>
        <div class="item-input-wrap">
          <input value={k} on:input="{e => setBothFromK(e.target.value)}" min="0" type=number placeholder="kgs">
        </div>
      </div>
    </div>
  </div>

</div>
<h1>Antibiotics</h1>
{#each antibiotics as antibiotic, i}
<div class="Rtable-row eachdrug eachdrugE" data-id="{i + 1}">
  <div class="Rtable-cell drug-cell">
    <span class="drugTitle searchme">{antibiotic.name}
      {#if antibiotic.concSelect.length === 1}
      {antibiotic.concentration} {antibiotic.perml}
      {:else if antibiotic.concSelect.length > 1}

      <select bind:value={selected} on:change="{() => concs = selected}">


        {#each antibiotic.concSelect as concSelect}
        <option value={concSelect.conc}>
          {concSelect.name}
        </option>
        {/each}

      </select>
      {/if}

    </span>

  </div>
</div>
<div>

  <div>
    Dose: <input bind:value={antibiotic.dosevalue} step={antibiotic.dosestep} min="{antibiotic.dosemin}" max="{antibiotic.dosemax}" type=number>

    {#if  antibiotic.dosevalue > antibiotic.dosemax * 1.1 }
    <span class="error-message1 hidden-print" transition:fly="{{ y: 10, duration: 500 }}"><i class="fas fa-exclamation-triangle fa-sm fa-fw hidden-print" data-fa-transform="up-2"></i> Above Range</span>
    {/if}

  </div>
  <div> <span class="vol">{(k *   antibiotic.dosevalue).toFixed(antibiotic.decimal)} {antibiotic.appendose}</span>
  <span class="vol">{#if antibiotic.concSelect.length === 1}
{((k * antibiotic.dosevalue) / antibiotic.concentration).toFixed(antibiotic.decimal)} {antibiotic.appendvol}
 {:else if antibiotic.concSelect.length > 1}
{((k * antibiotic.dosevalue) / concs).toFixed(antibiotic.decimal)} {antibiotic.appendvol}
{/if} </span></div>
</div>


{/each}
<style>
input{min-width:120px}
.vol {
background: rgba(0, 0, 0, .12); padding:5px;}
.error-message1 {
font-size: 10px !important;
line-height: 11px !important;
font-weight: normal;
color: red;
opacity: 0.5;
font-weight: 700;
}
.eachdrug {border-top: 1px solid #ccc; margin-top:15px}
</style>

<script>
import { fade, fly } from 'svelte/transition';
let k = '';
let l = '' ;
let selected;
let concs ="";

function setBothFromK(value) {
k = +value;
l = +( k * 2.2046226218).toFixed(1);
}
function setBothFromL(value) {
l = +value;
k = +( l / 2.2046226218).toFixed(1);
}

let antibiotics = [
    {  
 "group":"",
   "route":"IV,IM,SQ BID",
   "perml":"mg/ml",
   "concentration":"50",
    "concSelect": [
        { "conc": 50, "name": "50 mg/ml","perml": "ml" }
        ],
   "perkg":"mg/kg",
   "doseper":"10",
   "dosemin":"10",
   "dosemax":"30",
   "dosestep":"1",
   "dosevalue":"10",
   "hide":"",
   "name":"Amikacin",
   "calc":"Amikacin",
   "calcID":"Amikacin2",
   "decimal": "2",
   "appendose": " mg",
   "appendvol": " ml",
   "multiply": "",
   "class": "drug",
   "color": "green"
},
{
"group":"",
"route":"BID",
"perml":"mg/ml",
"concentration":"50",
"concSelect": [
{"id": 1 , "conc": 50, "name": "50 mg/ml","perml": "ml" },
{"id": 2 , "conc": 100, "name": "100 mg/ml","perml": "" },
{"id": 3 , "conc": 150, "name": "150 mg/ml","perml": "" },
{"id": 4 , "conc": 200, "name": "200 mg/ml","perml": "" },
{"id": 5 , "conc": 400, "name": "400 mg/ml","perml": "" }
],
"perkg":"mg/kg",
"doseper":"11",
"dosemin":"11",
"dosemax":"22",
"dosestep":"1",
"dosevalue":"11",
"hide":"",
"name":"Amoxicillin",
"decimal": "2",
"appendose": " mg",
"appendvol": " ml",
"class": "drug"
},
{
"group":"",
"route":"BID",
"perml":"mg/ml",
"concentration":"62.5",
"concSelect": [
{"id": 1 , "conc": 62.5, "name": "62.5","perml": "ml" },
{"id": 2, "conc": 125, "name": "125","perml": "" },
{"id":3 , "conc": 250, "name": "250","perml": "" },
{"id": 4, "conc": 375, "name": "375","perml": "" }
],
"perkg":"mg/kg",
"doseper":"13.75",
"dosemin":"13.75",
"dosemax":"25",
"dosestep":"1",
"dosevalue":"13.75",
"hide":"",
"name":"Amoxicillin-Clavulanate",
"calc":"Amoxicillin-Clavulanate",
"calcID":"Amoxicillin-Clavulanate2",
"decimal": "2",
"appendose": " mg",
"appendvol": " ml",
"class": "drug",
},
{
"group":"",
"route":"BID",
"perml":"mg/ml",
"concentration":"100",
"concSelect": [
{"id": 1 , "conc": 100, "name": "100","perml": "ml" },
{"id": 2 , "conc": 125, "name": "125","perml": "" },
{"id": 3 , "conc": 250, "name": "250","perml": "" },
{ "id": 4 ,"conc": 500, "name": "500","perml": "" }
],
"perkg":"mg/kg",
"doseper":"6.6",
"dosemin":"6.6",
"dosemax":"22",
"dosestep":"1",
"dosevalue":"6.6",
"hide":"",
"name":"Ampicillin",
"calc":"Ampicillin",
"calcID":"Ampicillin2",
"decimal": "2",
"appendose": " mg",
"appendvol": " ml",
"class": "drug"
}
];1
</script> 

问题是:

  1. 在页面加载时,select 选项值最初未在药物剂量方程中使用(我得到 NaN 或 Infinity)。 selecting后就是。

  2. 更改 select 选项会更改所有药物浓度,而不仅仅是单个药物浓度。

如有任何帮助,我们将不胜感激。

每种抗生素您都有以下其中一种:

<select bind:value={selected} on:change="{() => concs = selected}">
...
</select>

此处不需要您的 on:change 处理程序,因为这是一个简单的分配。所以你可以 bind:value={concs} 完全一样。您正在使用两个变量,而您可以使用一个变量。这也是您看到 NaN 值的原因,因为直到您 更改 selected 选项后,您的 concs 变量才会被设置。通过直接绑定到跟踪变量,您正在解决第一个问题。

但是,您还使用单个变量(或变量对,如上所示)来跟踪几个 distinct select 字段中的变化,这就是你真正的问题在于。对于每个 select 字段,您需要一个不同的变量来跟踪其 selected 值。

您可以通过向每个 antibiotic 添加一个 concs 键并将其设置为您希望的默认值,然后更新您的 select 字段以使用该新变量,使用简化的绑定,最后更新您依赖该值进行浓度计算的行:

<select bind:value={antibiotic.concs}>
...
</select>
...
{#if antibiotic.concSelect.length === 1}
  ...
{:else if antibiotic.concSelect.length > 1}
  {((k * antibiotic.dosevalue) / antibiotic.concs).toFixed(antibiotic.decimal)}{antibiotic.appendvol}
{/if}
...

<script>
...
let antibiotics = [
  {
    ...
    "concs" = 50,
  },
  {
    ...
    "concs" = 100,
  },
  {
    ...
    "concs" = 62.5,
  },
  {
    ...
    "concs" = 100,
  },
]
...
</script>

Working REPL