手把手教你vuex写个简单的购物车DEMO

10 篇文章 0 订阅

先看效果图:如下
这里写图片描述
仓库地址:vuex-shopcart的github地址

本文一边讲解如何实现购物车功能,一边带你如何查看vuex的文档

  • 先展示下项目的目录结构(具体的细节不做过多解释)
    这里写图片描述

具体的操作步骤如下(bootstrap的布局)

  • product组件(纯静态代码)
<template>
  <div class="product">

    <h4>商品信息</h4>
    <table class="table table-hover table-bordered">
      <thead>
        <tr>
          <th>id</th>
          <th>名称</th>
          <th>价格</th>
          <th>操作</th>
        </tr>
      </thead>
      <tbody>
        <tr v-for='(shop,index) in shoplist' :key='index'>
          <td>{{shop.id}}</td>
          <td>{{shop.name}}</td>
          <td>{{shop.price}}</td>
          <td>
            <div class="btn btn-info">购物车</div>
          </td>
        </tr>
      </tbody>
    </table>

  </div>
</template>

<script>
export default {
  name: 'product',
  data() {
    return {
      shoplist: [
        {
          id: 11,
          name: '鱼香肉丝',
          price: 12,
        },
        {
          id: 22,
          name: '宫保鸡丁',
          price: 14,
        },
        {
          id: 34,
          name: '土豆丝',
          price: 10,
        },
        {
          id: 47,
          name: '米饭',
          price: 2,
        },
      ],
    };
  },
};
</script>

<style scoped>
.table-shop > th {
  text-align: center;
}

.item-wrapper {
  display: flex;
  background-color: #dfdfdf;
  align-items: center;
  justify-content: center;
}

.item {
  flex: 1;
}
</style>
  • cart组件(纯静态代码)
<template>
    <div>
        <h4>已选商品</h4>
        <table class="table table-hover table-bordered">
            <thead>
                <tr>
                    <th>id</th>
                    <th>名称</th>
                    <th>价格</th>
                    <th>数量</th>
                    <th>操作</th>
                </tr>
            </thead>
            <tbody>
                <tr v-for='(shop,index) in cartProducts' :key='index'>
                    <td>{{shop.id}}</td>
                    <td>{{shop.name}}</td>
                    <td>{{shop.price}}</td>
                    <td>{{shop.num}}</td>
                    <td>
                        <div @click='delProduct(shop)' class="btn btn-danger btn-sm">删除</div>
                    </td>
                </tr>
                <tr v-if="!cartProducts.length">
                    <td colspan="5" class="text-center">您的购物车空空如也。。。</td>
                </tr>
            </tbody>
        </table>
    </div>
</template>

<script>
export default {
  name: 'cart',
  data() {
    return {
      cartProducts: [],
    };
  },
};
</script>

  • info组件(纯静态代码)
<template>
    <div>
        <div class="item-wrapper">
            <div class='item'>总数:
                <strong>{{totalNum}}</strong>
            </div>
            <div class='item'>总价:
                <strong>{{totalPrice}}</strong>
            </div>
            <div class="item btn btn-danger">清空购物车</div>
        </div>
    </div>
</template>

<script>
import { mapGetters, mapActions } from 'vuex';

export default {
  name: 'info',
  data() {
    return {
      totalNum: 13,
      totalPrice: 342,
    };
  },
};
</script>

<style scoped>
.item-wrapper {
  display: flex;
  background-color: #dfdfdf;
  align-items: center;
  justify-content: center;
}

.item {
  flex: 1;
}
</style>

</style>
  • 完成以上的三个组件,现在要开始调用这些组件,在App.vue中调用
<template>
    <div id="app">
        <h3>Vuex购物车demo</h3>
        <!-- 商品的列表 -->g
        <product></product>
        <!-- 购物车的列表 -->
        <cart></cart>
        <!-- 总数量价格 -->
        <info></info>
    </div>
</template>

<script>
import product from './components/product'; //商品的列表组件
import cart from './components/cart'; //已选商品的组件
import info from './components/info'; //总数量价格的组件

export default {
  name: 'app',
  components: {
    product,
    cart,
    info,
  },
};
</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
}
</style>
  • 如果你的姿势正确的话,会出现这个画面
    这里写图片描述

  • 解释这里为什么要分开组件的编写,vuex是就是存储的数据的中心的,每个组件都是拿到数据,这样才能vuex的价值(每个组件的代码不做解释,既然是学vuex,前提的一定有一些的vue的基础的)

  • 安装vuex

        npm install vuex --save
  • 使用vuex ,搭建的vuex的目录结构,文章的目录结构,在你的项目中创建相应的文件,文件名称对应上,可参考官网项目结构

  • store/index.js

