国瑞个人博客
首页 > Vue-Cli > Vue-router > 使用vuex制作购物车

使用vuex制作购物车

使用vuex制作购物车

 2018年08月27日 作者: 国瑞个人博客 594次浏览

购物车是商城一类的网站的重要的一部分,因为涉及对多个数据的操作,逻辑也相对会复杂很多,使用jquery的情况下,逻辑会很复杂,很容易出错,但是使用vue进行搭建就会容易很多了。接下来我们就一起来搭建一个简单的购物车吧

购物车需要用到以下知识储备:

h5存储
html+css基础
js基础
vue基础
vue-cli基础
vuex基础

细节梳理:

1.购物车中的总数量为一个变量每次为累加操作
2.每次点击加入购物车之后,都会新建一个数组,里面存放一个对象,包括购物车中的物品的详细信息,这里我使用的是localStorage进行存储
3.购物车中的数据修改使用了vuex中的状态管理

全部源码如下所示:

main.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
// 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 router from './router'
import Vuex from 'vuex'
//import store from './store'
Vue.use(Vuex)

// 2.1 导入 vue-resource
import VueResource from 'vue-resource'
// 2.2 安装 vue-resource
Vue.use(VueResource)
// 设置请求的根路径
Vue.http.options.root = 'http://www.localhost/obj/resource.php/';
// 全局设置 post 时候表单数据格式组织形式   application/x-www-form-urlencoded
Vue.http.options.emulateJSON = true;
//开局获取到本地存储中的数据
var car = JSON.parse(localStorage.getItem('car') || '[]');


Vue.config.productionTip = false
let store = new Vuex.Store({
  state:{ //this.$store.state.***
    car:car   //购物车
  },
  mutations:{//this.$store.commit('方法的名称','按需传入唯一的参数')
    addToCar(state,goodsinfo){
      var flag = false;
      state.car.some(item=>{
        if(item.id == goodsinfo.id){
          item.count+=parseInt(goodsinfo.count)
          flag = true;
          return true
        }
      })

      if(!flag){
        state.car.push(goodsinfo);
      }
      //购物车中的数据存储到locaStorage中
      localStorage.setItem('car',JSON.stringify(state.car))
    },
    updateGoodsInfo(state,goodsinfo){
      //修改购物车中的商品的数量值
      state.car.some(item=>{
        if(item.id == goodsinfo.id){
          item.count = parseInt(goodsinfo.count)
          return true
        }
      })
      //修改完毕,再次更新
      localStorage.setItem('car',JSON.stringify(state.car))
    },
    removeFormCar(state,id){
      console.log("state="+state);

      state.car.some((item,i)=>{
        if(item.id == id){
          state.car.splice(i,1)
          return true
        }
      })
    localStorage.setItem('car',JSON.stringify(state.car))
    },
    updateGoodsSelected(state,info){
      console.log(info);
      state.car.some((item)=>{
        if(item.id == info.id){
          item.selected = info.selected
        }
      })
      localStorage.setItem('car',JSON.stringify(state.car))
    }



  },
  getters:{//this.$store.getters.***
      getAllCount(state){
        var c = 0;
        state.car.forEach(item=>{
          c+=item.count
        })
        console.log("c==="+c);
        return c;
      },
      getGoodsCount(state){
        var o = {}
        state.car.forEach(item=>{
          o[item.id] = item.count
        })
        return o
      },
      getGoodsSelected(state){
        var o ={}
        state.car.forEach(item=>{
          o[item.id] = item.selected
        })
        return o
      },
      getGoodsCountAndmount(state){
        var o = {
          count:0,  
          amount:0
        }
        state.car.forEach(item=>{
          if(item.selected){
            o.count+= item.count
            o.amount+=item.curprice*item.count
          }
        })
        return o
      }
     
  }


})
/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  store,
  components: { App },
  template: '<App/>'
})

app.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
<template>
  <div id="app">
        <div @click="goBack" v-show="flag">返回</div>
        <router-link to="/shap">商品列表</router-link>
    <div class="footer">
      <div>首页</div>
      <div>新闻</div>
      <router-link to="/shapcar" tag="div">购物车 <span>{{$store.getters.getAllCount}}</span></router-link>
      <div>用户中心</div>
    </div>
    <router-view/>

  </div>

