遍历html表并计算值

Posted

技术标签:

【中文标题】遍历html表并计算值【英文标题】:Iterate through html table and calculates value 【发布时间】:2021-12-01 18:16:57 【问题描述】:

目标是人们应该在输入字段中输入一个值,而 javascript 应该乘以一个固定值。

代码应该对每一行都执行此操作,并且无需刷新即可自动执行此操作。

JavaScript 适用于第一行,但如果我添加循环(前 3 行代码),它就不再起作用了。

表格是这样的

<table class="u-table-entity" id="table_gebäck">
  <script src="calculation.js"></script>
  <colgroup>
    <col >
    <col >
    <col >
    <col >
    <col >
  </colgroup>
  <tbody class="u-table-alt-grey-5 u-table-body">
    <tr style="height: 55px;">
      <b>
      <td class="u-table-cell u-table-cell-1"><b>Produkt</b><span style="font-weight: 700;"></span>
      </td>
      <td class="u-table-cell"></td>
      <td class="u-table-cell u-table-cell-3"><b>Einzelpreis</b></td>
      <td class="u-table-cell u-table-cell-4"><b>Menge</b></td>
      <td class="u-table-cell u-table-cell-5"><b>Gesamtpreis</b></td>
      </b>
    </tr>
    <tr style="height: 55px;">
      <td class="u-table-cell">Kornspitz</td>
      <td class="u-table-cell"></td>
      <td class="u-table-cell">
        <p value="1.39" id="basePrice">1,39 €</p>
      </td>
      <td class="u-table-cell">
        <form id="Menge">
          <input type="number" min="0" id="quantity" value="0" step="1.0">
        </form>
      </td>
      <td class="u-table-cell">
        <form id="sum">
          <p><output id="field_sum" for="quantity">0</output> €</p>
        </form>
      </td>
    </tr>
    <tr style="height: 55px;">
      <td class="u-table-cell">Row 2</td>
      <td class="u-table-cell"></td>
      <td class="u-table-cell">
        <p value="5.39" id="basePrice">5,39 €</p>
      </td>
      <td class="u-table-cell">
        <form id="Menge">
          <input type="number" min="0" id="quantity" value="0" step="1.0">
        </form>
      </td>
      <td class="u-table-cell">
        <form id="sum">
          <p><output id="field_sum" for="quantity">0</output> €</p>
        </form>
      </td>
    </tr>
  </tbody>
</table>

以及到目前为止我创建的 JavaScript 代码

var table = document.getElementById("table_gebäck");

for (var i = 0, row; row = table.rows[i]; i++) 
  let row = table.rows[i]
  (function () 
    const basePrice = document.getElementsByClassName("basePrice");
    const quantityInput = document.getElementsByClassName("quantity");
    const resOutput = document.getElementsByClassName("field_sum");
    quantityInput.addEventListener("change", function () 
      let currentQuantity = parseFloat(quantityInput.value);
      let currentBasePrice = parseFloat(basePrice.getAttribute("value"));
      resOutput.textContent = currentQuantity * currentBasePrice;
    );
  ());

编辑

这也帮助了我

Calculating total price by iterating in the table using JavaScript

【问题讨论】:

ID 必须html 文档中是唯一的。 好的,所以我必须称它为 id= baseprice1,id= baseprice 2 等等? 不仅 ID 重复,其他 ID 也重复,例如 Mengequantitiessum。而不是现在“编号”所有这些,您可能应该研究其他选择元素的方法 - f.e.基于类,和/或与 DOM 中其他元素的关系。 &lt;p value="1.39" - 段落没有值属性;如果您需要将类似这样的附加信息放在或多或少的通用元素上,则应该使用 自定义数据属性 getElementsByClassNamequerySelector 等方法不仅可以在文档上调用,还可以在特定元素上调用 - 在这种情况下,它们只会选择后代元素。 【参考方案1】:

除了标记清理/清理任务之外,还可以实现一种微组件方法。

与特定 DOM 层次结构无关(解耦)的可行解决方案可以基于 custom data attributes 和 dataset 访问以及 bound handler data ...

function jsonParse(value) 
  let result = null;
  try 
    result = JSON.parse(value);
   catch(exception) 
  return result;

