[超详细]vue组件化-购物车实例
最近在学习vue,学到了vue组件化了,想找一个例子来做一下,恰巧看到了该博主的文章,就照着学习了。当做一个总结,同时方便以后自己查阅,也给大家一个参考。本案例主要是完成一个简单的购物车功能(添加商品,显示商品列表,加入购物车);先是将所有功能在一个组件中完成;然后再进行组件化,再将购物车的功能摘出来,放置另一个组件中。以下是最终完成的效果图vue组件化实例-购物车_迷失的骆驼的博客-CSDN博客
vue组件化-购物车实例
前言
最近在学习vue,学到了vue组件化了,想找一个例子来做一下,恰巧看到了该博主的文章 (我将它贴在下面),就照着学习了。当做一个总结,同时方便以后自己查阅,也给大家一个参考。
本案例主要是完成一个简单的购物车功能(添加商品,显示商品列表,加入购物车);先是将所有功能在一个组件中完成;然后再进行组件化,再将购物车的功能摘出来,放置另一个组件中。
以下是最终完成的效果图:
文章转载于: vue组件化实例-购物车_迷失的骆驼的博客-CSDN博客_vue组件购物车
环境准备
浏览器(推荐:chrome)
编辑器(推荐:vscode、webstorm)
Node.js(推荐安装8.0以上版本)
Vue.js(推荐安装2.5版本)
注:装好node后 npm install -g @vue/cli
安装vue cli全局脚手架
注:我这里就不介绍怎么安装环境了,大家自己查找相关资料吧。。。
实现步骤
创建项目
创建命令:vue create 项目名。如我的项目:vue create vue-demo2。
注意:
1、创建过程中,问你选择哪个preset时,直接回车选择默认即可。如下图:
2、大家如果觉得,它下载包太慢的话,可以 Ctrl + C 停止掉,使用 淘宝镜像下载(命令:cnpm install)。
项目创建完成,如下图:
项目启动:
在上图中可以看到启动命令:
1. 跳转到 项目目录下:cd vue-demo2
。
2. 执行启动命令:npm run serve
。出现下图,表示启动成功。
3. 在浏览器中输入http://localhost:8080,如下图。
项目结构,如图:
注意:我的vue-cli,是2.9.6的版本,我参考的博主的安装图,也把她的拿过来了,她的vue-cli,是3.0的版本,与旧版有些不同。所以创建的项目有些不同,不过没有关系的。
购物车的编码
我就不另写组件了,直接在HelloWorld.vue组件中编写,同时也将组件中不需要的内容的删除了。此时 HelloWrold.vue的代码如下:
<template>
<div>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
}
</script>
<style scoped>
</style>
app.vue 如下(这里为了好看成点,写了些样式):
<template>
<div id="app">
<HelloWorld />
</div>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue'
export default {
name: 'app',
components: {
HelloWorld
}
}
</script>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
/*text-align: center;*/
color: #2c3e50;
width: 60%;
border: 1px solid peachpuff;
margin: 50px auto;
background: papayawhip;
padding:0 10px;
}
h2{text-align: center;}
input{margin-right: 20px;}
ul{padding: 0px;margin: 0;}
ul li{line-height: 30px; list-style: none; }
ul li button{margin-left: 10px;}
ul li span{margin-right: 20px;}
ul li span:nth-child(2){display: inline-block; min-width: 100px;}
ul li span:nth-child(3){display: inline-block; min-width: 60px;}
table{width: 100%;line-height: 30px; text-align: center;}
table tr td,table tr th{border-left: 1px solid #a2a2a2; border-top: 1px solid #a2a2a2;}
table tr td:last-child,table tr th:last-child{border-right: 1px solid #a2a2a2;}
table tr:last-child td{border-bottom: 1px solid #a2a2a2;}
.box{border: 1px solid peru; border-radius: 5px;margin-bottom: 10px;line-height: 30px;}
.box .header{border-bottom:1px solid peru;padding-left: 20px;font-weight: bold;
background: palegoldenrod; border-radius: 5px 5px 0 0;}
.box .body{padding: 20px 40px;}
</style>
标题的编码(基础知识,可跳过)
这个标题并不是必须了,但我想利用它来说明vue中的“数据绑定”及“条件显示”功能,就给加上了。
功能一:现在我想先给我的购物车加上一个大标题,要怎么做呢?
实现:在 HelloWord.vue
添加数据 title
,并将其绑定到模板中。这数据绑定的方法有多种:
- {{}}:插值绑定
- title=“title”:属性绑定
如下:
<template>
<div>
<!--绑定数据title-->
<h2 :title="title" >{{title}}</h2>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data() {
return {
title: '伴随的购物车' // 定义数据title
}
},
}
</script>
效果图:
功能二:我想要标题在页面加载2秒后,再显示。
实现:在组件的 created 生命周期中 设置一个定时器。在其回调中为给title赋值;且控制模板中的标题元素根据 title是否有值来显示与否。如下:
<template>
<div>
<!--绑定数据title-->
<h2 :title="title" v-if="title">{{title}}</h2>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data() {
return {
title: '' // 定义数据title,初始设置为''
}
},
created(){
setTimeout(()=>{
this.title = '伴随~的购物车';
},2000);
}
}
</script>
显示商品列表
功能三:显示商品列表
一个购物车,必须要有它的商品,我在data
中定义的是一个goods
数组来存储商品。 这个商品我定义了商品名称及价格两个属性。我给程序加入了3种原始的商品。如下:
goods:[
{id:1,text:'香蕉',price:10},
{id:2,text:'苹果',price:12},
{id:3,text:'芒果',price:13},
],
并在模板中循环显示。如下:
<!--循环-->
<div class="box">
<div class="header">商品列表</div>
<div class="body">
<ul>
<!--循环显示goods-->
<li v-for="(good,index) in goods" :key="good.id">
<span>{{index+1}}</span>
<span>{{good.text}}</span><span>¥{{good.price}}</span>
</li>
</ul>
</div>
</div>
效果图:
补充:循环语法v-for = "(item,index) in list"
, 其中item
为元素,index
为列表索引,从0开始。
添加商品
功能四:我要向商品列表中添加新的商品(包括商品名和单价)
1、声明两个数据变量,商品名text
, 商品价格price
,用于绑定输入框。
data() {
return {
title: '', // 定义数据title
text:'砂糖桔', // ------添加商品时绑定商品名称,给个默认值
price:null, // -------添加商品时绑定商品价格
goods:[
{id:1,text:'香蕉',price:10},
{id:2,text:'苹果',price:12},
{id:3,text:'芒果',price:13},
],
}
},
2、在模板中添加用户输入需要输入框,并绑定对应的数据变量。
<!--用户输入-->
<div class="box">
<div class="header">添加商品</div>
<div class="body">
<div>
<label>商品名称:</label>
<input type="text" v-model="text">
</div>
<div>
<label>商品价格:</label>
<input type="text" v-model="price">
</div>
<div>
<button @click="addGood">提交</button>
</div>
</div>
</div>
3、添加提交按钮,并绑定其对应的提交事件,这里只提交到数组中,并不涉及逻辑后台。
addGood(){
// 验证是否填写
if(this.text && this.price){
// 只在前端数组追加元素,不提交后台
this.goods.push({
id:this.goods.length+1,
text:this.text,
price:this.price
});
// 提交后清空
this.text = '';
this.price = null;
}
},
效果图:
添加后:
加入购物车
功能五:将商品加入到购物车中,并显示购物车信息
1、声明一个数组来存储购物车中的数据。其内的元素数据结构基本与商品数据结构一至;不过要多一个count
属性,来表示购买的商品数据。
2、模板中,在商品列表中商品后面添加一上“加入购物车”的按钮,并绑定加入事件。如下:
添加按钮:
<button @click="addCart(good)">加购物车</button>
绑定事件:
addCart(good) {
// 添加购物车
const ret = this.cart.find(v=>v.id === good.id);
if(ret){
// 购物车里已有该商品,则数量加1,
ret.count += 1;
} else {
// 追加进购物车中,数据为1
this.cart.push({...good,count:1});
}
}
3、显示购物信息
<div class="box">
<div class="header">购物车</div>
<div class="body">
<table v-if="cart.length>0" cellpadding="0" cellspacing="0">
<thead>
<tr>
<th>水果名</th>
<th>单价</th>
<th>数量</th>
</tr>
</thead>
<tbody>
<tr v-for="c in cart" :key="c.id" >
<td>{{c.text}}</td>
<td>¥{{c.price}}</td>
<td>{{c.count}}</td>
</tr>
</tbody>
</table>
</div>
</div>
效果图:
将 芒果 加入购物车!!!
加入购物车后:
将购物车功能组件化
功能六:将购物车的相关信息放到独立的组件中。实现项目的组件化。
1、 在Component目录下创建Cart.vue组件,并将购物车相关信息提取到此。Cart.vue如下:
<template>
<table v-if="cart.length>0" cellpadding="0" cellspacing="0">
<thead>
<tr>
<th>水果名</th>
<th>单价</th>
<th>数量</th>
</tr>
</thead>
<tbody>
<tr v-for="c in cart" :key="c.id" :class="{inactive:!c.active}">
<td>{{c.text}}</td>
<td>¥{{c.price}}</td>
<td>{{c.count}}</td>
</tr>
</tbody>
</table>
</template>
<script>
export default {
name: "cart",
data() {
return {
cart:[],
addCart(good) {
// 添加购物车
const ret = this.cart.find(v=>v.id === good.id);
if(ret){
// 购物车里已有该商品
ret.count += 1;
} else {
// this.cart.push({...good,count:1,active:true});
this.cart.push({...good,count:1});
}
}
}
},
}
</script>
<style scoped>
</style>
2、在 HelloWord.vue
组件中使用 Cart.vue
组件。
导入组件:import Cart from "./Cart";
在vue中声明组件:components: {Cart},
在模板中使用组件:<cart></cart>
3、 组件之间通信(父传子):在父组件中点击“加入购物车”;然后在子组件中执行加入操作,显示购物车信息;这是一个父传子的通信。
第一种: 为 cart 添加属性 ref='cart'
,然后在 HelloWord.vue
中的addCart
函数中使用this.$refs.cart.addCart()
来调用子组 件的加入购物车方法;不过,这种方法不太推荐,耦合性比较强。 我们使用第二种!
第二种:
1.在 main.js
中 定义一个全局的总线:Vue.prototype.$bus = new Vue(); // 定义全局的
。这是在Vue原型上声明的对象,所以所有的Vue组件都可以调用它,它可以实现任意两个组件之间的通信。
2.在父组件的 addCart()
函数中使用 this.$bus.$emit('addCart',good)
派发 addCart 事件。
3.在子组件的生产周期 created()
中监听这个事件,使用 this.$bus.$on('addCart',good => this.addCart(good));
补充:子传父
1.在子组件Cart.vue组件的 addCart() 函数中 最后一行使用 this.$emit('addCart',true);
,返回一个true
给父组件。
2.在父组件中使用<cart></cart>
标签。
功能七:购物车中添加一列(价格列),自动计算各商品的价格。
在Cart.vue组件的模板中,添加列头 <th>价格</th>
,添加列 <td>{{c.price * c.count}}</td>
。如下图:
功能八:在购物车中加入一列复选框,默认选中,未选中时,其字体颜色变淡。
1、购物车组件写一个字体变色的样式.inactive{ color: #b0b0b0; }
,用于表示未选中的状态。
2、修改 Cart
组件的 addCart
方法中 cart数组追加元素时的对象,让其再加一个属性 active:true
,即:
this.cart.push({...good,count:1,active:true});
3、在 Cart
组件的模板的表格的最前面加入一列复选框。并将复选框绑定 active
。即:
<td><input type="checkbox" v-model="c.active" /></td>
4、为表格的 <tr>
标签,绑定动态样式 :class="{inactive:!c.active}"
效果图:
默认是选择的
去掉选中,字体变色
功能九:计算购物车中被选中商品的总价格。
1、写一个计算属性total
,用于计算总价格。如下:
computed: {
total() {
return this.cart.reduce((sum,c)=>{
if(c.active){ // 只计算被选中的
sum += c.price * c.count;
}
return sum;
},0);
}
},
2、在购物车的表格中添加一个底部,用来绑定 total
的值。如下:
<tfoot>
<tr>
<td colspan="4">总结</td>
<td>¥{{total}}</td>
</tr>
</tfoot>
效果图:
至此,所有的功能说明都完成了。
最后也感谢这位博主,写得太详细了 ,学到了很多!!!
附上项目源码:
链接:https://pan.baidu.com/s/1-t2kVbEpoKsKmoqh_maXYA
提取码:iqvz
更多推荐
所有评论(0)