② 尚品汇的前台开发笔记【尚硅谷】【Vue】

文章目录

八、加入购物车

点击 加入购物车 的时候,先发请求,把数据存储到服务器,然后再进行路由跳转

在这里插入图片描述

  • 当点击 加入购物车 的时候,会跳转到 加入购物车成功的页面,到时候需要配置路由,进行路由跳转
    在这里插入图片描述

路由跳转之前发请求

api—请求接口

//     src/api/index.js

// 将产品添加到购物车中(或者 更新某一个产品个数)
//   /api/cart/addToCart/{ skuId }/{ skuNum }  POST 带参数
export const reqAddOrUpdateShopCart = (skuId,skuNum)=>{
   
    return requests({
   url:`/cart/addToCart/${
     skuId}/${
     skuNum}`,method:'POST'})
}

将数据存储到服务器里

  1. 派发actions,发请求

    //       src / pages / detail /index.vue
    
    <div class="add">
     <!-- 以前的路由跳转,从A路由跳转到B路由 -->
     <!-- 在这里路由跳转,进行路由跳转之前,需要发请求 把你购买的产品信息通过请求的形式通知服务器,服务器进行相应的存储 -->
          <a @click="addShopcar">加入购物车</a>
    </div>
    
        // 加入购物车的回调函数
    addShopcar() {
         
          // 1. 发请求--将产品加入到数据库(通知服务器)
          //    服务器存储成功----进行路由跳转
          //    失败,给用户提示
         this.$store.dispatch( "detail/addOrUpdateShopCart",{
         skuId:this.$route.params.skuId,skuNum:this.skuNum});
    },
    

加入购物车以后(发请求),前台将参数带给服务器

服务器写入数据成功,并没有返回其他的数据,只是返回code=200,代表这次成功

⚠ !!!因为服务器没有返回其余的数据,所以我们不需要vuex来存储数据

  1. 将参数带给服务器

    const actions = {
         
        // 将产品添加到购物车中
        async addOrUpdateShopCart({
          commit},{
          skuId,skuNum}){
         
            // 加入购物车返回的结果
            let result = await reqAddOrUpdateShopCart(skuId,skuNum);
            console.log('购物车',result);
            // 加入购物车以后(发请求),前台将参数带给服务器
            // 服务器写入数据成功,并没有返回其他的数据,只是返回code=200,代表这次成功
            // 因为服务器没有返回其余的数据,所以我们不需要vuex来存储数据
        },
    };
    

判断加入成功 或 失败

async:只要有async返回的就是Promise,Promise返回的不是成功就是失败

  1. 发请求–将产品加入到数据库(通知服务器)

  2. 服务器存储成功----进行路由跳转

  3. 服务器存储失败------给用户提示

//      src/pages/detail/index.vue

	// 加入购物车的回调函数
    async addShopcar() {
   
      // 1. 发请求--将产品加入到数据库(通知服务器)
      //    服务器存储成功----进行路由跳转
      //    失败------给用户提示
      try {
   
        await this.$store.dispatch("detail/addOrUpdateShopCart", {
   skuId: this.$route.params.skuId,skuNum: this.skuNum,});
        // 成功了进行路由跳转
          .....
      } catch (error) {
   
        alert(error.message);
      }
    },

this.$store.dispatch("detail/addOrUpdateShopCart", {skuId: this.$route.params.skuId,skuNum: this.skuNum,});表示调用了addOrUpdateShopCart这个函数,👇调用这个函数,这个函数有async,说明这个函数的返回值是Promise函数

await返回的是promise成功的值,但是我们要有成功做什么以及失败做什么…如果await的promise失败了,就会抛出异常,我们需要通过try…catch捕获处理

所以在detail.vue中,给 加入购物车的回调函数加上 async