</template>

<script>
export default {
    name: 'App',
    data(){
        return {
            flag:false
        }
    },
    created(){
        //页面加载即判断
        this.flag = this.$route.path === "/home"?false:true;
    },
    methods:{
        goBack(){
            this.$router.go(-1);
        }
    },
    watch:{
        "$route.path":function(newVal){
            if(newVal === "/home"){
                    this.flag = false
            }else{
                this.flag = true
            }
        }
    }
}
</script>

<style>
*   {
  margin:0;
  padding:0;
}
.footer {
    background: #ccc;

    position: relative;
    z-index: 999;
    width:100%;
    height: 70px;
    bottom:0;
    display: flex;
    position: fixed;
    left:0;
    bottom: 0;
}
.footer div {
    text-align: center;
    line-height: 70px;
    width:25%;
    height: 100%;
    box-shadow:0 0 3px #ccc;
}
.footer span {
    padding:4px;
    box-shadow:0 0 3px #ccc;
    background: red;
    color:#fff;

}
#app {
    margin-bottom: 100px;
}
</style>

index.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
import Shap from '@/components/Shap'
import ShapInfo from '@/components/ShapInfo'
import ShapCar from '@/components/ShapCar'
Vue.use(Router)

export default new Router({
  //mode:'history',这个还不能去掉,去掉就会出问题
  routes: [
    {
      path: '/',
      name: 'HelloWorld',
      component: HelloWorld
    },
    {
      path: '/shap',
      name: 'Shap',
      component: Shap
    },
    {
      path: '/home/shapinfo/:id',
      name: 'ShapInfo',
      component: ShapInfo
    },
    {
      path:'/shapcar',
      name: 'ShapCar',
      component: ShapCar  
    }        
  ]
})

商品列表显示组件Shap.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
<template>
<div class="goods-list">
    <div class="item" v-for="item in datalist" :key="item.id">
    <router-link :to="'/home/shapinfo/'+item.id">

        <img src="../assets/logo.png" alt="" width="100%" height="150px" >
        <div class="title">{{item.title}}</div>
        <div class="val">现价:${{item.curprice}}</div>
        <div>原价:<del>${{item.price}}</del></div>
        <p>热卖中剩余,{{item.count}}</p>
     </router-link>

    </div>
</div>
</template>
<script>


export default {
  data() {
    return {
      datalist:[]
    };
  },
  created(){
this.getGoodsList()
  },
  methods:{
      getGoodsList(){
          this.$http.get('?shap=true').then(result=>{
              if(result.body.status==0){
                  this.datalist = result.body.message;
              console.log(this.datalist);

              }
          })
      }
  }
};
</script>
<style scoped>
.goods-list {
  width: 100%;
  height: auto;
  display: flex;
  flex-wrap: wrap;
}
.item {
  width: 48%;
  height: auto;
  margin: 1%;
  box-shadow: 0 0 3px #ccc;
  box-sizing: border-box;
  padding: 1%;
}
</style>

购物车数量选择组件number.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<template>
    <div>
            <div>购买数量:<input  type="number" value="1" @change="countChanged" max="10" min="1" ref="numbox" ></div>
            <!-- readonly 禁止修改 -->
    </div>
</template>
<script>
export default {
  methods: {
    countChanged() {
        //每当 文本框中的数据被修改的时候,立即把 最新的数据,通过事件调用,传递给父组件
      console.log(this.$refs.numbox.value);
    this.$emit('getcount',parseInt(this.$refs.numbox.value));

    }
  }
};
</script>

商品详情组件Shapinfo.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
<template>
    <div>
    <transition
      @before-enter="beforeEnter"
      @enter="enter"
      @after-enter="afterEnter">
      <div class="ball" v-show="ballFlag" ref="ball"></div>
    </transition>

        <div class="photo">
            <img src="../assets/logo.png" alt="" width="100%" height="150px">
        </div>
        <div class="info" >
            <h1>{{shapinfo.title}}</h1>
            <p>市场价{{shapinfo.price}},特价¥{{shapinfo.curprice}}</p>
            <number @getcount="getSelectedCount"></number>
            <input type="submit" value="立即购买">
            <input type="submit" value="加入购物车"  @click="addToShopCar">
            <p>id==={{id}}</p>
        </div>
    </div>