function sanitizeFloatValue(value) 
  value = parseFloat(value);
  return Number.isFinite(value) ? value : null;


function updateTotalValueFromBoundContextData(/* evt */) 
  const  source, target, baseValue, toFixed  = this;
  const totalValue = baseValue * (sanitizeFloatValue(source.value) || 0);

  target.value = (typeof toFixed === 'number')
    ? totalValue.toFixed(toFixed)
    : totalValue;

function initializeUpdateTotalValue(componentRoot) 
  const source = componentRoot
    .querySelector('[data-base-value]');
  const target = componentRoot
    .querySelector('[data-total-value]');

  const baseValue = sanitizeFloatValue(source.dataset.baseValue) || 0;

  const config = jsonParse(componentRoot.dataset.updateTotalValue) ?? ;
  const toFixed = sanitizeFloatValue(config.toFixed);

  const context =  source, target, baseValue, toFixed ;

  source
    .addEventListener('input',
      updateTotalValueFromBoundContextData.bind(context)
    );

  // initial update call
  updateTotalValueFromBoundContextData.call(context);


function main() 
  document
    .querySelectorAll('[data-update-total-value]')
    .forEach(initializeUpdateTotalValue);

main();
body  zoom: .8; 
tr, td  margin: 0!important; padding: 0!important; height: unset!important; 
<form name="product-orders">
  <!-- <script src="calculation.js"></script> //-->
  <table class="u-table-entity">
    <colgroup>
      <col >
      <col >
      <col >
      <col >
      <col >
    </colgroup>
    <tbody class="u-table-alt-grey-5 u-table-body">
      <tr style="height: 55px;">
        <td class="u-table-cell u-table-cell-1"><b>Produkt</b><span style="font-weight: 700;"></span>
        </td>
        <td class="u-table-cell"></td>
        <td class="u-table-cell u-table-cell-3"><b>Einzelpreis</b></td>
        <td class="u-table-cell u-table-cell-4"><b>Menge</b></td>
        <td class="u-table-cell u-table-cell-5"><b>Gesamtpreis</b></td>
      </tr>
      <tr style="height: 55px;" data-update-total-value='"toFixed": 2'>
        <td class="u-table-cell">Kornspitz</td>
        <td class="u-table-cell"></td>
        <td class="u-table-cell">
          <p value="1.39">1,39 €</p>
        </td>
        <td class="u-table-cell">
          <input type="number"
            min="0" value="0" step="1"
            name="quantity-Kornspitz"
            id="quantity-Kornspitz"
            data-base-value="1.39"
          />
        </td>
        <td class="u-table-cell">
          <p>
            <output for="quantity-Kornspitz" data-total-value>0</output>
            €
          </p>
        </td>
      </tr>
      <tr style="height: 55px;" data-update-total-value='"toFixed": 2'>
        <td class="u-table-cell">Row 2</td>
        <td class="u-table-cell"></td>
        <td class="u-table-cell">
          <p value="5.39">5,39 €</p>
        </td>
        <td class="u-table-cell">
          <input type="number"
            min="0" value="0" step="1"
            name="quantity-Row_2"
            id="quantity-Row_2"
            data-base-value="5.39"
          />
        </td>
        <td class="u-table-cell">
          <p>
            <output for="quantity-Row_2" data-total-value>0</output>
            €
          </p>
        </td>
      </tr>
      <tr style="height: 55px;" data-update-total-value>
        <td class="u-table-cell">float number calculation</td>
        <td class="u-table-cell"></td>
        <td class="u-table-cell">
          <p value="1.39">1,39 €</p>
        </td>
        <td class="u-table-cell">
          <input type="number"
            min="0" value="5" step="1"
            name="quantity-Row_3"
            id="quantity-Row_3"
            data-base-value="1.39"
          />
        </td>
        <td class="u-table-cell">
          <p>
            <output for="quantity-Row_3" data-total-value>0</output>
            €
          </p>
        </td>
      </tr>
      <tr style="height: 55px;" data-update-total-value='"toFixed": 4'>
        <td class="u-table-cell"><code>toFixed</code> set to 4</td>
        <td class="u-table-cell"></td>
        <td class="u-table-cell">
          <p value="5.39">5,39 €</p>
        </td>
        <td class="u-table-cell">
          <input type="number"
            min="0" value="3" step="1"
            name="quantity-Row_4"
            id="quantity-Row_4"
            data-base-value="5.39"
          />
        </td>
        <td class="u-table-cell">
          <p>
            <output for="quantity-Row_4" data-total-value>0</output>
            €
          </p>
        </td>
      </tr>
    </tbody>
  </table>