//      src/store/detail/index.js

	// 将产品添加到购物车中
    async addOrUpdateShopCart({
     commit }, {
     skuId, skuNum }) {
   
        // 加入购物车返回的结果
        // 加入购物车以后(发请求),前台将参数带给服务器
        // 服务器写入数据成功,并没有返回其他的数据,只是返回code=200,代表这次成功
        // 因为服务器没有返回其余的数据,所以我们不需要vuex来存储数据
        let result = await reqAddOrUpdateShopCart(skuId, skuNum);
        // 当前的这个函数,如果执行,返回promise
        // 👇代表服务器加入购物车成功
        if(result.code==200){
   
            return 'ok'; // 返回的只要是非空字符串就是成功
        }else{
   
            // 代表加入购物车失败
            return Promise.reject(new Error('false'));
        }
    },

成功后进行路由跳转

注意:路由不是组件!!!??????❓

路由组件通常存放在pages文件夹,一般组件通常存放在components文件夹。

使用组件的步骤:创建-注册-引用-使用

  1. 创建路由,写到专门放路由的文件夹下

    在这里插入图片描述

  2. 编写路由配置项:src/router/index.js

    // 配置路由的地方
    import Vue from 'vue';
    import VueRouter from 'vue-router';
    // 使用插件
    Vue.use(VueRouter);
    
    // 引入路由组件
    import AddCartSuccess from '../pages/AddCartSuccess'
    
    // 先把VueRouter原型对象的push,先保存一份
    const originalPush = VueRouter.prototype.push
    const originalReplace = VueRouter.prototype.replace
    
    // 重写push | replace
    // 参数:告诉原来的push方法,你往哪里跳转(传递哪些参数)
    VueRouter.prototype.push = function push(location) {
         
        return originalPush.call(this, location).catch(err => err)
    }
    VueRouter.prototype.replace = function replace(location) {
         
        return originalReplace.call(this, location).catch(err => err)
    }
    
    // 配置路由
    export default new VueRouter({
         
        // 配置路由
        routes: [
            ...
            {
         
                name: 'addcartsuccess',
                path: '/addcartsuccess',
                component: AddCartSuccess,
                meta: {
          showFooter: true }
            },
            // 重定向:在项目跑起来的时候,访问/,立马让他定向到首页!!!
            {
         
                path: '*',
                redirect: '/home',
            }
        ],
        // 控制滚动条的滚动行为
        scrollBehavior(to, from, savedPosition) {
         
            // return 期望滚动到哪个的位置
            return {
          y: 0 }; // 始终滚动到顶部
        }
    })
    

开始进行路由跳转,并进行路由传参

在这里插入图片描述

路由传参的话数据过多,在skuInfo里面,是个对象,以及还要带参数skuNum,地址栏会有点乱

在这里插入图片描述

所以这里我们只带skuNum参数传过去,其余复杂数据用会话存储—不持久化,会话结束数据消失

浏览器存储功能:HTML5中新增的,分为本地存储和会话存储

本地存储:持久化的,具有上限-----5M

会话存储:不是持久化的(浏览器关闭等),

在这里插入图片描述

    // 加入购物车的回调函数
    async addShopcar() {
   
      // 1. 发请求--将产品加入到数据库(通知服务器)
      //    服务器存储成功----进行路由跳转
      //    失败------给用户提示
      try {
   
        await this.$store.dispatch("detail/addOrUpdateShopCart", {
   
          skuId: this.$route.params.skuId,
          skuNum: this.skuNum,
        });
        // 成功了进行路由跳转,并将产品的信息带给下一级的路由组件
        // 会话存储 | 本地存储,一般存储的是字符串,所以将对象转换为字符串
        sessionStorage.setItem('SKUINFO',JSON.stringify(this.skuInfo))
        this.$router.push({
   
          name: "addcartsuccess",
          query:{
   skuNum:this.skuNum},
        });
      } catch (error) {
   
        alert(error.message);
      }
    },

本地存储 里面只能存储字符串格式 ,因此需要把对象转换为字符串JSON.stringify()

获取本地存储数据,需要把里面的字符串转换为对象格式JSON.parse() 我们才能使用里面的数据。

获取本地存储数据

在这里插入图片描述

