Demo checkout page via Vuejs
by Gaoping
HTML
<script src="https://unpkg.com/vue"></script>
<h1>Demo Checkout page via Vuejs</h1>
<div id="app">
<div class="main">
<div class="step">
<div class="number">1</div>
<div class="name">Shipping address</div>
<div class="content">
<div v-if="editAddress">
<label>Address:</label> <br>
<input type="text" v-model="address"> <br>
<label>State:</label> <br>
<input type="text" v-model="state"> <br>
<label>Zipcode:</label> <br>
<input type="text" v-model="zipcode"> <br>
</div>
<div v-else>
<!-- add some filters -->
{{address | uppercase}} <br>
{{state | uppercase}} {{zipcode}}, USA
</div>
<button v-if="!editAddress" v-on:click="editAddress = !editAddress">Change</button>
<button v-else v-on:click="editAddress = !editAddress">Save</button>
</div>
</div>
<div class="step">
<div class="number">2</div>
<div class="name">Payment method</div>
<div class="content">
<div v-if="editPayment">
<label>Card Number:</label> <br>
<input type="text" v-model="cardnumber"> <br>
</div>
<div v-else>VISA ending in {{cardnumber | last4digit}}</div>
<strong>Billing address:</strong> {{billingAddress | uppercase}}
<button v-if="!editPayment" v-on:click="editPayment = !editPayment">Change</button>
<button v-else v-on:click="editPayment = !editPayment">Save</button>
</div>
</div>
<div class="step">
<div class="number">3</div>
<div class="name">Review items</div>
<div style="clear: both"></div>
<div class="content-lg">
<!-- v-for and components -->
<!-- pass properties to components -->
<order-item v-for="item of items" :key="item.id" :item="item" v-on:decrease="decreaseNumber"...
CSS
body {
font-family: 'Helvetica Neue', Arial, sans-serif;
font-size: 18px;
margin: 10px;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
color: #34495e;
min-width: 800px;
}
body a {
color: #42b983;
font-weight: 600;
}
pre {
margin: 0px;
}
pre.code-area {
margin-top: 10px;
margin-bottom: -70px;
}
ol li {
padding: 5px 0px;
}
input {
font-family: Helvetica;
font-size: 20px;
padding-left: 5px;
}
h1 {
color: #483d8b;
border-bottom: 2px solid #aaa;
padding-bottom: 15px;
}
.page-header {
border-bottom: 1px solid #ccc;
padding-bottom: 15px;
padding-top: 30px;
}
.counter-group button {
font-size: 18px;
height: 29px;
width: 29px;
}
.counter-group input {
width: 30px;
}
.main {
float: left;
width: 69%;
}
.main .step {
padding-bottom: 10px;
padding-top: 10px;
border-bottom: solid 1px #ddd;
}
.main .step:after {
content: '';
display: block;
clear: both;
}
.main .step:last-child {
border: none;
}
.main .number, .main .name {
font-weight: bold;
float: left;
}
.main .number {
width: 5%;
}
.main .name {
width: 30%;
}
.main .content {
float: left;
width: 65%;
position: relative;
font-family: serif;
}
.main .content input {
font-size: 14px;
}
.main .content button {
padding: 1px 20px;
position: absolute;
right: 0;
top: 0;
}
.main .content-lg {
margin-top: 10px;
margin-left: 20px;
border: 1px solid #ddd;
padding: 10px;
}
.item-body {
display: block;
font-family: Arial !important;
font-size: 14px;
}
.item-body:after {
content: '';
display: block;
clear: both;
}
.item-body h4, .item-body p {
padding-top: 5px;
margin: 0px;
}
.item-body .image {
float: left;
}
.item-body .seller {
color: #888;
}
.item-body .price {
color: #a82f0b;
font-weight: bold;
}
.item-body .item-content {
float: left;
margin-left: 20px;
}
.item-body .quantity-group {
display: inline-block;
}
.total {
margin-top: 10px;
margin-left: 20px;
...
Vue
// register some filters
Vue.filter('uppercase', function(value) {
return value.toUpperCase()
})
Vue.filter('last4digit', function(value) {
return value.slice(value.length-4)
})
// register components
Vue.component('order-item', {
template: '#item-template', // include template from <script type="x-template">
props: ['item'], // properties passed from parent
methods: {
decrease: function() {
this.$emit('decrease', this.item.id)
},
increase: function() {
this.$emit('increase', this.item.id)
}
}
})
Vue.component('my-sidebar', {
template: '#sidebar-template', // include template from <script type="x-template">
props: ['items', 'totalCostWithTax', 'tax', 'totalCostNoTax'],
computed: {
itemNumber: function() {
var res = 0
this.items.forEach(function(item) {
res += item.number
})
return res
}
}
})
// create a root vue instance
new Vue({
el: '#app',
data: {
items: [{
id: 1,
name: 'Wireless mouse',
imgUrl: 'https://gaopinghuang0.github.io/assets/imgs/mouse.jpg',
seller: 'Amazon.com LLC',
price: 9.99,
number: 2
}, {
id: 2,
name: 'Wireless keyboard',
imgUrl: 'https://gaopinghuang0.github.io/assets/imgs/keyboard.png',
seller: 'Amazon.com LLC',
price: 19.99,
number: 1
}],
zipcode: 47906,
state: 'IN',
address: 'SOME ADDRESS',
editAddress: false,
editPayment: false,
cardnumber: '000000000001234'
},
computed: {
billingAddress: function() {
return this.address + ', ' + this.state + ' ' + this.zipcode + ', USA'
},
totalCostWithTax: function() {
return (Number(this.totalCostNoTax) + Number(this.tax)).toFixed(2)
},
tax: function() {
return (this.totalCostNoTax * 0.07).toFixed(2)
},
totalCostNoTax: function() {
var total = 0
this.items.forEach(function(item) {
total += item.price * item.number
})
...