</form>

编辑

“非常感谢您分享这个但我不知道如何使用它 – Setzi138”

好的,那我试试……

首先,OP 需要编写有效的标记,因此任何元素的 id 属性永远不会有重复值。

其次,这个任务应该尽可能通用。一个例如不应实现与特定 DOM 层次结构(或标记)或过于具体的任务(如计算总价)紧密耦合的任何代码。

因此,必须找到一种解决方案,该解决方案可以轻松适应具有相同任务的其他环境,例如这里... “更新并显示根据基值和当前更改的乘数计算的总值每当此乘数值发生变化时”

上述措辞谨慎的要求给出了方向,甚至指出了解决方案的基石。

一个主要的初始化任务首先需要在初始化之前识别每个结构。

一种可行的方法是使用custom data-* attributes 而不是class(与布局和样式相结合)和id(过于具体,不适合通用解决方案)属性。此外,可以将任何基于字符串的数据提供给自定义属性,该属性可以通过HTMLElementdataset 属性访问。

尽管该方法声称尽可能与标记无关,但它有一个先决条件。这样一个“微组件”的结构需要有一个根元素和另外两个元素,它们都需要嵌套在组件根的下面/内部。 一个是数量变化的触发因素或来源,另一个是更新总值的目标。

利用[data-*] 属性在访问 DOM 中的此类元素方面也没有任何缺点,因为解决方案通过 &lt;element &gt;.querySelector&lt;element &gt;.querySelectorAll 使用现代元素查询。

现在唯一剩下的就是正确的命名和实现本身。

...

+++待续+++

...

通过对第一个所示方法的更多迭代,最终可以提供高度通用可定制基于模块实现自初始化组件,由于具有自定义能力,它也可以在不允许大规模更改标记的 DOM 环境中运行...

// utility functions
function parseJSON(value) 
  let result = null;
  try 
    result = JSON.parse(value);
   catch(exception) 
  return result;

function sanitizeFloatValue(value) 
  value = parseFloat(value);
  return Number.isFinite(value) ? value : null;


function getCustomKeyFromAttributeSelector(selector) 
  return (/\[\s*data-(?<customKey>[^\s\]]+)(?:\s|\])/)
    .exec(selector)
    ?.groups
    ?.customKey;

function getDatasetKeyFromCustomAttributeSelector(selector) 
  return getCustomKeyFromAttributeSelector(selector)
    ?.toLowerCase()
    ?.replace((/-(\pLl)/gu), (match, char) => char.toUpperCase());


// component specific module based code
const updateTotalValueModule = (function () 
  const DEFAULT_CONFIG = 
    calculation: 
      baseValue: 0,
      toFixed: 2,
    ,
    selectors: 
      source: '[data-base-value]',
      target: '[data-total-value]',
    ,
    eventType: 'input',
  
  const DEFAULT_SELCTOR_COMPONENT = '[data-update-total-value]';

  function updateTotalValueFromBoundContextData(/* evt */) 
    const  source, target, baseValue, toFixed  = this;
    const totalValue = baseValue * (sanitizeFloatValue(source.value) || 0);

    target.value = (typeof toFixed === 'number')
      ? totalValue.toFixed(toFixed)
      : totalValue;
  
  let currentConfigKey;

  function initializeUpdateTotalValue(componentRoot) 
    const  // config values.
      selectors = DEFAULT_CONFIG.selectors,
      eventType = DEFAULT_CONFIG.eventType,
      calculation = DEFAULT_CONFIG.calculation
     = (parseJSON(
      componentRoot.dataset[currentConfigKey]
    ) ?? DEFAULT_CONFIG);

    const source = componentRoot.querySelector(
      selectors.source || DEFAULT_CONFIG.selectors.source
    );
    const target = source && componentRoot.querySelector(
      selectors.target || DEFAULT_CONFIG.selectors.target
    );
    if (source && target) 

      const baseValue = (
        calculation.baseValue ||
        sanitizeFloatValue(source.dataset[
          getDatasetKeyFromCustomAttributeSelector(
            selectors.source || DEFAULT_CONFIG.selectors.source
          )
        ]) || 0
      );
      const toFixed = sanitizeFloatValue(
        calculation.toFixed || DEFAULT_CONFIG.calculation.toFixed
      );
      const context =  source, target, baseValue, toFixed ;

      source.addEventListener(
        eventType,
        updateTotalValueFromBoundContextData.bind(context)
      );

      // initial update call
      updateTotalValueFromBoundContextData.call(context);
    
  
  function initialize(customAttributeSelector) 
    const selector = (typeof customAttributeSelector === 'string')
      && customAttributeSelector
      || DEFAULT_SELCTOR_COMPONENT;

    currentConfigKey = getDatasetKeyFromCustomAttributeSelector(selector);

    document
      .querySelectorAll(selector)
      .forEach(initializeUpdateTotalValue);
  

  // (module) export(s)
  return 
    initialize
  ;

());