// 组装模块并导出 store 的地方
import Vue from 'vue';
import Vuex from 'vuex';

import cart from './modules/cart’; //购物车

Vue.use(Vuex);

export default new Vuex.Store({
  modules: {  //和文件名字对应
    cart,
  },
  strict: process.env.NODE_ENV !== 'production', // 严格模式
});
  • modules/cart.js
//初始化数据
const state = {};

//getter 抛出去的数据
const getters = {};

//action 异步的操作
const actions = {};

//mutation
const mutations = {};

export default {
  state,
  mutations,
  actions,
  getters,
};
  • 搭建问vuex的我们现在要使用vuex的,在main.js中使用
import Vue from 'vue';
import App from './App';

import store from './store’; //引入

new Vue({
  el: '#app',
  store,  //使用
  template: '<App/>',
  components: {
    App,
  },
});
  • 到这步,vuex的模板基本,但是没有效果怎么办,现在开始修改的product.vue中data中的shoplist剪切到cart.js中的state中,
    这里解释一下,state和组件中大data作用是一样,都是的设置假数据的和变量,查看文档的state

    修改cart.js的state

const state = {
    //商品列表
    shop_list: [{
        id: 11,
        name: '鱼香肉丝',
        price: 12,
      }, {
        id: 22,
        name: '宫保鸡丁',
        price: 14
      }, {
        id: 34,
        name: '土豆丝',
        price: 10
      }, {
        id: 47,
        name: '米饭',
        price: 2
      }],

      //添加到购物车的商品(已选商品)
      added:[]
}
  • 既然state和data的作用是一样的,那么我们在组件中拿到state中的shop_list的数据呢?
    • 这是需要getters的处理哦
//getter 抛出去的数据
const getters = {
    //商品列表
    shoplist:state => state.shop_list,
 }
  • 组件中怎么拿到这个shoplist数据呢?查看文档getters 中的mapGetters辅助函数的方法

    这个数据是从product组件剪切走的,现在还回去,是这样秀的

    script标签里面引入vuex的辅助函数, export default 中computed使用

  import {mapGetters} from "vuex";

  //第一种方法:vuex和组件中使用的shoplist的名称,下面所有其他的辅助函数都使用第一种方法,第二种方法不在说明
   computed: {
     ...mapGetters(['shoplist’]) //这是数组['A’,’B’,...]
   }, 

    //第二种写法,vuex中抛出的shoplist,但是我们组件实际用的是shoplistData,实际就是换个名字
   //computed: {
     //…mapGetters({
       //  shoplistData:'shoplist’  //这是对象
     //})
   //},
  • 上面的2中写法文档中有详细解释,希望先查看文档,这样看的比较好。

  • 现在需要我们添加的购物车的操作,product.vue中按钮处添加

 <div @click='addToCart(shop)' class="btn btn-info">购物车</div>
  • 现在编写addToCart的方法,我们会到cart,js 中的action里面去,查看文档action的介绍,需要commit来分发actions
const actions = {
    //添加到购物车操作
    addToCart({commit},product){
        commit('add’,{  //传递一个add的方法,携带参数id
            id:product.id
        })
    },
}
  • 既然我们分发出来了一个add的方法,我们在mutations中接受,mutation中可以直接拿到state里面所有的数据,因为这里的added是自己定一个已选商品的数组,我组件中点击时传递一个对象过来的,find这个对象,但是这里有2种情况,一个added为空或者有数据,但是不是当前点击的对象的数据,当为空时,我们人为个这个对象push一个id和num为1的值,有点击就是当前这个对象的时候,我们执行++的操作,这里打印一下的值,或者从vue-tool的种查看的,vuex的一个浏览器的查看,自己百度去安装,查看数据比较方便
const mutations = {
    //添加到购物车操作
    add(state,{id}){  //解构id 你可以 测试id 和 {id}的区别        
    let record = state.added.find(n=>n.id == id); 
        if(!record){
            state.added.push({
                id,
                num:1
            })
        }else {
            record.num++
        }
        console.info(record,state.added)
      },
    }
  • 这里vuex中action的addToCart方法写好了,如何product.vue中的addToCart方法对应上去呢?
  • 这里文档中有介绍,有个mapActions的辅助函数,
    script中标签引入 methods中调用
