vue组件之间如何共享数据?
How to share data between vue components?
我不是 javascript 开发人员,我的工作是将我构建的 API 连接到第三方用 vuejs 编写的一些前端代码。我正在尝试访问 'shopping cart' 以将详细信息发送到服务器。我很难确定什么是 child 或 parent。流程如下:
- 一个。 Select让步
- 乙。 Select 要添加到购物车的商品
- C。去购物车
- D.结帐
这是产品卡片
<template>
<div class="flex flex-col flex-wrap justify-center items-center w-1/3 px-12">
<img :src="require(`../../assets/images/` + backgroundImg)" :alt="product.id">
<h5 class="font-bold text-lg mt-2">{{ product.title }}</h5>
<p class="text-15px text-gray-500 ">{{ product.short }}</p>
<p class="text-15px text-gray-500 px-8">{{ product.long }}</p>
<p class="text-base font-bold">${{ formatPrice(product.price) }}</p>
<Button @click.native="$emit('add-cart', product)" msg="Add to Cart" class="bg-seafoam rounded-md lg:text-sm lg:px-8 text-white mt-1"></Button>
</div>
</template>
<script>
import Button from '../Button.vue';
export default {
name: 'ProductCard',
components: {
Button
},
props: {
product: Object
},
data() {
return {
backgroundImg: this.product.image,
}
},
methods: {
formatPrice(value) {
let val = (value/1).toFixed(2)
return val.toLocaleString("en", {useGrouping: false, minimumFractionDigits: 2,})
}
}
}
</script>
这是产品列表代码
<template>
<div>
<span v-if="!hideMenu">
<MenuHero v-if="!viewCart" :locationName="locationName" :selectedVendor="selectedVendor" />
</span>
<CartHero v-if="viewCart" />
<CheckoutHero v-if="showCheckout" />
<div class="lg:px-40 pt-4 pb-16 m-auto max-w-" :class="{ 'bg-bgBlue': showCheckout, 'max-w-screen-2xl': !showCheckout }">
<div v-if="!hideBreadcrumb" class="breadcrumbs flex mb-6 ml-6">
<a href="/OrderResturantPicker" class="text-left mt-6 mb-12 lg:pl-0 text-sm lg:text-base bg-arrowRight font-bold text-darkBlueText bg-no-repeat bg-right bg-5px lg:bg-8px pr-3 lg:pr-6">Choose Restaurant</a>
<a @click="viewCart = false" class="text-left mt-6 mb-12 text-sm lg:text-base bg-arrowRight font-bold text-darkBlueText bg-no-repeat bg-right bg-5px lg:bg-8px pr-3 lg:pr-6 pl-1 lg:pl-4" >Choose Meal</a>
<a v-if="viewCart" class="breadcrumb text-left mt-6 mb-12 text-sm lg:text-base font-bold text-darkBlueText bg-no-repeat bg-right bg-5px lg:bg-8px pr-3 lg:pr-6 pl-1 lg:pl-4">View Cart</a>
</div>
<div class="flex flex-wrap section-wrapper">
<div v-if="!hideMenu" class="flex flex-wrap section-wrapper">
<div v-for="product in menu" :key="product.id" v-show="!viewCart" :class="{ sectionTitle: product.section }" class="flex flex-col w-full lg:mb-0 mb-6 lg:w-1/3">
<div v-if="product.section" class="text-left w-full text-darkBlueText lg:text-xl font-bold">{{ product.section }}</div>
<ProductCard @add-cart="addToCart(product)" :product="product" class="locationOption w-full flex py-2 px-6 lg:py-2 rounded-sm rounded-b-none text-gray-600 lg:text-lg md:text-base text-13px text-center cursor-pointer" />
</div>
</div>
<CartList :cart="cart" v-if="viewCart" @show-checkout="showCheckoutScreen()" :totalPrice="totalPrice" :product="product"/>
<CartWidget :cart="cart" v-if="!viewCart && showCartWidget" :itemCount="itemCount" @view-cart="viewCart = !viewCart" :totalPrice="totalPrice"/>
<Checkout :cart="cart" :product="product" :totalPrice="totalPrice" v-if="showCheckout" />
</div>
</div>
</div>
</template>
<script>
import ProductCard from './ProductCard'
import CartList from './TheCartList'
import CartWidget from './CartWidget'
import Checkout from './Checkout'
import MenuHero from '../heros/MenuHero'
import CartHero from '../heros/CartHero'
import CheckoutHero from '../heros/CheckoutHero'
export default {
name: 'ProductList',
components: {
MenuHero,
CartHero,
CheckoutHero,
ProductCard,
CartList,
CartWidget,
Checkout,
},
props: {
menu: Array,
locationName: String,
selectedVendor: String,
},
data() {
return {
cart: [],
showCartWidget: false,
itemCount: 0,
totalPrice: 0,
viewCart: false,
showCheckout: false,
hideMenu: false,
hideBreadcrumb: false,
}
},
methods: {
calculateTotal(item) {
this.totalPrice += item.price
},
addToCart(product) {
if(this.cart.includes(product)){
product.quantity++
this.itemCount++
this.calculateTotal(product)
} else {
this.cart.push(product)
this.itemCount++
this.calculateTotal(product)
this.showCartWidget = true
}
},
showCheckoutScreen() {
this.showCheckout = true
this.viewCart = false
this.showCartWidget = false
this.hideMenu = true
this.hideBreadcrumb = true
}
},
}
</script>
----------
This is the cart list code
<template>
<div class="w-full">
<div class="cart-heading-wrapper flex justify-between text-darkBlueText lg:text-xl font-bold">
<h5 class="w-1/3 text-left">Item Name</h5>
<h5 class="w-1/3 text-center ml-2 pl-16">Quantity</h5>
<h5 class="w-1/3 text-right">Item Price</h5>
</div>
<div class="grid border-b border-gray-400">
<div v-for="product in cart" :key="product.id" class="py-4 border-t border-gray-400">
<CartCard :product="product" :totalPrice="totalPrice" @incremented="calculateTotal(product)" @decremented="decrementTotal(product)" class="locationOption w-full flex py-2 lg:py-2 rounded-sm rounded-b-none text-gray-600 lg:text-lg md:text-base text-13px text-center cursor-pointer" />
</div>
</div>
<div class="flex flex-col justify-start float-right">
<div class="mb-4 px-28 mt-8 flex justify-between"><span class="mr-24 text-xl text-darkBlueText font-bold">Tax:</span><span class="text-2xl text-darkBlueText font-bold">${{taxes}}</span></div>
<div class="mb-4 px-28 flex justify-between"><span class="mr-24 text-xl text-darkBlueText font-bold">Fees:</span><span class="text-2xl text-darkBlueText font-bold">${{ fees }} </span></div>
<div class="border-t border-gray-500 mb-12 px-28 pt-4 flex justify-between"><span class="mr-24 text-2xl text-darkBlueText font-bold">Total:</span><span class="text-2xl text-darkBlueText font-bold">${{ formatPrice(totalPrice) }}</span></div>
</div>
<div class="w-full flex justify-between">
<div class="flex flex-col">
<button class="py-2 px-16 mb-2 bg-white border-2 border-darkBlueText text-darkBlueText text-lg font-bold">Back to Menu</button>
<a class="underline" href="#">Browse Restaurants </a>
</div>
<span>
<button class="px-6 py-3 text-white font-bold bg-seafoam rounded-sm text-lg" @click="$emit('show-checkout')">Proceed To Checkout</button>
</span>
</div>
</div>
</template>
<script>
import CartCard from './CartCard';
export default {
name: 'CartList',
components: {
CartCard,
},
props: {
cart: Array,
totalPrice: Number,
product: Object,
},
data() {
return {
taxes: 0,
fees: 0,
grandTotal: 0,
}
},
methods: {
formatPrice(value) {
let val = (value/1).toFixed(2)
return val.toLocaleString("en", {useGrouping: false, minimumFractionDigits: 2,})
},
calculateTotal(item) {
this.totalPrice += item.price
},
decrementTotal(item) {
this.totalPrice -= item.price
},
},
}
</script>
购物车小部件代码
<template>
<div class="translateCenter left-1/2 m-auto w-1/2 max-w-5xl py-5 px-6 border flex justify-between bg-white fixed bottom-10 border-black rounded-md">
<div class="font-bold flex items-center">
<div class="bg-cartImage w-7 h-7 mr-2 font-bold bg-no-repeat bg-cover text-15px bg-right pr-5"></div>
{{ itemCount }} Item(s)
</div>
<div class="flex items-center flex-grow ml-16">
<div class="rounded-full bg-black h-3 w-3 mr-4"></div>
<div class="flex items-center pt-px">
<strong class="mr-2">Total:</strong> ${{ formatPrice(totalPrice) }}
</div>
</div>
<div class="flex items-center">
<div @click="$emit('view-cart')" class="bg-arrowRight font-bold bg-no-repeat bg-8px text-15px bg-right pr-5">View Cart</div>
</div>
</div>
</template>
<script>
export default {
name: "CartWidget",
props: {
cart: Array,
itemCount: Number,
totalPrice: Number,
},
data() {
return {
total: 0,
}
},
methods: {
formatPrice(value) {
let val = (value/1).toFixed(2)
return val.toLocaleString("en", {useGrouping: false, minimumFractionDigits: 2,})
}
}
}
</script>
购物车卡片代码
<template>
<div class="flex flex-col flex-wrap justify-center items-center w-1/3">
<div class="flex justify-between items-center w-full">
<div class="flex w-1/3">
<img class="w-32 h-32" :src="require(`../../assets/images/` + backgroundImg)" :alt="product.id">
<div class="flex flex-col justify-center ml-4 text-left">
<h5 class="mb-4 text-xl text-darkBlueText font-bold">{{ product.title }}</h5>
<p class="text-15px text-gray-500 leading-5">{{ product.short }}</p>
<p class="text-15px text-gray-500 leading-5 whitespace-nowrap overflow-ellipsis overflow-hidden block w-3/4">{{ product.long }}</p>
</div>
</div>
<Quantity class="font-bold" :product="product" :totalPrice="totalPrice" @incremented="incremented()" @decremented="decremented()" />
<p class="font-bold">${{ formatPrice(product.price) }}</p>
</div>
</div>
</template>
<script>
import Quantity from './Quantity';
export default {
name: 'ProductCard',
components: {
Quantity
},
props: {
product: Object,
totalPrice: Number
},
data() {
return {
backgroundImg: this.product.image,
cart: []
}
},
methods: {
formatPrice(value) {
let val = (value/1).toFixed(2)
return val.toLocaleString("en", {useGrouping: false, minimumFractionDigits: 2,})
},
incremented() {
this.$emit('incremented')
},
decremented() {
this.$emit('decremented')
}
}
}
</script>
和结帐代码
<template>
<div>
<div class="apply-wrapper bg-bgBlue lg:p-32 lg:pt-12">
<div class="form-wrapper lg:bg-white rounded-2xl bg-bgBlue py-6 px-8 lg:py-12 lg:px-32 lg:shadow-lg max-w-screen-2xl m-auto">
<form class="lg:flex flex-wrap m-auto">
<h4 class="text-darkBlueText text-center text-xl font-bold mb-12 w-full">Contact and Delivery Information</h4>
<div class="mb-8 lg:mb-4 text-left text-lg lg:text-xl lg:w-1/2 lg:pr-12">
<label for="FirstName">First Name</label>
<input v-model="firstName" class="mt-2 h-8 lg:h-10 appearance-none border rounded border-black w-full py-3 px-3 text-gray-700 text-sm leading-tight" id="firstname" type="text" name="FirstName" required>
</div>
<div class="mb-7 lg:mb-4 text-left text-lg lg:text-xl lg:w-1/2 lg:pl-12">
<label for="LastName">Last Name</label>
<input v-model="lastName" class="mt-2 h-8 lg:h-10 text-sm appearance-none rounded border border-black w-full py-3 px-3 text-gray-700 mb-3 leading-tight" id="lastname" type="text" name="LastName" required>
</div>
<div class="mb-8 lg:mb-4 text-left text-lg lg:text-xl lg:w-1/2 lg:pr-12">
<label for="PhoneNumber">Phone Number</label>
<input v-model="phone" class="mt-2 h-8 lg:h-10 lg:mt-1 appearance-none rounded border border-black w-full py-3 px-3 text-gray-700 text-sm leading-tight" id="phonenumber" type="tel" name="PhoneNumber" required>
</div>
<div class="mb-8 lg:mb-4 text-left text-lg lg:text-xl lg:w-1/2 lg:pl-12">
<label for="EmailAddress">Email Address</label>
<input v-model="email" class="mt-2 h-8 lg:h-10 lg:mt-1 appearance-none rounded border border-black w-full py-3 px-3 text-gray-700 text-sm leading-tight" id="emailaddress" type="email" name="EmailAddress" required>
</div>
<div class="mb-8 lg:mb-4 inline-block text-left text-lg lg:text-xl w-1/2 pr-2 lg:pr-12">
<label for="Terminal" class="whitespace-nowrap">Terminal</label>
<input v-model="terminal" class="mt-2 h-8 lg:h-10 lg:mt-1 text-sm appearance-none rounded border border-black w-full py-3 px-3 text-gray-700 mb-3 leading-tight" id="terminal" type="text" name="Terminal" required>
</div>
<div class="mb-8 lg:mb-4 inline-block text-left text-lg lg:text-xl w-1/2 pl-2 lg:pl-12">
<label for="Gate">Gate</label>
<input v-model="gate" class="mt-2 h-8 lg:h-10 lg:mt-1 text-sm appearance-none rounded border border-black w-full py-3 px-3 text-gray-700 mb-3 leading-tight" id="gate" type="text" name="Gate" required>
</div>
<div class="w-1/2 m-auto">
<div class="mb-8 lg:mb-4 inline-block text-left text-lg lg:text-xl w-1/2 pl-2 lg:pl-12">
<label for="Tip">Leave A Tip?</label>
<currency-input v-model="tip" id="leaveATip" currency="USD" name="Tip" class="mt-2 h-8 lg:h-10 lg:mt-1 text-sm appearance-none rounded border border-black w-full py-3 px-3 text-gray-700 mb-3 leading-tight" />
</div>
<div>
<label for="DeliveryDate" class="block w-full">When Should We Deliver?</label>
<input v-model="date" type="date" id="DeliveryDateTime" name="DeliveryDate"
value="Today"
min="2021-01-01" max="2040-12-31" required>
<input v-model="time" type="time" id="delTime" name="DeliveryTime"
min="00:00" max="23:59" required>
</div>
</div>
<!-- stripe div -->
<section class="row payment-form">
<h5 class="#e0e0e0 grey lighten-4">
Payment Method
<span class="right"></span>
</h5>
<div class="error red center-align white-text"> {{stripeValidationError}}</div>
<div class="col s12 card-element">
<label>Card Number</label>
<div id="card-number-element" class="input-value"></div>
</div>
<div class="col s6 card-element">
<label>Expiry Date</label>
<div id="card-expiry-element"></div>
</div>
<div class="col s6 card-element">
<label>CVC</label>
<div id="card-cvc-element"></div>
</div>
<div class="col s12 place-order-button-block">
<button class="btn col s12 #e91e63 pink" @click="placeOrderButtonPressed">Place Order</button>
</div>
</section>
<CartList :cart="cart" v-if="viewCart" :totalPrice="totalPrice" :product="product"/>
</form>
</div>
</div>
</div>
</template>
<script>
import ProductList from "./ProductList";
export default {
name: 'Checkout',
components: {
ProductList,
},
props: {
cart: Array
},
data(){
console.log("[DEBUG 1]: " + this.cart + " " + this.cart.product.id + " " + this.cart.product.short);
return {
viewCart: true,
stripe: null,
cardNumberElement:null,
cardExpiryElement:null,
cardCVCElement:null,
stripeValidationError:null,
firstName:'',
lastName:'',
phone:'',
email:'',
terminal:'',
gate:'',
tip:'',
amount:25,
}
},
mounted(){
this.stripe = new Stripe("MY_KEY");
this.init();
this.testCart();
},
methods: {
testCart(){
console.log("[DEBUG 3]: " + this.cart + " " + this.cart.product.id + " " + this.cart.product.short);
this.cart.printCart();
},
init(){
// invoke and mount
var elements = this.stripe.elements();
this.cardNumberElement = elements.create("cardNumber");
this.cardNumberElement.mount("#card-number-element");
this.cardExpiryElement = elements.create("cardExpiry");
this.cardExpiryElement.mount("#card-expiry-element");
this.cardCVCElement = elements.create("cardCvc");
this.cardCVCElement.mount("#card-cvc-element");
// change events
this.cardNumberElement.on("change", this.setValidationError);
this.cardExpiryElement.on("change", this.setValidationError);
this.cardCVCElement.on("change", this.setValidationError);
},
setValidationError(event){
this.stripeValidationError = event.error ? event.error.message : "";
},
async processToken(data){
const response = await fetch('https://asite.azurewebsites.net/api/payment', {
method: 'POST',
headers: {
'Accept':'application/json',
'Access-Control-Allow-Origin':'*'
},
body: JSON.stringify(data)
});
const content = await response;
console.log(content);
if(content[2] === "True")
{
// success
// create a new swift oder
// how do I get access to the cart?
}
},
placeOrderButtonPressed(){
this.stripe.createToken(this.cardNumberElement).then(result => {
if(result.error){
this.stripeValidationError = result.error.message;
}
else {
var json = {
amount: this.amount,
source: result.token.id
}
this.processToken(json);
}
});
}
}
};
</script>
我想访问购物车中的商品,这样我就可以向服务器发出 post 调用。但我似乎无法做到这一点。
我不需要在屏幕上显示项目或其他任何东西。我只是想访问购物车,它似乎是一个总计项目的数组。
谁能指出我正确的方向?
顺便说一句,产品是一个 object,具有 ID、标题、简短描述、详细描述、价格和默认数量 1。
您的 cart
在您的 ProductList
中定义。您在该组件内实现所有其他组件,因此它是父组件。它可以通过添加 :cart="cart"
属性 将购物车中的项目分配给所有其他组件。为了让子组件访问它,他们只需要在收到的道具中声明 cart
:
props: {
cart: Array
}
然后您可以在子组件中访问this.cart
。
我不是 javascript 开发人员,我的工作是将我构建的 API 连接到第三方用 vuejs 编写的一些前端代码。我正在尝试访问 'shopping cart' 以将详细信息发送到服务器。我很难确定什么是 child 或 parent。流程如下:
- 一个。 Select让步
- 乙。 Select 要添加到购物车的商品
- C。去购物车
- D.结帐
这是产品卡片
<template>
<div class="flex flex-col flex-wrap justify-center items-center w-1/3 px-12">
<img :src="require(`../../assets/images/` + backgroundImg)" :alt="product.id">
<h5 class="font-bold text-lg mt-2">{{ product.title }}</h5>
<p class="text-15px text-gray-500 ">{{ product.short }}</p>
<p class="text-15px text-gray-500 px-8">{{ product.long }}</p>
<p class="text-base font-bold">${{ formatPrice(product.price) }}</p>
<Button @click.native="$emit('add-cart', product)" msg="Add to Cart" class="bg-seafoam rounded-md lg:text-sm lg:px-8 text-white mt-1"></Button>
</div>
</template>
<script>
import Button from '../Button.vue';
export default {
name: 'ProductCard',
components: {
Button
},
props: {
product: Object
},
data() {
return {
backgroundImg: this.product.image,
}
},
methods: {
formatPrice(value) {
let val = (value/1).toFixed(2)
return val.toLocaleString("en", {useGrouping: false, minimumFractionDigits: 2,})
}
}
}
</script>
这是产品列表代码
<template>
<div>
<span v-if="!hideMenu">
<MenuHero v-if="!viewCart" :locationName="locationName" :selectedVendor="selectedVendor" />
</span>
<CartHero v-if="viewCart" />
<CheckoutHero v-if="showCheckout" />
<div class="lg:px-40 pt-4 pb-16 m-auto max-w-" :class="{ 'bg-bgBlue': showCheckout, 'max-w-screen-2xl': !showCheckout }">
<div v-if="!hideBreadcrumb" class="breadcrumbs flex mb-6 ml-6">
<a href="/OrderResturantPicker" class="text-left mt-6 mb-12 lg:pl-0 text-sm lg:text-base bg-arrowRight font-bold text-darkBlueText bg-no-repeat bg-right bg-5px lg:bg-8px pr-3 lg:pr-6">Choose Restaurant</a>
<a @click="viewCart = false" class="text-left mt-6 mb-12 text-sm lg:text-base bg-arrowRight font-bold text-darkBlueText bg-no-repeat bg-right bg-5px lg:bg-8px pr-3 lg:pr-6 pl-1 lg:pl-4" >Choose Meal</a>
<a v-if="viewCart" class="breadcrumb text-left mt-6 mb-12 text-sm lg:text-base font-bold text-darkBlueText bg-no-repeat bg-right bg-5px lg:bg-8px pr-3 lg:pr-6 pl-1 lg:pl-4">View Cart</a>
</div>
<div class="flex flex-wrap section-wrapper">
<div v-if="!hideMenu" class="flex flex-wrap section-wrapper">
<div v-for="product in menu" :key="product.id" v-show="!viewCart" :class="{ sectionTitle: product.section }" class="flex flex-col w-full lg:mb-0 mb-6 lg:w-1/3">
<div v-if="product.section" class="text-left w-full text-darkBlueText lg:text-xl font-bold">{{ product.section }}</div>
<ProductCard @add-cart="addToCart(product)" :product="product" class="locationOption w-full flex py-2 px-6 lg:py-2 rounded-sm rounded-b-none text-gray-600 lg:text-lg md:text-base text-13px text-center cursor-pointer" />
</div>
</div>
<CartList :cart="cart" v-if="viewCart" @show-checkout="showCheckoutScreen()" :totalPrice="totalPrice" :product="product"/>
<CartWidget :cart="cart" v-if="!viewCart && showCartWidget" :itemCount="itemCount" @view-cart="viewCart = !viewCart" :totalPrice="totalPrice"/>
<Checkout :cart="cart" :product="product" :totalPrice="totalPrice" v-if="showCheckout" />
</div>
</div>
</div>
</template>
<script>
import ProductCard from './ProductCard'
import CartList from './TheCartList'
import CartWidget from './CartWidget'
import Checkout from './Checkout'
import MenuHero from '../heros/MenuHero'
import CartHero from '../heros/CartHero'
import CheckoutHero from '../heros/CheckoutHero'
export default {
name: 'ProductList',
components: {
MenuHero,
CartHero,
CheckoutHero,
ProductCard,
CartList,
CartWidget,
Checkout,
},
props: {
menu: Array,
locationName: String,
selectedVendor: String,
},
data() {
return {
cart: [],
showCartWidget: false,
itemCount: 0,
totalPrice: 0,
viewCart: false,
showCheckout: false,
hideMenu: false,
hideBreadcrumb: false,
}
},
methods: {
calculateTotal(item) {
this.totalPrice += item.price
},
addToCart(product) {
if(this.cart.includes(product)){
product.quantity++
this.itemCount++
this.calculateTotal(product)
} else {
this.cart.push(product)
this.itemCount++
this.calculateTotal(product)
this.showCartWidget = true
}
},
showCheckoutScreen() {
this.showCheckout = true
this.viewCart = false
this.showCartWidget = false
this.hideMenu = true
this.hideBreadcrumb = true
}
},
}
</script>
----------
This is the cart list code
<template>
<div class="w-full">
<div class="cart-heading-wrapper flex justify-between text-darkBlueText lg:text-xl font-bold">
<h5 class="w-1/3 text-left">Item Name</h5>
<h5 class="w-1/3 text-center ml-2 pl-16">Quantity</h5>
<h5 class="w-1/3 text-right">Item Price</h5>
</div>
<div class="grid border-b border-gray-400">
<div v-for="product in cart" :key="product.id" class="py-4 border-t border-gray-400">
<CartCard :product="product" :totalPrice="totalPrice" @incremented="calculateTotal(product)" @decremented="decrementTotal(product)" class="locationOption w-full flex py-2 lg:py-2 rounded-sm rounded-b-none text-gray-600 lg:text-lg md:text-base text-13px text-center cursor-pointer" />
</div>
</div>
<div class="flex flex-col justify-start float-right">
<div class="mb-4 px-28 mt-8 flex justify-between"><span class="mr-24 text-xl text-darkBlueText font-bold">Tax:</span><span class="text-2xl text-darkBlueText font-bold">${{taxes}}</span></div>
<div class="mb-4 px-28 flex justify-between"><span class="mr-24 text-xl text-darkBlueText font-bold">Fees:</span><span class="text-2xl text-darkBlueText font-bold">${{ fees }} </span></div>
<div class="border-t border-gray-500 mb-12 px-28 pt-4 flex justify-between"><span class="mr-24 text-2xl text-darkBlueText font-bold">Total:</span><span class="text-2xl text-darkBlueText font-bold">${{ formatPrice(totalPrice) }}</span></div>
</div>
<div class="w-full flex justify-between">
<div class="flex flex-col">
<button class="py-2 px-16 mb-2 bg-white border-2 border-darkBlueText text-darkBlueText text-lg font-bold">Back to Menu</button>
<a class="underline" href="#">Browse Restaurants </a>
</div>
<span>
<button class="px-6 py-3 text-white font-bold bg-seafoam rounded-sm text-lg" @click="$emit('show-checkout')">Proceed To Checkout</button>
</span>
</div>
</div>
</template>
<script>
import CartCard from './CartCard';
export default {
name: 'CartList',
components: {
CartCard,
},
props: {
cart: Array,
totalPrice: Number,
product: Object,
},
data() {
return {
taxes: 0,
fees: 0,
grandTotal: 0,
}
},
methods: {
formatPrice(value) {
let val = (value/1).toFixed(2)
return val.toLocaleString("en", {useGrouping: false, minimumFractionDigits: 2,})
},
calculateTotal(item) {
this.totalPrice += item.price
},
decrementTotal(item) {
this.totalPrice -= item.price
},
},
}
</script>
购物车小部件代码
<template>
<div class="translateCenter left-1/2 m-auto w-1/2 max-w-5xl py-5 px-6 border flex justify-between bg-white fixed bottom-10 border-black rounded-md">
<div class="font-bold flex items-center">
<div class="bg-cartImage w-7 h-7 mr-2 font-bold bg-no-repeat bg-cover text-15px bg-right pr-5"></div>
{{ itemCount }} Item(s)
</div>
<div class="flex items-center flex-grow ml-16">
<div class="rounded-full bg-black h-3 w-3 mr-4"></div>
<div class="flex items-center pt-px">
<strong class="mr-2">Total:</strong> ${{ formatPrice(totalPrice) }}
</div>
</div>
<div class="flex items-center">
<div @click="$emit('view-cart')" class="bg-arrowRight font-bold bg-no-repeat bg-8px text-15px bg-right pr-5">View Cart</div>
</div>
</div>
</template>
<script>
export default {
name: "CartWidget",
props: {
cart: Array,
itemCount: Number,
totalPrice: Number,
},
data() {
return {
total: 0,
}
},
methods: {
formatPrice(value) {
let val = (value/1).toFixed(2)
return val.toLocaleString("en", {useGrouping: false, minimumFractionDigits: 2,})
}
}
}
</script>
购物车卡片代码
<template>
<div class="flex flex-col flex-wrap justify-center items-center w-1/3">
<div class="flex justify-between items-center w-full">
<div class="flex w-1/3">
<img class="w-32 h-32" :src="require(`../../assets/images/` + backgroundImg)" :alt="product.id">
<div class="flex flex-col justify-center ml-4 text-left">
<h5 class="mb-4 text-xl text-darkBlueText font-bold">{{ product.title }}</h5>
<p class="text-15px text-gray-500 leading-5">{{ product.short }}</p>
<p class="text-15px text-gray-500 leading-5 whitespace-nowrap overflow-ellipsis overflow-hidden block w-3/4">{{ product.long }}</p>
</div>
</div>
<Quantity class="font-bold" :product="product" :totalPrice="totalPrice" @incremented="incremented()" @decremented="decremented()" />
<p class="font-bold">${{ formatPrice(product.price) }}</p>
</div>
</div>
</template>
<script>
import Quantity from './Quantity';
export default {
name: 'ProductCard',
components: {
Quantity
},
props: {
product: Object,
totalPrice: Number
},
data() {
return {
backgroundImg: this.product.image,
cart: []
}
},
methods: {
formatPrice(value) {
let val = (value/1).toFixed(2)
return val.toLocaleString("en", {useGrouping: false, minimumFractionDigits: 2,})
},
incremented() {
this.$emit('incremented')
},
decremented() {
this.$emit('decremented')
}
}
}
</script>
和结帐代码
<template>
<div>
<div class="apply-wrapper bg-bgBlue lg:p-32 lg:pt-12">
<div class="form-wrapper lg:bg-white rounded-2xl bg-bgBlue py-6 px-8 lg:py-12 lg:px-32 lg:shadow-lg max-w-screen-2xl m-auto">
<form class="lg:flex flex-wrap m-auto">
<h4 class="text-darkBlueText text-center text-xl font-bold mb-12 w-full">Contact and Delivery Information</h4>
<div class="mb-8 lg:mb-4 text-left text-lg lg:text-xl lg:w-1/2 lg:pr-12">
<label for="FirstName">First Name</label>
<input v-model="firstName" class="mt-2 h-8 lg:h-10 appearance-none border rounded border-black w-full py-3 px-3 text-gray-700 text-sm leading-tight" id="firstname" type="text" name="FirstName" required>
</div>
<div class="mb-7 lg:mb-4 text-left text-lg lg:text-xl lg:w-1/2 lg:pl-12">
<label for="LastName">Last Name</label>
<input v-model="lastName" class="mt-2 h-8 lg:h-10 text-sm appearance-none rounded border border-black w-full py-3 px-3 text-gray-700 mb-3 leading-tight" id="lastname" type="text" name="LastName" required>
</div>
<div class="mb-8 lg:mb-4 text-left text-lg lg:text-xl lg:w-1/2 lg:pr-12">
<label for="PhoneNumber">Phone Number</label>
<input v-model="phone" class="mt-2 h-8 lg:h-10 lg:mt-1 appearance-none rounded border border-black w-full py-3 px-3 text-gray-700 text-sm leading-tight" id="phonenumber" type="tel" name="PhoneNumber" required>
</div>
<div class="mb-8 lg:mb-4 text-left text-lg lg:text-xl lg:w-1/2 lg:pl-12">
<label for="EmailAddress">Email Address</label>
<input v-model="email" class="mt-2 h-8 lg:h-10 lg:mt-1 appearance-none rounded border border-black w-full py-3 px-3 text-gray-700 text-sm leading-tight" id="emailaddress" type="email" name="EmailAddress" required>
</div>
<div class="mb-8 lg:mb-4 inline-block text-left text-lg lg:text-xl w-1/2 pr-2 lg:pr-12">
<label for="Terminal" class="whitespace-nowrap">Terminal</label>
<input v-model="terminal" class="mt-2 h-8 lg:h-10 lg:mt-1 text-sm appearance-none rounded border border-black w-full py-3 px-3 text-gray-700 mb-3 leading-tight" id="terminal" type="text" name="Terminal" required>
</div>
<div class="mb-8 lg:mb-4 inline-block text-left text-lg lg:text-xl w-1/2 pl-2 lg:pl-12">
<label for="Gate">Gate</label>
<input v-model="gate" class="mt-2 h-8 lg:h-10 lg:mt-1 text-sm appearance-none rounded border border-black w-full py-3 px-3 text-gray-700 mb-3 leading-tight" id="gate" type="text" name="Gate" required>
</div>
<div class="w-1/2 m-auto">
<div class="mb-8 lg:mb-4 inline-block text-left text-lg lg:text-xl w-1/2 pl-2 lg:pl-12">
<label for="Tip">Leave A Tip?</label>
<currency-input v-model="tip" id="leaveATip" currency="USD" name="Tip" class="mt-2 h-8 lg:h-10 lg:mt-1 text-sm appearance-none rounded border border-black w-full py-3 px-3 text-gray-700 mb-3 leading-tight" />
</div>
<div>
<label for="DeliveryDate" class="block w-full">When Should We Deliver?</label>
<input v-model="date" type="date" id="DeliveryDateTime" name="DeliveryDate"
value="Today"
min="2021-01-01" max="2040-12-31" required>
<input v-model="time" type="time" id="delTime" name="DeliveryTime"
min="00:00" max="23:59" required>
</div>
</div>
<!-- stripe div -->
<section class="row payment-form">
<h5 class="#e0e0e0 grey lighten-4">
Payment Method
<span class="right"></span>
</h5>
<div class="error red center-align white-text"> {{stripeValidationError}}</div>
<div class="col s12 card-element">
<label>Card Number</label>
<div id="card-number-element" class="input-value"></div>
</div>
<div class="col s6 card-element">
<label>Expiry Date</label>
<div id="card-expiry-element"></div>
</div>
<div class="col s6 card-element">
<label>CVC</label>
<div id="card-cvc-element"></div>
</div>
<div class="col s12 place-order-button-block">
<button class="btn col s12 #e91e63 pink" @click="placeOrderButtonPressed">Place Order</button>
</div>
</section>
<CartList :cart="cart" v-if="viewCart" :totalPrice="totalPrice" :product="product"/>
</form>
</div>
</div>
</div>
</template>
<script>
import ProductList from "./ProductList";
export default {
name: 'Checkout',
components: {
ProductList,
},
props: {
cart: Array
},
data(){
console.log("[DEBUG 1]: " + this.cart + " " + this.cart.product.id + " " + this.cart.product.short);
return {
viewCart: true,
stripe: null,
cardNumberElement:null,
cardExpiryElement:null,
cardCVCElement:null,
stripeValidationError:null,
firstName:'',
lastName:'',
phone:'',
email:'',
terminal:'',
gate:'',
tip:'',
amount:25,
}
},
mounted(){
this.stripe = new Stripe("MY_KEY");
this.init();
this.testCart();
},
methods: {
testCart(){
console.log("[DEBUG 3]: " + this.cart + " " + this.cart.product.id + " " + this.cart.product.short);
this.cart.printCart();
},
init(){
// invoke and mount
var elements = this.stripe.elements();
this.cardNumberElement = elements.create("cardNumber");
this.cardNumberElement.mount("#card-number-element");
this.cardExpiryElement = elements.create("cardExpiry");
this.cardExpiryElement.mount("#card-expiry-element");
this.cardCVCElement = elements.create("cardCvc");
this.cardCVCElement.mount("#card-cvc-element");
// change events
this.cardNumberElement.on("change", this.setValidationError);
this.cardExpiryElement.on("change", this.setValidationError);
this.cardCVCElement.on("change", this.setValidationError);
},
setValidationError(event){
this.stripeValidationError = event.error ? event.error.message : "";
},
async processToken(data){
const response = await fetch('https://asite.azurewebsites.net/api/payment', {
method: 'POST',
headers: {
'Accept':'application/json',
'Access-Control-Allow-Origin':'*'
},
body: JSON.stringify(data)
});
const content = await response;
console.log(content);
if(content[2] === "True")
{
// success
// create a new swift oder
// how do I get access to the cart?
}
},
placeOrderButtonPressed(){
this.stripe.createToken(this.cardNumberElement).then(result => {
if(result.error){
this.stripeValidationError = result.error.message;
}
else {
var json = {
amount: this.amount,
source: result.token.id
}
this.processToken(json);
}
});
}
}
};
</script>
我想访问购物车中的商品,这样我就可以向服务器发出 post 调用。但我似乎无法做到这一点。
我不需要在屏幕上显示项目或其他任何东西。我只是想访问购物车,它似乎是一个总计项目的数组。
谁能指出我正确的方向?
顺便说一句,产品是一个 object,具有 ID、标题、简短描述、详细描述、价格和默认数量 1。
您的 cart
在您的 ProductList
中定义。您在该组件内实现所有其他组件,因此它是父组件。它可以通过添加 :cart="cart"
属性 将购物车中的项目分配给所有其他组件。为了让子组件访问它,他们只需要在收到的道具中声明 cart
:
props: {
cart: Array
}
然后您可以在子组件中访问this.cart
。