开始渲染页面

   <div class="left-good">
         <div class="left-pic">
            <img :src="skuInfo.skuDefaultImg" />
         </div>
         <div class="right-info">
            <p class="title">{
  { skuInfo.skuName }}</p>
            <p class="attr">
              <span v-for="attrName in skuInfo.skuSaleAttrValueList" :key="attrName.id">{
  { attrName.saleAttrName }} {
  {attrName.saleAttrValueName}}  </span>
              <span>数量:{
  {$route.query.skuNum}}</span>
            </p>
         </div>
       </div>
   <div class="right-gocart">

在这里插入图片描述

购物车静态组件与修改

在这里插入图片描述

  1. 跳转到detail商品详情页,携带参数

     <div class="right-gocart">
              <router-link :to="`/detail/${skuInfo.id}`" class="sui-btn btn-xlarge">查看商品详情</router-link>
              <a href="javascript:">去购物车结算 > </a>
     </div>
    
  2. 跳转到购物车页面ShopCart

九、完成ShopCart购物车模块业务

在这里插入图片描述

  1. 引入和配置路由

    // 配置路由的地方
    import Vue from 'vue';
    import VueRouter from 'vue-router';
    // 使用插件
    Vue.use(VueRouter);
    
    // 引入路由组件
    import ShopCart from '../pages/ShopCart'
    
    // 先把VueRouter原型对象的push,先保存一份
    const originalPush = VueRouter.prototype.push
    const originalReplace = VueRouter.prototype.replace
    
    // 重写push | replace
    // 参数:告诉原来的push方法,你往哪里跳转(传递哪些参数)
    VueRouter.prototype.push = function push(location) {
         
        return originalPush.call(this, location).catch(err => err)
    }
    VueRouter.prototype.replace = function replace(location) {
         
        return originalReplace.call(this, location).catch(err => err)
    }
    
    // 配置路由
    export default new VueRouter({
         
        // 配置路由
        routes: [
            {
         
                name: 'shopcart',
                path: '/shopcart',
                component: ShopCart,
                meta: {
          showFooter: true },
            },
            // 重定向:在项目跑起来的时候,访问/,立马让他定向到首页!!!
            {
         
                path: '*',
                redirect: '/home',
            }
        ],
        // 控制滚动条的滚动行为
        scrollBehavior(to, from, savedPosition) {
         
            // return 期望滚动到哪个的位置
            return {
          y: 0 }; // 始终滚动到顶部
        }
    })
    
  2. 路由跳转

      <div class="right-gocart">
              <router-link :to="`/detail/${skuInfo.id}`" class="sui-btn btn-xlarge">查看商品详情</router-link>
              <router-link to="/shopcart">去购物车结算 > </router-link>
      </div>
    

向服务器发起请求,获取购物车数据

向服务器发请求

/api/cart/cartList GET 无参数

//    src/api/index.js

// 获取购物车列表数据   /api/cart/cartList  GET 无参数
export const reqCartList = ()=>{
   
    return requests({
   url:'/cart/cartList',method:'GET'})
}

操作vuex 将数据存储到仓库中

  1. 新建一个仓库,用来存储购物车的数据
//      src/store/shopcart/index.js

import {
    reqCartList } from '@/api/index'
const state = {
   };
const mutations = {
   };
const actions = {
   };
const getters = {
   };
export default {
   
    namespaced: true,
    state,
    mutations,
    actions,
    getters
}
  1. 在大仓库中引用小仓库
//      src/store/index.js

import Vue from 'vue';
import Vuex from 'vuex';
// 需要使用插件
Vue.use(Vuex);

