首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >StimulusJS如何根据不同子控制器中的值计算父控制器中的值(购物车->购物车项)

StimulusJS如何根据不同子控制器中的值计算父控制器中的值(购物车->购物车项)
EN

Stack Overflow用户
提问于 2022-06-02 12:35:16
回答 1查看 429关注 0票数 2

我正在建造一辆带有刺激的购物车。购物车回顾页面显示多个购物车项目。购物车有单价和数量。每个购物车项组件都有一个数量选择器,当数量编号发生变化时,cartitem元素的总价将被重新计算为totalCartItem = unitPrice x Quantity,如果购物车还必须重新计算totalCartPrice = sum(totalCartItem),则为总价。

以下是html结构的简化

代码语言:javascript
复制
<div class="cart" data-controller='cart'>
  <div class="cart-item" data-controller='cart-item'>
    <p class='unit-price'>20</p>
    <input type="number" name="quantity" value="1">
    <p class='total-price' data-target='cart-item.totalPrice' data-action="change->cart-item#update" data-target='cart-item.quantity'>20</p>
  </div>
  <div class="cart-item" data-controller='cart-item'>
    <p class='unit-price'>10</p>
    <input type="number" name="quantity" value="2" data-action="change->cart-item#update" data-target='cart-item.quantity'>
    <p class='total-price' data-target='cart-item.totalPrice'>20</p>
  </div>
  <div class="cart-total">
    40
  </div>
</div>

我的购物车项目控制器工作得非常好,并正确地更新了UI中的购物车项目totalPriceFor。

代码语言:javascript
复制
export default class extends Controller {
  static targets = ["totalPrice", "quantity"]

  static values = {
    unitPrice: String,
  }

  connect() {
    console.log("hello from StimulusJS")
  }

  update(){
    this.totalPriceTarget.textContent = parseFloat(this.unitPriceValue) * parseInt(this.quantityTarget.value)
  }
}

但是,我现在不知道如何更新totalCartPrice。我觉得这应该是封装cartController元素的cartItems的响应性,但是我不知道实现这个目标的正确方法是什么。我觉得我应该为每个购物车的数量在每个数字输入选择器上添加change->cart#update,但是我应该在cart#update方法中添加什么来重新计算每个购物车项目的总数呢?

代码语言:javascript
复制
export default class extends Controller {
  static targets = ["total"]
  connect() {
    console.log("hello from StimulusJS")
  }

  update(){
    // let details = event.detail;
    // this.cartItemChildren.forEach((item) => console.log(item.totalValue))
  }
}
EN

回答 1

Stack Overflow用户

发布于 2022-06-03 21:59:31

根据刺激文档,从HTML开始总是最好的选择。通过扩展,最好以一种可访问的方式构造您的HTML,并查看浏览器给您带来的东西,而不需要重新发明任何东西。

在构建表单时,最好使用form元素,即使没有提交此表单。https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement

还有一个非常有用的output元素,它帮助您根据某些输入值分配输出值。https://developer.mozilla.org/en-US/docs/Web/HTML/Element/output#attr-for

最后,表单元素有一个DOM,它允许您通过其name属性访问表单的各个部分,这就是form.elementshttps://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/elements

把这些结合在一起,我们可以从以下HTML开始。

HTML

  • 我们只是将控制器操作作为一个整体附加到表单上,这样我们就可以听到表单中输入的任何更改。
  • 这里有一个控制器,虽然文档推荐更小的粒度控制器,但这里最小的单元内容似乎是作为一个整体的表单。
  • 每个input都有一个唯一的ID,每个output元素都使用for属性通过这个id引用输入--这对于可访问性来说更好,但是当我们想解析值和更新输出时会很方便。
  • 我们在单价上还有一个额外的数据属性,它使用相同的id,请注意,这个数据属性没有什么特别之处,只是给了我们一种“查找”相关价格的方法。不需要为这个简单的情况创建控制器目标。
  • 注意:这假设您不必支持IE11 (因为输出元素在该浏览器中不能工作)。
代码语言:javascript
复制
<form class="cart" data-controller='cart' data-action="change->cart#updateTotals">
  <div class="cart-item">
    <span class='unit-price' data-price-for="cart-item-1">20</span>
    x
    <input type="number" name="quantity" value="1" id="cart-item-1">
    =
    <output class="total-price" for="cart-item-1" name="item-total">20</output>
  </div>
  <div class="cart-item">
    <span class='unit-price' data-price-for="cart-item-2">10</span>
    x
    <input type="number" name="quantity" value="1" id="cart-item-2">
    =
    <output class="total-price" for="cart-item-2" name="item-total">10</output>
  </div>
  <div class="cart-total">
    Total: <span data-cart-target="total">30</span>
  </div>
</form>

JavaScript (控制器)

  • 除了总目标外,我们的控制器实际上不需要其他任何东西,因为我们可以在基本表单的附加控制器上使用this.element
  • 我们正在避免使用通用的update方法,并试图更具体地处理updateTotals
  • 我们在表单上使用elements API获取名称为'item-total'的元素(注意输出名称没有提交)。https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/elements
  • 一旦我们有了每个输出元素,我们就可以通过for和输入的id找到相关的输入元素,然后通过数据属性来找到价格。
  • 然后计算总计,最后更新DOM中的所有值。
  • 注意:数字解析是非常基本的,最好在这里添加一些安全性,我们还假设您不需要支持IE11。
代码语言:javascript
复制
import { Controller } from '@hotwired/stimulus';

export default class extends Controller {
  static targets = ['total'];

  connect() {
    this.updateTotals();
  }

  updateTotals() {
    // parse the form elements to get all data
    // https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/elements

    const cartItems = [...this.element.elements['item-total']].map(
      (outputElement) => {
        const forId = outputElement.getAttribute('for');
        const priceElement = document.querySelector(`[data-price-for='${forId}']`);
        const price = Number(priceElement.textContent);
        const quantity = Number(document.getElementById(forId).value);
        return { outputElement, total: quantity * price };
      }
    );

    // calculate the grand total
    const grandTotal = cartItems.reduce(
      (runningTotal, { total }) => runningTotal + total,
      0
    );

    // update the grand total
    this.totalTarget.textContent = grandTotal;

    // update totals for each cart item
    cartItems.forEach(({ outputElement, total }) => {
      outputElement.textContent = total;
    });

    console.log('form updated', { grandTotal, cartItems });
  }
}
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72476371

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档