如何用Vue和Dinero.js建立购物车
入门
对于这个项目,我们将使用 vue-cli 和简单的 webapp-Vue.js 模板。如果您的计算机上没有全局安装 vue-cli,请启动您的终端并输入以下内容:
npm install -g vue-cli
然后:
vue init webpack-simple path/to/my-project
您可以保留所有问题的默认选项。完成后,导航到新目录,安装依赖项,然后运行项目:
cd path/to/my-project npm install npm run dev
Webpack 将开始在端口上为您的项目提供服务 8080(如果可用)并在您的浏览器中打开它。
设置 HTML/CSS
在本教程中,我不会涉及页面结构和样式,所以我邀请您复制/粘贴代码。打开 App.vue 文件并粘贴以下代码片段。
这在<template>标签之间:
<div id =“app”>
<div class =“cart”>
<h1 class =“title”>订单</ h1>
<ul class =“items”>
<li class =“item”>
<div class =“ item-preview“>
<img src =”“alt =”“class =”item-thumbnail“>
<div>
<h2 class =”item-title“> </ h2>
<p class =”item-description“> </ p>
</ div>
</ div>
<div>
<input type =“text”class =“item-quantity”>
<span class =“item-price”> </ span>
</ DIV>
</ LI>
</ UL>
<H3 类= “购物车线”>
小计<跨度类= “购物价格”> </跨度>
</ H3>
<H3 类= “购物车线” >
运费<span class =“cart-price”> </ span>
</ h3>
<h3 class =“cart-line”>
总计<span class =“cart-price cart-total”> </ span>
</ h3 >
</ div>
</ div>
CSS 样式:
body {
margin: 0;
background: #fdca40;
padding: 30px;
}
.title {
display: flex;
justify-content: space-between;
align-items: center;
margin: 0;
text-transform: uppercase;
font-size: 110%;
font-weight: normal;
}
.items {
margin: 0;
padding: 0;
list-style: none;
}
.cart {
background: #fff;
font-family: 'Helvetica Neue', Arial, sans-serif;
font-size: 16px;
color: #333a45;
border-radius: 3px;
padding: 30px;
}
.cart-line {
display: flex;
justify-content: space-between;
align-items: center;
margin: 20px 0 0 0;
font-size: inherit;
font-weight: normal;
color: rgba(51, 58, 69, 0.8);
}
.cart-price {
color: #333a45;
}
.cart-total {
font-size: 130%;
}
.item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15px 0;
border-bottom: 2px solid rgba(51, 58, 69, 0.1);
}
.item-preview {
display: flex;
align-items: center;
}
.item-thumbnail {
margin-right: 20px;
border-radius: 3px;
}
.item-title {
margin: 0 0 10px 0;
font-size: inherit;
}
.item-description {
margin: 0;
color: rgba(51, 58, 69, 0.6);
}
.item-quantity {
max-width: 30px;
padding: 8px 12px;
font-size: inherit;
color: rgba(51, 58, 69, 0.8);
border: 2px solid rgba(51, 58, 69, 0.1);
border-radius: 3px;
text-align: center;
}
.item-price {
margin-left: 20px;
}
添加数据
在处理产品时,您通常会从数据库或 API 中检索原始数据。我们可以通过在单独的 JSON 文件中表示它,然后异步地导入它,就像查询 API 一样。
我们创建一个 products.json 文件 assets/并添加以下内容:
{
"items": [
{
"title": "Item 1",
"description": "A wonderful product",
"thumbnail": "https://fakeimg.pl/80x80",
"quantity": 1,
"price": 20
},
{
"title": "Item 2",
"description": "A wonderful product",
"thumbnail": "https://fakeimg.pl/80x80",
"quantity": 1,
"price": 15
},
{
"title": "Item 3",
"description": "A wonderful product",
"thumbnail": "https://fakeimg.pl/80x80",
"quantity": 2,
"price": 10
}
],
"shippingPrice": 20
}
这与我们从真实 API 获得的数据非常相似:数据作为集合,标题和文本作为字符串,数量和价格作为数字。
我们可以返回 App.vue 并设置空值 data。这将允许模板在获取实际数据时进行初始化。
data(){
return {
data:{
items:[],
shippingPrice:0
}
}
}
最后,我们可以从 products.json 异步请求中获取数据,并 data 在其准备就绪时更新属性:
export default {
...
created() {
fetch('./src/assets/products.json')
.then(response => response.json())
.then(json => (this.data = json))
}
}
现在让我们用这些数据填充我们的模板:
<ul class="items">
<li :key="item.id" v-for="item in data.items" class="item">
<div class="item-preview">
<img :src="item.thumbnail" :alt="item.title" class="item-thumbnail">
<div>
<h2 class="item-title">{{ item.title }}</h2>
<p class="item-description">{{ item.description }}</p>
</div>
</div>
<div>
<input type="text" class="item-quantity" v-model="item.quantity">
<span class="item-price">{{ item.price }}</span>
</div>
</li>
</ul>
...
<h3 class="cart-line">
Shipping
<span class="cart-price">{{ data.shippingPrice }}</span>
</h3>
...
你应该看到你的购物车中的所有物品。现在让我们添加一些计算属性来计算小计和总计:
export default {
...
computed: {
getSubtotal() {
return this.data.items.reduce(
(a, b) => a + b.price * b.quantity,
0
)
},
getTotal() {
return (
this.getSubtotal + this.data.shippingPrice
)
}
}
}
并将它们添加到我们的模板中:
<h3 class="cart-line">
小计
<span class="cart-price">{{ getSubtotal }}</span>
</h3>
...
<h3 class="cart-line">
总计
<span class="cart-price cart-total">{{ getTotal }}</span>
</h3>
尝试改变数量-你应该看到小计和总金额相应变化。
现在我们在这里有几个问题。首先,我们只显示金额,而不是货币。当然,我们可以在反应量旁边的模板中对它们进行硬编码。但是如果我们想制作一个多语言网站呢?并非所有的语言都以相同的方式进行金钱化
如果我们想要显示所有金额的小数点后两位,以便更好地对齐?您可以尝试使用该 toFixed 方法将所有初始金额保留为浮点数,但那时您将使用的 String 类型在进行数学运算时难度更大,性能更低。而且,这意味着为了纯粹的表达目的而改变数据,这从来不是一个好主意。如果您需要将相同的数据用于其他目的并且需要不同的格式?
最后,当前的解决方案依赖于浮点数学,这对于处理金钱来说是个坏主意。尝试并更改一些金额:
{
"items": [
{
...
"price": 20.01
},
{
...
"price": 15.03
},
...
]
}
现在,看看您的购物车是如何损坏的?这不是一些错误的 JavaScript 行为,而是我们如何用二进制机器表示我们的小数编号系统的限制。如果你用花车做数学,你迟早会遇到那些不准确的。
好消息是,我们不必使用花车来存储钱。这正是 Dinero.js 发挥作用的地方。
Dinero.js,金钱包装
Dinero.js 之于金钱,正如 Moment.js 之于日期。它是一个库,允许您创建货币价值对象、操作它们、向它们提问并格式化它们。它依赖于 Martin Fowler 的货币模式,并帮助您解决由浮点数引起的所有常见问题,主要方法是将金额以整数的形式存储在较小的货币单位中。
打开终端,安装 Dinero.js:
npm install dinero.js --save
然后将其导入到 App.vue:
import Dinero from 'dinero.js'
export default {
...
}
现在可以创建 Dinero 对象:
// 返回 Dinero 对象,金额为$ 50
Dinero({ amount: 500, currency: 'USD' })
// 返回$ 4,000.00
Dinero({ amount: 500 })
.add(Dinero({ amount: 500 }))
.multiply(4)
.toFormat()
让我们创建一个工厂方法,将我们的 price 属性按需转换为 Dinero 对象。我们有最多两位小数的浮点数。这意味着如果我们想要以次要货币单位(在我们的情况下为美元)将它们转换为它们的等价物,我们需要将它们乘以 10 来乘以 2 的幂。
我们将该 factor 参数作为参数传递给默认值,以便我们可以使用具有不同指数的货币的方法。
export default {
...
methods: {
toPrice(amount, factor = Math.pow(10, 2)) {
return Dinero({ amount: amount * factor })
}
}
}
美元是默认货币,所以我们不需要指定它。
因为我们在转换过程中正在进行浮点数学运算,所以有些计算结果可能会稍微不准确。通过将结果四舍五入到最接近的整数很容易解决。
toPrice(amount, factor = Math.pow(10, 2)) {
return Dinero({ amount: Math.round(amount * factor) })
}
现在我们可以 toPrice 在我们的计算属性中使用:
export default {
...
computed: {
getShippingPrice() {
return this.toPrice(this.data.shippingPrice)
},
getSubtotal() {
return this.data.items.reduce(
(a, b) =>
a.add(
this.toPrice(b.price).multiply(b.quantity)
),
Dinero()
)
},
getTotal() {
return this.getSubtotal.add(this.getShippingPrice)
}
}
}
在我们的模板中:
<ul class="items">
<li :key="item.id" v-for="item in data.items" class="item">
<div class="item-preview">
<img :src="item.thumbnail" :alt="item.title" class="item-thumbnail">
<div>
<h2 class="item-title">{{ item.title }}</h2>
<p class="item-description">{{ item.description }}</p>
</div>
</div>
<div>
<input type="text" class="item-quantity" v-model="item.quantity">
<span class="item-price">{{ toPrice(item.price) }}</span>
</div>
</li>
</ul>
<h3 class="cart-line">
Subtotal
<span class="cart-price">{{ getSubtotal }}</span>
</h3>
<h3 class="cart-line">
Shipping
<span class="cart-price">{{ getShippingPrice }}</span>
</h3>
<h3 class="cart-line">
Total
<span class="cart-price cart-total">{{ getTotal }}</span>
</h3>
如果你看看你的购物车,你会看到{}价格的地方。这是因为我们试图显示一个对象。相反,我们需要对它们进行格式化,以便它们可以使用正确的语法显示价格以及货币符号。
我们可以用 Dinero 的 toFormat 方法来实现这一点。
<ul class="items">
<li :key="item.id" v-for="item in data.items" class="item">
...
<div>
...
<span class="item-price">
{{ toPrice(item.price).toFormat() }}
</span>
</div>
</li>
</ul>
<h3 class="cart-line">
Subtotal
<span class="cart-price">
{{ getSubtotal.toFormat() }}
</span>
</h3>
<h3 class="cart-line">
Shipping
<span class="cart-price">
{{ getShippingPrice.toFormat() }}
</span>
</h3>
<h3 class="cart-line">
Total
<span class="cart-price cart-total">
{{ getTotal.toFormat() }}
</span>
</h3>
现在你已经掌握了 Dinero.js 的基本知识,现在有时间来提升吧。
介绍
让我们 shippingPrice 转到 0JSON 文件。您的购物车现在应该显示“运费:$0.00”,这是准确的,但不便于用户使用。它会说“免费”更好吗?
幸运的是,Dinero.js 有很多方便的方法来向您的实例提问。在我们的例子中,这个 isZero 方法正是我们需要的。
在模板中,只要表示零,就可以显示文本而不是格式化的 Dinero 对象:
<h3 class="cart-line">
Shipping
<span class="cart-price">
{{
getShippingPrice.isZero() ?
'Free' :
getShippingPrice.setLocale(getLocale).toFormat()
}}
</span>
</h3>
当然,你可以通过将它包装在一个方法中来概括这种行为。这将需要一个 Dinero 对象作为参数并返回一个 String。这样,只要您尝试显示零金额,就可以显示“免费”。
区域设置切换
想象一下你正在制作一个电子商务网站。你想适应你的国际观众,所以你翻译内容并添加一个语言切换器。但是,有一个细节可能会引起您的注意:货币格式也会根据语言而变化。例如,在美国英语中 10.00 欧元翻译为法语中的 10,00 欧元。
Dinero.js 通过 I18n API 支持国际格式。这可让您以本地化格式显示金额。
Dinero.js 是不可变的,所以我们不能依靠改变 Dinero.globalLocale 来重新格式化所有现有的实例。相反,我们需要使用该 setLocale 方法。
首先,我们添加了一个新的属性 language 中 data,并将其设置为默认值。对于语言环境,您需要使用 BCP 47 语言标签,如 en-US。
data() {
return {
data: {
...
},
language: 'en-US'
}
}
现在我们可以直接在 Dinero 对象上使用 setLocale。当语言发生变化时,格式也会发生变化。
export default {
...
methods: {
toPrice(amount, factor = Math.pow(10, 2)) {
return Dinero({ amount: Math.round(amount * factor) })
.setLocale(this.language)
}
},
computed: {
...
getSubtotal() {
return this.data.items.reduce(
(a, b) =>
a.add(
this.toPrice(b.price).multiply(b.quantity)
),
Dinero().setLocale(this.language)
)
},
...
}
}
我们只需要在 toPrice 和 getSubtotal 中添加 setLocale,这是我们创建 Dinero 对象的唯一位置。
现在我们可以添加语言切换器:
// HTML
<h1 class="title">
Order
<span>
<span class="language" @click="language = 'en-US'">English</span>
<span class="language" @click="language = 'fr-FR'">French</span>
</span>
</h1>
// CSS
.language {
margin: 0 2px;
font-size: 60%;
color: rgba(#333a45, 0.6);
text-decoration: underline;
cursor: pointer;
}
当您单击切换器时,它将重新分配语言,这将更改对象的格式化方式。因为库是不可变的,这将返回新的对象,而不是更改现有的对象。这意味着,如果您创建一个 Dinero 对象并决定在某个地方显示它,然后在其他地方引用它并在其上应用 setLocale,那么您的初始实例将不会受到影响。没有讨厌的副作用!
所有含税
在购物车上看到一条税收线是很常见的。你可以用百分比法添加 Dinero.js
首先,让我们在 JSON 文件中添加一个 vatRate 属性:
{
...
"vatRate": 20
}
数据的初值:
data() {
return {
data: {
...
vatRate: 0
}
}
}
现在我们可以用这个值来计算我们的带税购物车的总数。首先,我们需要创建一个 getTaxAmount computed 属性。然后我们也可以将它添加到 getTotal 中。
export default {
...
computed: {
getTaxAmount() {
return this.getSubtotal.percentage(this.data.vatRate)
},
getTotal() {
return this.getSubtotal
.add(this.getTaxAmount)
.add(this.getShippingPrice)
}
}
}
购物车现在显示了含税总额。我们也可以加一行来显示税额是多少:
<h3 class="cart-line">
VAT ({{ data.vatRate }}%)
<span class="cart-price">{{ getTaxAmount.toFormat() }}</span>
</h3>
结束语
到这儿文章就将如何用 Vue 和 Dinero.js 建立购物车就完成了!小编带大家已经探讨了 Dinero 的几个概念。但这只是它所能提供的服务的皮毛。如果你感兴趣的话可以阅读文档并在 GitHub 上查看项目。
以上关于如何用Vue和Dinero.js建立购物车的文章就介绍到这了,更多相关内容请搜索码云笔记以前的文章或继续浏览下面的相关文章,希望大家以后多多支持码云笔记。
如若内容造成侵权/违法违规/事实不符,请将相关资料发送至 admin@mybj123.com 进行投诉反馈,一经查实,立即处理!
重要:如软件存在付费、会员、充值等,均属软件开发者或所属公司行为,与本站无关,网友需自行判断
码云笔记 » 如何用Vue和Dinero.js建立购物车

微信
支付宝