// 引入小仓库
import home from './home'
import search from './search'
import detail from './detail'
import shopcart from './shopcart';
// 对外暴露Store类的一个实例
export default new Vuex.Store({
   
    // 实现vuex仓库模块式开发存储数据
    modules:{
   
        home,
        search,
        detail,
        shopcart
    }
})
  1. vuex三连环

    const actions = {
         
        // 获取购物车列表的数据
        async getCartList({
           commit }) {
         
            let result = await reqCartList();
            console.log('购物车列表',result);
        },
    };
    
      export default {
         
        name: 'ShopCart',
        mounted(){
         
          // 获取服务器数据
          this.getData();
        },
        methods:{
         
          // 获取个人购物车数据
          getData(){
         
            this.$store.dispatch('shopcart/getCartList');
          }
        }
      }
    

    注意:发请求的时候,获取不到你购物车里的数据,因为这里不知道购物车获取谁的数据,需要给用户加一个身份!所以需要 👉 UUID临时游客身份

    在这里插入图片描述

    在这里插入图片描述

  2. 开始真正的vuex三连环!!

    👇这个是shopcart仓库里面的数据,有点复杂,所以我们要简化

    在这里插入图片描述

    在这里插入图片描述

    import {
          reqCartList } from '@/api/index'
    
    const state = {
         
        cartList:[],
    };
    
    const mutations = {
         
        GETCARTLIST(state, cartList) {
         
            state.cartList = cartList;
        }
    };
    
    const actions = {
         
        // 获取购物车列表的数据
        async getCartList({
           commit }) {
         
            let result = await reqCartList();
            if (result.code == 200) {
         
                commit('GETCARTLIST', result.data); // result.data 是个数组
            }
        },
    };
    
    const getters = {
         
        cartList(state){
         
            // state.cartList[0] 如果没有返回,至少是个数组
            return state.cartList[0]|| [];
        },
    };
    
    export default {
         
        namespaced: true,
        state,
        mutations,
        actions,
        getters
    }
    

    现在仓库里面有了数据

组件获取数据展示数据

...mapGetters("shopcart", ["cartList"]), 组件开始获取数据

遍历用every

<script>
import {
    mapGetters } from "vuex";
export default {
   
  name: "ShopCart",
  mounted() {
   
    // 获取服务器数据
    this.getData();
  },
  methods: {
   
    // 获取个人购物车数据
    getData() {
   
      this.$store.dispatch("shopcart/getCartList");
    },
  },
  computed: {
   
    ...mapGetters("shopcart", ["cartList"]),// 并不是真正的购物车列表数据
    // 真正的购物车列表数据
    cartInfoList() {
   
      // 至少是个空数组
      return this.cartList.cartInfoList || [];
    },
    // 计算购买产品的总价
    totalPrice() {
   
      let sum = 0;
      this.cartInfoList.forEach((item) => {
   
        // item是购物车列表的每一行数据
        sum += item.skuNum * item.cartPrice;
      });
      return sum;
    },
    // 判断底部的复选框是否勾选
    isAllChecked(){
   
      // 遍历每一个产品的isChecked,只要全部元素isChecked属性都为1,返回为真
      return this.cartInfoList.every(item=>item.isChecked==1)
    },
  },
};
</script>

开始渲染数据

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

UUID临时游客身份

在点击 加入购物车 的时候,告诉服务器你是谁

在这里插入图片描述

utils :放一些常用的功能模块,比如正则,uuid

  1. 将游客身份用会话存储(sessionStorage)保存,放到detail仓库里

    uuid是一个随机的字符串,且每次执行不能发生变化,且持久存储,

    所以每次调用getUUID函数的时候,先从本地存储获取uuid,看会话存储是否有,

    如果有的话就返回会话存储里面的uuid,

    如果没有的话,就生成uuid

//      src/utils/uuid_token.js

import {
   v4 as uuidv4} from 'uuid'
// 要生成一个随机的字符串,且每次执行不能发生变化,游客身份持久存储
export const getUUID = ()=>{
   
    // 先从会话存储获取uuid,看一下本地存储是否有
    let uuid_token = sessionStorage.getItem('UUIDTOKEN');
    // 如果没有,我就生成UUID
    if(!uuid_token){
   
        uuid_token=uuidv4();
        // 会话存储 存储一次
        sessionStorage.setItem('UUIDTOKEN',uuid_token);
    }
    // 切记要有返回值!
    return uuid_token;
}

在detail仓库里面存储uuid