// running the component ...

// ... does target any default-config conform component.
updateTotalValueModule.initialize();

// ... does target any custom specific component.
updateTotalValueModule.initialize('[data-auto-total-price]');
body  zoom: .8; 
tr, td  margin: 0!important; padding: 0!important; height: unset!important; 
<!-- <script src="calculation.js"></script> //-->
<table class="u-table-entity" id="table_gebäck">
  <colgroup>
    <col >
    <col >
    <col >
    <col >
    <col >
  </colgroup>
  <tbody class="u-table-alt-grey-5 u-table-body">
    <tr style="height: 55px;">
      <td class="u-table-cell u-table-cell-1"><b>Produkt</b><span style="font-weight: 700;"></span>
      </td>
      <td class="u-table-cell"></td>
      <td class="u-table-cell u-table-cell-3"><b>Einzelpreis</b></td>
      <td class="u-table-cell u-table-cell-4"><b>Menge</b></td>
      <td class="u-table-cell u-table-cell-5"><b>Gesamtpreis</b></td>
    </tr>
    <tr style="height: 55px;" data-update-total-value ='"calculation":"baseValue":1.39,"toFixed":2,"selectors":"source":"form input[type=\"number\"]","target":"form output","eventType":"input"'>
      <td class="u-table-cell">Kornspitz</td>
      <td class="u-table-cell"></td>
      <td class="u-table-cell">
        <p>1,39 €</p>
      </td>
      <td class="u-table-cell">
        <form name="amount_Kornspitz">
          <input type="number" value="0" min="0" step="1" id="amount_Kornspitz">
        </form>
      </td>
      <td class="u-table-cell">
        <form name="price_total_Kornspitz">
          <p>
            <output for="amount_Kornspitz">0</output>
            €
          </p>
        </form>
      </td>
    </tr>
    <tr style="height: 55px;" data-auto-total-price='"calculation":"toFixed":4,"selectors":"target":"form output"'>
      <td class="u-table-cell">Row 2</td>
      <td class="u-table-cell"></td>
      <td class="u-table-cell">
        <p>5,39 €</p>
      </td>
      <td class="u-table-cell">
        <form name="amount_Row_2">
          <input type="number" value="5" min="0" step="1" id="amount_Row_2" data-base-value="5.39">
        </form>
      </td>
      <td class="u-table-cell">
        <form name="price_total_Row_2">
          <p>
            <output for="amount_Row_2">0</output>
            €
          </p>
        </form>
      </td>
    </tr>
  </tbody>
</table>

【讨论】:

以上是关于遍历html表并计算值的主要内容,如果未能解决你的问题,请参考以下文章

遍历数据透视表并删除相同的值

Oracle - 遍历表并检查属性中的值

遍历所有工作表并查找范围内的值。如果找到然后执行一些操作并转到

SQL中如何遍历表并更新某个字段的值

DataTables 循环遍历表并删除特定列中包含特定字符串的所有行

循环遍历 Excel 工作表并使用 C# 将文本保存到 TXT 文件中