import {mapGetters, mapActions } from ‘vuex’ //之前引入了一个mapGetters
methods: {
 ...mapActions(['addToCart'])
}
  • 这样我们就是action和组件中方法关联起来了,
  • 现在增加商品的click事件解决,但是我们要把added给抛出,但是前提要对added这个数组进行数据转化
  • 修改getter中方法,添加一条
const getters = {
    //商品列表
    shoplist:state => state.shop_list,
    //购物车的列表
    cartProducts:state=>{
        return state.added.map(({id,num})=>{ //在actions中只有的id和num的字段
            //在原始数据数据上面进行刷选,这里通过id来匹配
            let product = state.shop_list.find(n=>n.id == id)
            // console.info('product',product)
            return {
                ...product,
                num
            }
        })
    },
    },
  • 这里我们需要将cartProducts这个抛出去,和shoplist的方法一样的,只不过这个是在cart.vue中操作,
    script中引入
    import { mapGetters} from "vuex";


    computed: {
        ...mapGetters(['cartProducts’]) //页面中v-for的数据
    },
  • 现在我们开始计算总价,总数量 和 清空购物车功能,在getter中操作,
const getters = {
    //商品列表
    shoplist:state => state.shop_list,
    //购物车的列表
    cartProducts:state=>{
        return state.added.map(({id,num})=>{
            let product = state.shop_list.find(n=>n.id == id)
            // console.info('product',product)
            return {
                ...product,
                num
            }
        })
    },
    //计算总价
    totalPrice:(state,getters)=>{  //getter中可以调用getter里面的方法,文档有介绍
        let total = 0;
        getters.cartProducts.forEach(n=>{
            total += n.price * n.num
        })
        return total;
    },
    //计算总数量
    totalNum:(state,getters)=>{
        let total = 0;
        getters.cartProducts.forEach(n=>{
            total += n.num
        })
        return total;
    },
}
  • 调用的方法是一样,
 import { mapGetters } from 'vuex'
 computed:{
    ...mapGetters(['totalPrice','totalNum'])
 }
  • 清空购物车的操作,原理就是added的数组置为空数组就可以的,
<div class="item btn btn-danger" @click='clearAllCart'>清空购物车</div>
  • 将actions中clearAllCart和info.vue中的组件联系到一起,前面已经介绍过了。cart.js中的actions
const actions = {
    //添加到购物车操作
    addToCart({commit},product){
        commit('add',{
            id:product.id
        })
    },
    //清除购物车
    clearAllCart({commit}){
        commit('clearAll’) //分发一个clearAll事件,不带参数进行
    },
}
  • mutations接受
const mutations = {
    //添加到购物车操作
    add(state,{id}){
        let record = state.added.find(n=>n.id == id);
        if(!record){
            state.added.push({
                id,
                num:1
            })
        }else {
            record.num++
        }
        // console.info(record)
    },
    //清除购物车
    clearAll(state){
        state.added = []
    },
}
  • info.vue中调用clearAllCart方法,
import { mapGetters, mapActions } from 'vuex'

methods: {
    ...mapActions(['clearAllCart'])
},
  • 还有一个小功能就是已选商品中的有个删除的按钮,实现这个功能,cart.vue组件中修改
<div @click='delProduct(shop)' class="btn btn-danger btn-sm">删除</div>

cart,js中actions

const actions = {
    //添加到购物车操作
    addToCart({commit},product){
        commit('add',{
            id:product.id
        })
    },
    //清除购物车
    clearAllCart({commit}){
        commit('clearAll')
    },
    //删除购物车的指定的商品
    delProduct({commit},product){
        commit('del',product)//commit del的方法
    }
}
  • mutations
const mutations = {
    //添加到购物车操作
    add(state,{id}){
        let record = state.added.find(n=>n.id == id);
        if(!record){
            state.added.push({
                id,
                num:1
            })
        }else {
            record.num++
        }
    },
    //清除购物车
    clearAll(state){
        state.added = []
    },
    //删除购物车的指定的商品
    del(state,product){
        //console.info(state,product)
        state.added.forEach((n,i)=>{
            if(n.id == product.id){
                //console.info(11,n)
                //找到下标值
                state.added.splice(i,1)
            }
        })
    },
}
  1. cart.vue调用
 import { mapGetters,mapActions} from "vuex";

 methods:{
       ...mapActions(['delProduct'])
 }

到此为止,vuex的基本使用方法基本介绍完了,
1. 详细看看vuex中的例子和写法
2. 这个所有的actions的操作对于state中added数据都是共享的,这里修改其他地方也立即修改,都是同步的,特别明显就是不同组件中数据共享
3. 文章写的比较急,具体的查看的git的地址vuex-shopcart的github地址

  • 17
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值