vue组件化实例-购物车

vue组件化实例-购物车

  • 前言
  • 环境准备
  • 实现步骤
    • 创建项目
    • 购物车的编码
      • 标题的编码(基础知识,可跳过)
        • 功能一:现在我想先给我的购物车加上一个大标题,要怎么做呢?
        • 功能二:我想要标题在页面加载2秒后,再显示。
      • 显示商品列表
        • 功能三:显示我的商品列表
      • 添加商品
        • 功能四:我要向商品列表中添加新的商品(包括商品名和单价)
      • 加入购物车
        • 功能五:将商品加入到购物车中,并显示购物车信息
    • 将购物车功能组件化
      • 功能六:将购物车的相关信息放到独立的组件中。实现项目的组件化。
      • 功能七:购物车中添加一列(价格列),自动计算各商品的价格。
      • 功能八:在购物车中加入一列复选框,默认选中,未选中时,其字体颜色变淡。
      • 功能九:计算购物车中被选中商品的总价格。

前言

最近,报了开课吧的web全栈课程,课程讲的干货挺多的,现将课上的例子的实现步骤写下来,当做一个课后总结,同时方便以后自己查阅,也给大家一个参考。
本案例主要是完成一个简单的购物车功能(添加商品,显示商品列表,加入购物车);先是将所有功能在一个组件中完成;然后再进行组件化,再将购物车的功能摘出来,放置另一个组件中。

以下是最终完成的效果图:
​​vue组件化实例-购物车_第1张图片

环境准备

浏览器(推荐: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时,直接回车选择默认即可。如下图:
    vue组件化实例-购物车_第2张图片
  2. 大家如果觉得,它下载包太慢的话,可以 Ctrl + C 停止掉,使用 淘宝镜像下载(命令:cnpm install)。

项目创建完成,如下图:
vue组件化实例-购物车_第3张图片
项目启动:
  在上图中可以看到启动命令:
  1. 跳转到 项目目录下:cd vue-demo2
  2. 执行启动命令:npm run serve。出现下图,表示启动成功。
  vue组件化实例-购物车_第4张图片
  3. 在浏览器中输入http://localhost:8081,如下图。:
vue组件化实例-购物车_第5张图片
项目结构,如下图。:
vue组件化实例-购物车_第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>
    
    <h2 :title="title" >{{title}}h2>
  div>
template>

<script>
export default {
  name: 'HelloWorld',
    data() {
        return {
            title: '小诺的购物车' // 定义数据title
        }
    },
}
script>

效果图:
vue组件化实例-购物车_第7张图片

功能二:我想要标题在页面加载2秒后,再显示。

实现:在组件的 created 生命周期中 设置一个定时器。在其回调中为给title赋值;且控制模板中的标题元素根据 title是否有值来显示与否。如下:

<template>
  <div>
    
    <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>
          
          <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>

效果图:
vue组件化实例-购物车_第8张图片
补充:循环语法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},
            ],
        }
    },
  1. 在模板中添加用户输入需要输入框,并绑定对应的数据变量。
 
    <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>
  1. 添加提交按钮,并绑定其对应的提交事件,这里只提交到数组中,并不逻辑后台。
 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;
            }
        },

效果图:
vue组件化实例-购物车_第9张图片
vue组件化实例-购物车_第10张图片

加入购物车

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

  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});
                }
            }
  1. 显示购物信息
<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>

效果图:
vue组件化实例-购物车_第11张图片
vue组件化实例-购物车_第12张图片

将购物车功能组件化

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

  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>
  1. HelloWord.vue 组件中使用 Cart.vue 组件。
    导入组件:import Cart from "./Cart";
    在vue中声明组件:components: {Cart},
    在模板中使用组件:
  2. 组件之间通信(父传子):在父组件中点击“加入购物车”;然后在子组件中执行加入操作,显示购物车信息;这是一个父传子的通信。
    第一种: 为 cart 添加属性 ref='cart',然后在HelloWord.vue中的addCart函数中使用this.$refs.cart.addCart()来调用子组件的加入购物车方法;不过,这种方法不太推荐,耦合性比较强。
    第二种:
    • main.js 中 定义一个全局的总线:Vue.prototype.$bus = new Vue(); // 定义全局的。这是在Vue原型上声明的对象,所以所有的Vue组件都可以调用它,它可以实现任意两个组件之间的通信。
    • 在父组件的 addCart() 函数中使用 this.$bus.$emit('addCart',good) 派发 addCart 事件。
    • 在子组件的生产周期 created() 中监听这个事件,使用 this.$bus.$on('addCart',good => this.addCart(good));

补充:子传父

  • 在子组件Cart.vue组件的 addCart() 函数中 最后一行使用 this.$emit('addCart',true); ,返回一个true 给父组件。
  • 在父组件的中绑定addCart事件,即
    vue组件化实例-购物车_第13张图片

功能七:购物车中添加一列(价格列),自动计算各商品的价格。

  1. 在Cart.vue组件的模板中,添加列头 价格 ,添加列 {{c.price * c.count}}。如下图:
    vue组件化实例-购物车_第14张图片

功能八:在购物车中加入一列复选框,默认选中,未选中时,其字体颜色变淡。

  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. 为表格的 标签,绑定动态样式 :class="{inactive:!c.active}"

效果图:
vue组件化实例-购物车_第15张图片
vue组件化实例-购物车_第16张图片

功能九:计算购物车中被选中商品的总价格。

  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>
    

至此,所有的功能说明都完成了。

你可能感兴趣的:(Vue,前端,vue实例,vue组件化实例,购物车实例,vue父子通信)