</template>
<script>

// 引入组件
import number from '@/components/number'
export default {
    data(){
        return {
            shapinfo:[],
            ballFlag:false,
            selectedCount:1,
            id:this.$route.params.id
        }
    },
    created(){
        this.getgoodsinfo();
    },
    methods:{
        addToShopCar(){
            console.log('点击了添加购物车');
            //添加购物车
            var shapinfo = {
                id:this.id,
                count:this.selectedCount,
                curprice:this.shapinfo.curprice,
                selected:true,
                title:this.shapinfo.title
            };
            console.log(shapinfo);
            //调用comiit进行提交
            this.$store.commit('addToCar',shapinfo)

                this.ballFlag=!this.ballFlag;
        },
       
    beforeEnter(el){
        el.style.transform = "translate(0,0)"

    },
    enter(el,done){
        el.offsetWidth;
        el.style.transform = "translate(93px,230px)";
        el.style.transition = "all 1s cubic-bezier(.4,-0.3,1,.68)";
        done(); //引用afterenter
    },
    afterEnter(el){
            this.ballFlag=!this.ballFlag;
    },
    getSelectedCount(count){
        this.selectedCount = count;
        console.log('父组件拿到的值为:'+count);
    }
    ,
    getgoodsinfo(){
          console.log('请求结果=');


        this.$http.get("?shap=" + this.id).then(result => {
        if (result.body.status === 0) {
          // 先循环轮播图数组的每一项,为 item 添加 img 属性,因为 轮播图 组件中,只认识 item.img, 不认识 item.src
          this.shapinfo = result.body.message;
          console.log(this.shapinfo);

        }
      });
    }


    },
    components:{
        number
    }

}
//cubic-bezier.com
</script>
<style scoped>
  .ball {
    width: 15px;
    height: 15px;
    border-radius: 50%;
    background-color: red;
    position: absolute;
    z-index: 99;
    top: 390px;
    left: 146px;
  }


</style>

购物车结算界面数量选择组件number-car.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<template>
    <div>
            <div>购买数量:<input  type="number" :value="initcount" @change="countChanged" max="10" min="1" ref="numbox" ></div>
            <!-- readonly 禁止修改 -->
    </div>
</template>
<script>
export default {
  methods: {
    countChanged() {

  console.log(this.goodsid);
  this.$store.commit("updateGoodsInfo",{
    id:this.goodsid,
    count:this.$refs.numbox.value
  })

    }
  },
  props:['initcount','goodsid']
};
</script>

购物车结算组件 ShapCar.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
<template>
<div>
    <div class="item" v-for="(item,i) in data"  :key="item.id">
       <input type="checkbox"  v-model="$store.getters.getGoodsSelected[item.id]" @change="selectChanged(item.id,$store.getters.getGoodsSelected[item.id])" >
       <p> 单价:{{item.curprice}}
       </p>
       <p> 数量:
         <number :goodsid="item.id" :initcount="$store.getters.getGoodsCount[item.id]"></number>
        </p>
       <p> 标题{{item.title}} </p>
         <p><a href="##" @click.prevent="remove(item.id,i)">删除</a></p>
   </div>

   <div>当前按钮的状态为:{{$store.getters.getGoodsSelected}}</div>
   <div>当前选择的件数:{{$store.getters.getGoodsCountAndmount.count}}</div>
   <div>当前选择的钱数:{{$store.getters.getGoodsCountAndmount.amount}}</div>
</div>    
</template>
<script>
import number from "@/components/number-car";

export default {
  data() {
    return {
data:[]
    };
  },
  methods: {
    remove(id,index){
      this.data.splice(index, 1);
      console.log("--------");

      this.$store.commit('removeFormCar',id)
    },
    selectChanged(id,val){
      this.$store.commit('updateGoodsSelected',{id,selected:val})

      console.log('点击了');
    }
  },
  components: {
    number
  },
  created(){
    console.log('挂载完成中')
   console.log(JSON.parse(localStorage.getItem('car')));
  this.data = JSON.parse(localStorage.getItem('car'));
  }
};
</script>
<style scoped>
.item {
  width: 100%;
  display: flex;
  flex-wrap: wrap;
  height: 100px;
  border: 1px solid red;
  box-sizing: border-box;
}
</style>

