代码实例
App.vue
<template>
<div id="app">
<index></index>
</div>
</template>
<script>
// 引入主页index
import Index from './pages/Index';
export default {
name: 'App',
components: {
Index
}
};
</script>
<style>
*{
margin: 0;
padding: 0;
}
ul,li{
list-style: none;
}
a{
text-decoration: none;
color:#333333;
}
em{
font-style: normal;
}
</style>
Pages/Index.vue
<template>
<div id="wrap">
<s-header></s-header>
<s-main
:list="cartList"
@changestate="handleCheck"
@addnum="addNumber"
@reducenum="reduceNumber"
@delete="deleteItem"
>
</s-main>
<s-pay :list="cartList" @change="checkAll"></s-pay>
<s-footer></s-footer>
</div>
</template>
<script>
// 引入头部文件, 主页文件, 底部文件
import SHeader from './components/Header';
import SMain from './components/Main';
import SPay from './components/Pay';
import SFooter from './components/Footer';
export default {
components: {
SHeader,
SMain,
SPay,
SFooter
},
data() {
return {
cartList: [
{
id: 1,
img: '/static/images/product1.jpg',
name: '左右鞋店春夏爆款凉拖',
color: '粉',
size: '35',
price: 149,
number: 1,
checked: true
},
{
id: 2,
img: '/static/images/product2.jpg',
name: '左右鞋店春夏爆款福利',
color: '黑',
size: '35',
price: 169,
number: 1,
checked: true
},
{
id: 3,
img: '/static/images/product3.jpg',
name: '左右鞋店春夏2021爆款男士包',
color: '黑',
size: 'XL',
price: 499,
number: 1,
checked: true
}
]
};
},
methods: {
handleCheck(id) {
// console.log(id)
const selectedGood = this.cartList.find((item) => item.id === id);
selectedGood.checked = selectedGood.checked;
// console.log(selectedGood.checked)
},
checkAll(state) {
// console.log(state)
// 全选控制每一项单选
this.cartList.map((item) => {
item.checked = state;
});
},
addNumber(id) {
// console.log(id)
const selectedGood = this.cartList.find((item) => item.id === id);
selectedGood.number++;
},
reduceNumber(id) {
// console.log(id)
const selectedGood = this.cartList.find((item) => item.id === id);
if (selectedGood.number > 1) selectedGood.number--;
},
deleteItem(id) {
if (confirm('确定要删除吗?')) {
// 删除id对应的数据
const index = this.cartList.findIndex((item) => item.id === id);
this.cartList.splice(index, 1);
}
}
}
};
</script>
<style scoped>
#wrap {
max-width: 750px;
width: 7.5rem;
height: 15rem;
border: 1px solid #333;
margin: 0 auto;
}
</style>
Pages/Components/Header.vue
<template>
<div class="header">购物车</div>
</template>
<script>
export default {};
</script>
<style scoped>
.header {
width: 100%;
height: 1rem;
background: #ff5e46;
color: #ffffff;
font: 0.45rem/1rem "微软雅黑";
text-align: center;
}
</style>
Pages/Components/Main.vue
<template>
<div class="main">
<ul class="list">
<li v-for="item of list" :key="item.id" :item="item">
<input
type="checkbox"
id="checkbox"
v-model="item.checked"
@change="changeState(item.id)"
/>
<label for="checkbox"></label>
<div class="img">
<img :src="item.img" />
</div>
<div class="desc">
<h4>{{ item.name }}</h4>
<div class="spec">
<span>{{ item.color }}</span>
<span>{{ item.size }}</span>
<span class="iconfont icon-icon1"></span>
</div>
<p class="price">¥{{ item.price.toFixed(2) }}</p>
<div class="shoppingnum">
<span
class="iconfont icon-jian minus"
@click="reduceNumber(item.id)"
></span>
<span class="num">{{ item.number }}</span>
<span
class="iconfont icon-hao plus"
@click="addNumber(item.id)"
></span>
</div>
</div>
<div class="del" @click="deleteItem(item.id)">删除</div>
</li>
</ul>
</div>
</template>
<script>
export default {
// 接收cartList属性
props: {
list: {
type: Array,
required: true
}
},
methods: {
changeState(id) {
// console.log(id)
this.$emit('changestate', id);
},
// 通知父组件修改处理
addNumber(id) {
// console.log(id)
this.$emit('addnum', id);
},
reduceNumber(id) {
this.$emit('reducenum', id);
},
deleteItem(id) {
this.$emit('delete', id);
}
},
// 生命周期
mounted() {
console.log(this.list);
}
};
</script>
<style scoped>
.list li {
width: 7.5rem;
height: 2.4rem;
display: flex;
align-items: center;
justify-content: space-between;
}
li > input[type="checkbox"] {
width: 0.25rem;
height: 0.25rem;
outline: none;
-webkit-appearance: none; /*清除默认样式 */
border: 0.01rem solid #ff5e46;
border-radius: 50%;
margin: 0 0.2rem 0 0.2rem;
}
li > input[type="checkbox"]:checked {
background: url("../../assets/images/selected.jpg") no-repeat center center;
}
.img img {
width: 1.5rem;
height: 1.5rem;
}
.desc {
width: 4.5rem;
height: 2rem;
margin-left: 0.1rem;
position: relative;
}
.desc h4 {
padding-top: 0.1rem;
font-size: 0.25rem;
color: #666666;
}
.desc .spec {
margin-top: 0.5rem;
width: 0.9rem;
height: 0.3rem;
background: #eeeeee;
display: flex;
justify-content: space-between;
}
.desc .spec span {
display: inline-block;
width: 0.3rem;
height: 0.3rem;
text-align: center;
font: 0.18rem/0.3rem "微软雅黑";
color: #999999;
}
.desc .price {
font: bold 0.25rem "Arial";
padding-top: 0.17rem;
color: #ff5e46;
}
.desc .shoppingnum {
width: 1.6rem;
height: 0.4rem;
border: 0.01rem solid #e4e4e4;
display: flex;
position: absolute;
right: 0.4rem;
bottom: 0.25rem;
}
.desc .shoppingnum span {
text-align: center;
}
.desc .shoppingnum .plus,
.desc .shoppingnum .minus {
width: 0.4rem;
height: 0.4rem;
font: 0.2rem/0.4rem "微软雅黑";
color: #333333;
}
.desc .shoppingnum .num {
width: 0.8rem;
height: 0.4rem;
border-left: 0.01rem solid #e4e4e4;
border-right: 0.01rem solid #e4e4e4;
font: bold 0.3rem "宋体";
}
li .del {
width: 0.8rem;
height: 2.4rem;
background: #f51f24;
color: #ffffff;
font: 0.25rem/2.4rem "微软雅黑";
text-align: center;
cursor: pointer;
border-top: 0.01rem solid #908e68;
}
</style>
Pages/Components/Pay.vue
<template>
<div class="check">
<div class="selectall">
<input type="checkbox" v-model="allCheck" @change="getAllChecked" />全选
</div>
<div class="sum">
合计:
<span>¥{{ total }}</span>
</div>
<button>去结算</button>
</div>
</template>
<script>
// let state;
export default {
// 接收cartList属性
props: {
list: {
type: Array,
required: true
}
},
// 计算属性
computed: {
total() {
let total = 0;
this.list.forEach((item) => {
if (item.checked) {
total += item.price * item.number;
}
});
return total.toFixed(2);
},
allCheck: {
get() {
return this.list.every((item) => item.checked);
},
set(value) {
// state = value;
// console.log('all check:', value);
}
}
},
methods: {
// 点击全选和反选
getAllChecked() {
// console.log('check function', state);
// 将this.allCheck作为参数传递到父元素
this.$emit('change', !this.allCheck);
}
}
};
</script>
<style scoped>
.check {
width: 7.5rem;
height: 0.9rem;
display: flex;
justify-content: space-between;
align-items: center;
position: fixed;
bottom: 1.6rem;
left: 50%;
transform: translateX(-50%);
background: #ffffff;
}
.check .selectall {
width: 1.6rem;
font-size: 0.2rem;
margin-left: 0.1rem;
}
.check .selectall input[type="checkbox"] {
width: 0.25rem;
height: 0.25rem;
outline: none;
-webkit-appearance: none; /*清除默认样式 */
border: 0.01rem solid #ff5e46;
border-radius: 50%;
margin: 0 0.2rem 0 0.2rem;
vertical-align: bottom;
}
.check .selectall input[type="checkbox"]:checked {
background: url("../../assets/images/selected.jpg") no-repeat center center;
}
.check .sum {
width: 3.5rem;
font-size: 0.2rem;
}
.check .sum span {
font: bold 0.24rem "微软雅黑";
color: #ff5e46;
}
.check button {
width: 2.2rem;
height: 0.9rem;
border: none;
outline: none;
cursor: pointer;
font-size: 0.26rem;
color: #ffffff;
background: #ff5e46;
}
</style>
Pages/Components/Footer.vue
<template>
<footer class="footer">
<a href="#">
<i class="iconfont icon-yemian"></i>
<em>首页</em>
</a>
<a href="#">
<i class="iconfont icon-leimupinleifenleileibie2"></i>
<em>分类</em>
</a>
<a href="#">
<i class="iconfont icon-gouwuche"></i>
<em>购物车</em>
</a>
<a href="#">
<i class="iconfont icon-mine"></i>
<em>我的</em>
</a>
</footer>
</template>
<script>
export default {};
</script>
<style scoped>
.footer {
max-width: 750px;
width: 100%;
height: 1.6rem;
background: #ffffff;
border-top: 1px solid #908e68;
position: fixed;
bottom: 0;
left: 50%;
transform: translateX(-50%);
display: flex;
justify-content: space-around;
align-items: center;
}
.footer a {
display: inline-block;
width: 0.6rem;
height: 0.85rem;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-around;
}
.footer a i {
display: block;
font-size: 0.4rem;
color: #8a8a8a;
}
.footer a em {
font: 0.18rem/1 "微软雅黑";
color: #878787;
}
.footer a:nth-of-type(3) i,
.footer a:nth-of-type(3) em {
color: #ff5e46;
}
</style>
main.js
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue';
import App from './App';
import '../static/font/iconfont.css';
Vue.config.productionTip = false;
/* eslint-disable no-new */
new Vue({
el: '#app',
components: { App },
template: '<App/>'
});
代码实例2
mock/cart.js
const cart = [
{
id: 1,
gid: 11,
number: 1,
selected: true,
name: '【冰点清仓】天然淡水珍珠耳钉/耳环/网红爆款纯银饰品',
price: 83,
img: 'https://h2.appsimg.com/a.appsimg.com/upload/merchandise/pdcvis/2020/09/09/193/7f280391-2ca8-437b-bb42-c5a876ed8782_356x356_90.jpg'
},
{
id: 2,
gid: 12,
number: 1,
selected: true,
name: '18K金进口塑胶耳背透明硅胶耳堵耳帽防过敏耳塞耳迫耳饰配件',
price: 29,
img: 'https://h2.appsimg.com/a.appsimg.com/upload/merchandise/pdcvis/2020/12/26/199/660e0794-c693-47aa-baa7-e9632cfe0655_356x356_90.jpg'
},
{
id: 3,
gid: 13,
number: 1,
selected: true,
name: '【冰点清仓】气质款 7-8MM稀有混彩天然淡水珍珠项链',
price: 143,
img: 'https://h2.appsimg.com/a.appsimg.com/upload/merchandise/pdcvis/2020/09/09/12/018ea256-c179-4259-99ab-959d869074ba_356x356_90.jpg'
},
{
id: 4,
gid: 13,
number: 1,
selected: true,
name: '热卖爆款 四季百搭款 小蜜蜂胸针一款两戴珍珠胸针/珍珠项链',
price: 79,
img: 'https://h2.appsimg.com/a.appsimg.com/upload/merchandise/pdcvis/2020/09/08/193/5f91e56a-5624-4092-8b15-695b16842911_356x356_90.jpg'
}
]
export default cart
App.vue
<template>
<div>
<u-cart />
</div>
</template>
<script>
import UCart from './pages/cart/Index'
export default {
components: {
UCart
}
}
</script>
<style scoped>
</style>
Pages/Index.vue
<template>
<div>
<h1>购物车</h1>
<u-list :list="cartList" @update="updateCart" @select="toggleSelect"/>
<hr>
<u-count :selectAll="selectAll" :total="total" @select="toggleSelectAll"/>
</div>
</template>
<script>
import UList from './components/List'
import UCount from './components/Count'
import cartList from '@/mock/cart.js'
export default {
components: {
UList,
UCount
},
data () {
return {
cartList: [],
selectAll: true,
total: 0
}
},
mounted () {
// 初始化数据
this.cartList = [...cartList]
// 处理购物车的统计
this.countCart()
},
methods: {
countCart () {
// 统计购物车 是否全选 合计
let total = 0
let selectAll = true
if (this.cartList.length > 0) {
// 统计选中的商品的合计
this.cartList.forEach(item => {
if (item.selected) {
total += item.number * item.price
} else {
selectAll = false
}
})
} else {
selectAll = false
}
this.total = total
this.selectAll = selectAll
},
updateCart (res) {
// 修改商品的购买数量(加或者减)
const cart = this.cartList.find(item => item.id === res.id)
if (res.type === 'add') { // 数量+1
cart.number += 1
} else if (res.type === 'reduce') { // 数量-1
if (cart.number > 1) {
cart.number -= 1
}
}
// 处理购物车的统计
this.countCart()
},
toggleSelect (id) {
// 修改对应商品的是否选中
const cart = this.cartList.find(item => item.id === id)
cart.selected = !cart.selected
// 处理购物车的统计
this.countCart()
},
toggleSelectAll () {
// 全选按钮的切换
this.selectAll = !this.selectAll
this.cartList = this.cartList.map(item => {
item.selected = this.selectAll
return item
})
// 处理购物车的统计
this.countCart()
}
}
}
</script>
<style scoped>
</style>
Pages/Compoments/List.vue
<template>
<ul>
<li v-for="item of list" :key="item.id" style="margin-bottom:20px">
<img @click="toggleSelect(item.id)" :src="item.selected ? selectImg : notSelectImg" />
<img :src="item.img" height="120"/>
<span>¥{{item.price}}</span>
<button @click="reduceCart(item.id)">-</button>
<span>{{item.number}}</span>
<button @click="addCart(item.id)">+</button>
</li>
</ul>
</template>
<script>
export default {
props: {
list: {
type: Array,
required: true
}
},
data () {
return {
selectImg: require('@/assets/img/selected.png'),
notSelectImg: require('@/assets/img/not-select.png'),
}
},
methods: {
addCart (id) {
// 通知父组件修改购物车对应商品的购买数量
this.$emit('update', { id, type: 'add' })
},
reduceCart (id) {
// 通知父组件修改购物车对应商品的购买数量
this.$emit('update', { id, type: 'reduce' })
},
toggleSelect (id) {
// 通知父组件修改购物车对应商品的是否选中
this.$emit('select', id)
}
}
}
</script>
<style scoped>
</style>
Pages/Components/Count.vue
<template>
<h1>
<img @click="toggleSelectAll" :src="selectAll ? selectImg: notSelectImg" />
<span>合计:¥{{total}}</span>
</h1>
</template>
<script>
export default {
props: {
selectAll: Boolean,
total: Number
},
data () {
return {
selectImg: require('@/assets/img/selected.png'),
notSelectImg: require('@/assets/img/not-select.png'),
}
},
methods: {
toggleSelectAll () {
this.$emit('select')
}
}
}
</script>
<style scoped>
</style>