我正在用刺激 build 一辆购物车。购物车回顾页面显示多个购物车商品。购物车商品具有单价和数量。
每个购物车商品组件都有一个数量选择器,当数量发生变化时,会重新计算 cartitem 元素的总价 totalCartItem = unitPrice x Quantity
,如果还必须重新计算购物车的话,则总价 totalCartPrice = sum(totalCartItem)
这是 html 结构的简化
<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>
我的购物车项目 Controller 工作得很好,并正确更新 UI 中购物车项目的总价格。
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
。我觉得这应该是包装 cartItems 元素的 cartController
的责任,但我不知道实现此目的的正确方法是什么 id 。
我觉得我应该在每个数字输入选择器上添加 change->cart#update
以获取每个购物车项目的数量,但是我应该在 cart#update 方法中添加什么来重新计算每个项目的总数单个购物车项目?
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))
}
}
最佳答案
根据 Stimulus 文档,最好始终 start with the 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 API,可让您通过其 name
属性访问表单的各个部分,即 form.elements
。 https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/elements
将这些整合在一起,我们可以从以下 HTML 开始...
HTML
- 我们只是将 Controller 操作作为一个整体附加到表单上,这样我们就可以监听表单内输入的任何更改。
- 本例使用一个 Controller ,虽然文档推荐了更细粒度的 Controller ,但这里的最小单元内容似乎是整个表单。
- 每个
input
都有一个唯一的ID,每个output
元素使用for
属性通过这个id引用输入 - 这对于可访问性,但当我们想要解析值并更新输出时会派上用场。 - 我们还有一个使用相同 ID 的单价附加数据属性,请注意,该数据属性没什么特别的,只是为我们提供了一种“查找”相关价格的方法。无需为这个简单的情况创建 Controller 目标。
- 注意:这假设您不必支持 IE11(因为输出元素在该浏览器中不起作用)。
<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( Controller )
- 除了总目标之外,我们的 Controller 实际上不需要任何其他内容,因为我们可以在基本表单的附加 Controller 上使用
this.element
。 - 我们避免使用通用的
update
方法,并尝试使用updateTotals
实现更具体的方法。 - 我们在表单上使用
elements
API 来获取名为'item-total'
的元素(请注意,不会提交输出名称)。 https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/elements - 一旦我们有了每个输出元素,我们就可以通过
for
和输入的 id 以及数据属性找到相关的输入元素来查找价格。 - 然后我们计算总计并最终更新 DOM 中的所有值。
- 注意:数字解析非常基础,最好在这里添加一些安全性,而且我们假设您不需要支持 IE11。
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 });
}
}
关于javascript - StimulusJS 如何根据不同子 Controller 中的值计算父 Controller 中的值(购物车 -> 购物车项目),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72476371/