本文接口请求的是本地服务器(请求路径:http://localhost/obj/resource.php),本地服务器代码为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
<?php

// 指定允许特定域名访问
// header('Access-Control-Allow-Origin: https://localhost');
// // 响应类型
// header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
// // 响应头设置
// header('Access-Control-Allow-Headers: X-Requested-With, Content-Type, Accept');
/*这里填写的是允许访问的端口*/
//header('Access-Control-Allow-Origin:http://localhost:8080');
header('Access-Control-Allow-Origin:http://www.car.cn');



if(!empty($_GET['shap'])){
    $value = array(
        array(
        'id'=>1,
        'price'=>3999,
        'curprice'=>3000,
        'title'=>'小米Max,未来科技',
        'count'=>99
        ),
        array(
            'id'=>2,
            'price'=>10000,
            'curprice'=>1000,
            'title'=>'华为手机,就是快',
            'count'=>77
        ),
        array(
        'id'=>3,
        'price'=>1999,
        'curprice'=>999,
        'title'=>'oppo r9,照亮你的美',
        'count'=>99
        ),
        array(
            'id'=>4,
            'price'=>10000,
            'curprice'=>9999,
            'title'=>'8848钛金手机',
            'count'=>99
            ),
            array(
                'id'=>5,
                'price'=>10000,
                'curprice'=>1000,
                'title'=>'华为手机,就是快',
                'count'=>77
            ),
            array(
            'id'=>6,
            'price'=>1999,
            'curprice'=>999,
            'title'=>'oppo r9,照亮你的美',
            'count'=>99
            ),        

    );
if($_GET['shap']===true){

}else{
    $num = $_GET['shap'];
   // echo $num;
    foreach($value as $val=>$key){
   // echo '<pre>';
    if((int)$key['id']==$num){
        $oneVal = $key;
        $value=[];
        $value=$oneVal;
    }
    }
}
    $arr=array(
            'status'=>0,
            'message'=>$value ,
        );
        echo json_encode($arr);


}

?>
百度已收录

点击快速分享:

以上就是国瑞前端个人博客带来的是《使用vuex制作购物车》,感谢您的观看!

如果没有特殊的说明,本文即为国瑞前端博客原创(www.huanggr.cn),欢迎读者转载并保留本站版权!https://www.huanggr.cn/492.html

「专业前端博客,如果觉得我的文章对您有用,请帮助本站成长」

赞( 17 ) 打赏

谢谢你请我吃鸡腿*^_^*

支付宝
微信
17

谢谢你请我吃鸡腿*^_^*

支付宝
微信

上一篇:

下一篇:

相关文章:

共有 0 条评论

博客简介

国瑞个人博客: https://www.huanggr.cn/,我们关注Web前端开发技术,web前端开发,移动前端开发,前端资讯,同时分享前端资源和工具等,期待你的参与,了解更多..

博主独立研发主题:

本站唯一QQ群

加入国瑞个人博客QQ群

本群为学习探讨群,主要和前端相关,欢迎广大前端(抱有学习目的均可)爱好者加入!广告请勿添加!

升级版本

web前端开发博客,基于vue脚手架制作的前端博客正在制作中,尽情期待,目前示例的代码位于此处

最新版本(尽请期待)-web前端开发博客

精彩评论

本站主要提供服务

二年web前端开发博客,本站专注提供web资源下载,技术问题解答,经验分享,也提供新手的web技术指导,二年前端个人博客,期待你的加入!

站点统计

  • 文章总数: 269 篇
  • 草稿数目: 50 篇
  • 分类数目: 26 个
  • 页面总数: 16 个
  • 评论总数: 223 条
  • 链接总数: 10 个
  • 标签总数: 104 个
  • 建站时间: 808 天
  • 注册用户: 659 人
  • 访问总量: 8785246 次
  • 最近更新: 2019年7月15日
-->