前言

最近在学习vue,学到了vue组件化了,想找一个例子来做一下,恰巧看到了该博主的文章 (我将它贴在下面),就照着学习了。当做一个总结,同时方便以后自己查阅,也给大家一个参考。
本案例主要是完成一个简单的购物车功能(添加商品,显示商品列表,加入购物车);先是将所有功能在一个组件中完成;然后再进行组件化,再将购物车的功能摘出来,放置另一个组件中。

以下是最终完成的效果图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kGHFmbBz-1658598163788)(C:\Users\123\AppData\Roaming\Typora\typora-user-images\image-20220527194824331.png)]
文章转载于: 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)。
项目创建完成,如下图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UsSdL0L8-1658598163793)(C:\Users\123\AppData\Roaming\Typora\typora-user-images\image-20220527195545977.png)]
项目启动:
  在上图中可以看到启动命令:
  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>

效果图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-X4btFYGr-1658598163795)(C:\Users\123\AppData\Roaming\Typora\typora-user-images\image-20220527200804424.png)]

功能二:我想要标题在页面加载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;
            }
        },

效果图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9qXO8mDa-1658598163796)(C:\Users\123\AppData\Roaming\Typora\typora-user-images\image-20220527201738588.png)]
添加后:
在这里插入图片描述

加入购物车

功能五:将商品加入到购物车中,并显示购物车信息

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>

效果图:

将 芒果 加入购物车!!!
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-29aBptjH-1658598163798)(C:\Users\123\AppData\Roaming\Typora\typora-user-images\image-20220527202146430.png)]
加入购物车后:
在这里插入图片描述

将购物车功能组件化

功能六:将购物车的相关信息放到独立的组件中。实现项目的组件化。

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

Logo

前往低代码交流专区

更多推荐