vue案例-购物车进阶版(组件化,vuex,mock数据)

1. 目录结构

在这里插入图片描述

2. mock 数据

mock数据只能通过ajax请求获取,从而达到模拟后台接口的作用

定义数据 data.json

[
  {
    
    
    "id": 1,
    "name": "TCL彩电",
    "price": 1000,
    "num": 1
  },
  {
    
    
    "id": 2,
    "name": "机顶盒",
    "price": 1000,
    "num": 1

  },
  {
    
    
    "id": 3,
    "name": "海尔冰箱",
    "price": 1000,
    "num": 1

  },
  {
    
    
    "id": 4,
    "name": "小米手机",
    "price": 1000,
    "num": 1

  },
  {
    
    
    "id": 5,
    "name": "PPTV电视",
    "price": 1000,
    "num": 2

  }
]

提供数据接口 mockServer.js

/*
使用mockjs提供mock数据接口
 */
import Mock from 'mockjs'
import data from './data.json'

// 返回goods的接口
Mock.mock('/', {
    
    data:data});

// export default ???  不需要向外暴露任何数据, 只需要保存能执行即可

main.js 导入

// 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 store from './store'  // 导入vuex
import './mock/mockServer'  // 导入mock接口


Vue.config.productionTip = false

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

3. vuex 状态管理

action.js


/*
  通过mutation间接更新state的多个方法
 */

import {
    
    LIST, DELETE_GOOD, ADD_GOOD_COUNT, SUB_GOOD_COUNT, UPDATE_GOOD_COUNT} from './mutation_types'
import axios from 'axios'

export default {
    
    
  // 异步请求mock数据接口获取list数据
  async reqList({
    
    commit}){
    
    
    const result = await axios.get('/');
    const list = result.data.data;
    commit(LIST, {
    
    list})
  },
  // 删除商品
  deleteGood({
    
    commit}, id){
    
    
    commit(DELETE_GOOD, {
    
    id})
  },
  // 添加商品
  addGood({
    
    commit}, id){
    
    
    commit(ADD_GOOD_COUNT, {
    
    id})
  },
  // 减少商品
  subGood({
    
    commit}, id){
    
    
    commit(SUB_GOOD_COUNT, {
    
    id})
  },
  // 更新商品
  updateGood({
    
    commit}, {
    
    id, value}){
    
    
    commit(UPDATE_GOOD_COUNT, {
    
    id, value})
  }
}

getters.js

/*
包含多个基于state的getter计算属性的对象
 */

export default {
    
    
  // 计算商品总数
  total(state){
    
    
    let sumPrice = 0;
    state.list.forEach((item)=>{
    
    
      sumPrice += item.price * item.num
    });
    return sumPrice
  }
}

index.js

/*
vuex最核心的管理对象store
 */
import Vue from 'vue'
import Vuex from 'vuex'
import state from './state'
import mutations from './mutation'
import actions from './action'
import getters from './getters'

Vue.use(Vuex);

export default new Vuex.Store({
    
    
  state,
  mutations,
  actions,
  getters
})

mutatioan.js


/*
  直接更新state的多个方法
 */

import {
    
     LIST, DELETE_GOOD, ADD_GOOD_COUNT, SUB_GOOD_COUNT, UPDATE_GOOD_COUNT} from './mutation_types'

export default {
    
    

  [LIST](state, {
    
    list}){
    
    
    state.list = list
  },
  [DELETE_GOOD](state, {
    
    id}){
    
    
    // 通过id获取索引
    const index = state.list.findIndex(item=>{
    
    
      return item.id === id;
    });
    state.list.splice(index,1)
  },

  [ADD_GOOD_COUNT](state, {
    
    id}){
    
    
    // 通过id获取索引
    const index = state.list.findIndex(item=>{
    
    
      return item.id === id;
    });

    state.list[index].num ++
  },
  [SUB_GOOD_COUNT](state, {
    
    id}){
    
    
    // 通过id获取索引
    const index = state.list.findIndex(item=>{
    
    
      return item.id === id;
    });
    state.list[index].num --
  },

  [UPDATE_GOOD_COUNT](state, {
    
    id, value}){
    
    
    // 通过id获取索引
    const index = state.list.findIndex(item=>{
    
    
      return item.id === id;
    });
    state.list[index].num = value;
  },
}

mutation_type.js

/*
  所有常量
 */


export const LIST = 'list';  // 数据列表

export const DELETE_GOOD = 'delete_good';  //  删除商品