//     src/store/detail/index.js

// 封装游客身份模块uuid---生成一个随机的字符串(不能再变了)
import {
   getUUID} from '@/utils/uuid_token'
const state = {
   
    goodsInfo: {
   }, // 看api文档,result.data返回的是一个对象
    // 游客临时身份
    uuid_token:getUUID(),
};

现在游客身份在仓库里,我们要把数据带给服务器,可以利用请求头把数据带给服务器

找到请求拦截器,在请求拦截器捞到仓库里的数据

//   src/api/request.js

// 在当前模块引入store仓库
import store from '@/store'
.....
// 请求拦截器:在发请求之前,请求拦截器可以检测到,可以在请求发出去之前做一些事情
requests.interceptors.request.use((config) => {
   
    // config:配置对象,对象里面有一个属性很重要:headers请求头
    if (store.state.detail.uuid_token) {
   
        // 给请求头添加一个字段(userTempId):和后台老师商量好!
        config.headers.userTempId = store.state.detail.uuid_token
    }

    // 进度条开始动
    nprogress.start();
    return config;
})

在这里插入图片描述

动态展示购物车

修改购物车产品的数量

在这里插入图片描述

点击 + 或 - 或 修改input框里的数字,input框里发生变化

:这个时候向服务器发请求吗?

发请求,如果不发请求的话,服务器里的数据还是原来的,那么该页面的关于数量的数据和原来一样,

-----------所以我们每当修改的时候,就要发请求给服务器,然后再从服务器捞到数据,进行渲染页面

在这里插入图片描述

这个之前写过api(在将产品添加到购物车那里,detail详情页,也有仓库了)所以我们可以把数据存到detail仓库,就现在直接派发action就行了,然后再重新捞数据渲染

这里的skuNum是 现在状态的数字 与 起始状态的数字 的差值。比如:现在商品数量是5,我们要买12,这个skuNum是12-5 = 7

  1. 找到产品数量的结构位置

     <li class="cart-list-con5">
                <a href="javascript:void(0)" class="mins">-</a>
                <!-- 购买的个数 -->
                <input
                  autocomplete="off"
                  type="text"
                  minnum="1"
                  class="itxt"
                  :value="cart.skuNum"
                />
                <a href="javascript:void(0)" class="plus">+</a>
     </li>
    

    这三个节点 要派发同一个action,也就是说这三个节点调用同一个回调函数

    :但是如何判断这三个节点?

    通过传参。三个不同的参数,用形参接收,来区分这三个节点

  2. 要传三个参数

    第一个参数type 是用来区分它们三个节点

    第二个参数是disNum,他们的变化量,+号是1,-号是-1,input框暂定不是变化量,是修改后的值

    第三个参数是cart 当前他们点击的产品的信息cart,然后得知他们的id,因为要发请求需要skuID

      <li class="cart-list-con5">
                <a href="javascript:void(0)" class="mins" @click="handler('mins',-1,cart)">-</a>
                <!-- 购买的个数 -->
                <input
                  autocomplete="off"
                  type="text"
                  minnum="1"
                  class="itxt"
                  :value="cart.skuNum"
                  @change="handler('change',$event.target.value*1,cart)"
                />
                <a href="javascript:void(0)" class="plus" @click="handler('plus',1,cart)">+</a>
      </li>
    
  3. 先写 + 号 和 - 号

    加号:直接带给服务器变化的量

    减号:判断产品的当前数量是否大于1,大于1才能减,传递给服务器-1

    然后就是派发action发请求,发给服务器后再 捞数据 渲染页面

        // 购物车里 修改某一个产品的个数
        handler(type, disNum, cart) {
         
          //disNum 代表 现在状态的数字 与 起始状态的数字 的差值
          // 目前disNum 形参: + 号变化量(1),- 号 变化量 (-1),input 最终的量(并不是变化量)
          // 向服务器发请求,修改数量
          switch (type) {
         
            // 加号
            case "plus": {
         
              // 带给服务器变化的量
  • 10
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值