export const ADD_GOOD_COUNT = 'add_good_count';  // 添加商品数量
export const SUB_GOOD_COUNT = 'sub_good_count';  // 减少商品数量
export const UPDATE_GOOD_COUNT = 'update_good_count';  // 修改商品数量

state.js


/*
  所有管理的状态对象
 */
export default {
    
    

  list: []
}

main.js 导入,见上

4. 组件使用

app.vue

<template>
  <div id="app">
    <div class="container">
      <div class="cart">

        <Header></Header>
        <!-- $event 接受子组件传过来的参数 -->
        <List :list="list" @del="del($event)" @changeNum="changeNum($event)"></List>
        <Footer :list="list"></Footer>

      </div>
    </div>
  </div>


</template>

<script>
    import Header from "./components/Header";
    import List from "./components/List";
    import Footer from "./components/Footer";

    import {
    
    mapState} from 'vuex'

    export default {
    
    
        components:{
    
    
            Header, List, Footer
        },
        computed:{
    
    
          ...mapState(['list'])
        },
        
        // 页面刷新请求数据
        mounted(){
    
    
          this.$store.dispatch('reqList')
        }
    }
</script>

<style type="text/css">
  .container {
    
    
  }

  .container .cart {
    
    
    width: 300px;
    margin: auto;
  }

  .container .title {
    
    
    background-color: lightblue;
    height: 40px;
    line-height: 40px;
    text-align: center;
    /*color: #fff;*/
  }

  .container .total {
    
    
    background-color: #FFCE46;
    height: 50px;
    line-height: 50px;
    text-align: center;
  }

  .container .total button {
    
    
    margin: 0 10px;
    background-color: #DC4C40;
    height: 35px;
    width: 80px;
    border: 0;
  }

  .container .total span {
    
    
    color: red;
    font-weight: bold;
  }

  .container .item {
    
    
    height: 55px;
    line-height: 55px;
    position: relative;
    border-top: 1px solid #ADD8E6;
  }

  .container .item img {
    
    
    width: 45px;
    height: 45px;
    margin: 5px;
  }

  .container .item .name {
    
    
    position: absolute;
    width: 90px;
    top: 0;
    left: 55px;
    font-size: 16px;
  }

  .container .item .change {
    
    
    width: 100px;
    position: absolute;
    top: 0;
    right: 50px;
  }

  .container .item .change a {
    
    
    font-size: 20px;
    width: 30px;
    text-decoration: none;
    background-color: lightgray;
    vertical-align: middle;
  }

  .container .item .change .num {
    
    
    width: 40px;
    height: 25px;
  }

  .container .item .del {
    
    
    position: absolute;
    top: 0;
    right: 0px;
    width: 40px;
    text-align: center;
    font-size: 40px;
    cursor: pointer;
    color: red;
  }

  .container .item .del:hover {
    
    
    background-color: orange;
  }
</style>


头部

<template>
  <div class="title">我的商品</div>
</template>

<script>
    export default {
    
    
        name: "Header"
    }
</script>

<style scoped>

</style>

列表

<template>
  <div>
    <div class="item" v-for="item in list">
      <img src="../img/a.jpg">
      <div class="name"> {
    
    {
    
     item.name }} </div>
      <div class="change"><a href="" @click.prevent="sub(item.id)"></a>
        <input type="text" class="num" :value="item.num" @blur="updateCount(item.id, $event)">
        <a href="" @click.prevent="add(item.id)"></a></div>
      <div class="del" @click="del(item.id)">×</div>
    </div>

  </div>
</template>

<script>
  import {
    
    mapState} from  'vuex'
    export default {
    
    
        name: "List",
        computed:{
    
    
          ...mapState(['list'])
        },
        methods:{
    
    
          del(id){
    
    
              this.$store.dispatch('deleteGood', id)
          },

            add(id){
    
    
                this.$store.dispatch('addGood', id);

            },
            sub(id){
    
    
                this.$store.dispatch('subGood', id)
            },
            updateCount(id, event){
    
    

                this.$store.dispatch('updateGood',{
    
    id:id, value: event.target.value})
            }
        }
    }
</script>

<style scoped>

</style>

尾部

<template>
  <div class="total"><span>总价:{
    
    {
    
     total }}</span>

  </div>
</template>

<script>
  import {
    
    mapGetters} from 'vuex'
    export default {
    
    
        name: "Footer",
        props:['list'],
        computed:{
    
    
            ...mapGetters(['total'])
        }

    }
</script>

<style scoped>

</style>

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/gklcsdn/article/details/111167553