11-小程序(购物车页面,深度监听购物车数据变化让本地也跟着变化,数组reduce方法算总价总数量,计算属性弄全选状态,数组方法集合)

01.购物车-页面分析

  1. 入口: 点击底部tab菜单购物车时显示购物车页面;商详点击购物车跳转购物车页面
  2. 主要模块
    1. 商品列表
      1. 每一个商品包括选中状态,商品图片,商品名称,商品单价,商品数量
    2. 全选,总价,总数量
  3. 其他说明
    1. 收货地址放在支付页面
    2. 商品列表每一项目可以调整选中状态及数量
    3. 点击结算跳转到支付

02.购物车数据存哪里?(补充 )

  1. 描述:购物车的数据的改变是发请求还是存本地,还是存Vuex?发请求即可

  2. 对比以上三个方案

    1. 购物车添加商品,刷新页面数据依然在

      1. vuex刷新后就没有
    2. 手机端添加购物车,PC端可以看到添加的商品

      1. 只存本地也不行
    3. 登录前加入购物车,登录后商品在

在这里插入图片描述

注意点:
  1. 实际项目中请求一般在100ms以内

03.购物车-静态页面

  1. copy
  2. iconfont引入
    1. 找到icon,加入购物车,生成新的.css文件
    2. copy内容更新项目里面iconfont.css
    3. 在cart页面使用iconfont

04.商详跳转购物车

  1. 商详购物车点击@click: toCart
  2. 跳转逻辑uni.switchTab
    在这里插入图片描述

05.购物车-接口分析

  1. url : https://www.uinav.com/api/public/v1/goods/goodslist?goods_ids=140,395,291

  2. 参数id以逗号分隔

  3. 返回数据

    [
        {
            商品id,
            商品名称,
            商品价格
            商品图片
        }
    ]
    

问题:

  1. 那商品列表里面第一个商品的勾选状态和数量来自哪里呢?
  2. 参数里面goods_ids从哪里来呢?

06.购物车数据结构

商品勾选状态,数量还有goodsId存storage

那么storage购物车的数据结构是什么样的?

  1. 数组
    1. 取值比较麻烦
    2. 有序的
  2. 对象
    1. 取值比较方便
//数组
[
    {
        goodsId:542
        num:99,
        checked:true
        
    },
    ....
]

//对象
{
    542:{
        num:99,
        checked:true
    },
    291:{
        num:88,
        checked:false 
    }
}

07.商详加入购物车

点击商详加入购物车按钮加入购物车

1. 点击@click: addCart
  1. 商品加入购物车
    ​ 1. 把当前商品存储到storage里面
    ​ 1. goodsId就是当前商品的id
    ​ 2. num: 第一次为1,后续++
    ​ 3. checked始终为true
    ​ 2. 步骤
    ​ 1. 取storage
    ​ 2. 更新
    ​ 3. 存storage
注意点:
  1. 商品加入购物车,如果在购物车中去勾选,再添加也勾选状态
  2. 如何区分是第一次,还是非第一次?
    1. 对象 cart[542]
    2. 数组find
      在这里插入图片描述

08.购物车-非首次添加优化

  1. 添加成功购物车提示用户

  2. 非首次添加,商品移到数组最前面
    在这里插入图片描述

  3. findIndx的使用

在这里插入图片描述

注意点:
  1. git stash储藏,相当于是游戏存档

    git stash -u  #保存当前工作区代码,-u包括新增文件
    git stash pop #弹出最近一次的储藏
    

09.购物车-基本渲染

  1. 发请求

    1. 请求参数:取storage cart数组里面每一项的goodsId以逗号分隔拼成字符串

      1. forEach

      2. 方案2,返回一个goodsId的数组,然后join

        let goodsIdArr = cart.map(item=>{
            return item.goodsId
        })
        let ids = goodsIdArr.join(',')
        
    2. 什么时机发请求??

      1. onShow
        1. tabbar页面,后续不会再执行onLoad
      2. 方法名:queryGoodsList
    3. 拿到请求数据,设置给data属性goodsList

    4. 在结构中vfor渲染

10.购物车-渲染选中状态及数量

接口返回的数组并不是按传参goodsId的顺序

  1. 问题:

    1. 应该以cart为主,遍历
    2. 数量渲染:去goodslist里面找一项goodsId为当goodsid相等的那一项的商品名称。在结构写不了
  2. 解决方案

    1. 在请求结束后,把storage cart和goodsList融合在一起,以cart为主,返回一个新的属性

      this.goodsList = this.cart.map(cartItem => {
          // 到_goodsList里面找一项goodsId相等的,组成新的对象
          let targetGoods = _goodsList.find(goodsItem => {
              return goodsItem.goods_id === cartItem.goodsId;
          });
          return {...targetGoods, ...cartItem};
      });
      
    2. 渲染

注意点:
  1. cart添加为this的属性,相当于是全局变量

11.购物车-商品勾选与不勾选

  1. 商品列表的每一项点击时,checked状态取反
    1. 点击@click = toggleCheck
toggleCheck(item){
    item.checked = !item.checked
},

12.购物车-商品跳转商详

点击商品(不包括勾选,还有数量±按钮)跳转商详

  1. 点击@click= toItem
  2. toItem,跳转传参goodsId

补充:

  1. 不包括勾选,还有数量±按钮需要事件阻止冒泡
    1. .stop
  2. uniapp里面navigator跳转用绝对路径

13.购物车-商品数量

  1. 点击+,数量++

    1. 点击@click.stop: addNum
  2. 点击-,数量–

    1. 点击@click.stop: subNum
  3. 如果为1,提示删除goodsList

    this.goodsList.splice(从哪一项开始删除,删除多少项)
    

14.购物车-全选状态

  1. 所有商品都选中,全选就勾选
    1. 计算属性isAll
    2. 如何判断所有商品都选中呢?
      1. 1.选中的商品数量和数组总长度相等
      2. 2.如果有一个不选中,那么false
      3. 3.所有项都满足指定条件就返回true, 数组方法every
isAll() {
    // 所有商品都选中
    //1.选中的商品数量和数组总长度相等
    // let sum =0
    // this.goodsList.forEach(item=>{
    // 	if(item.checked){
    // 		sum++
    // 	}
    // })
    // return sum ===this.goodsList.length

    //2.如果有一个不选中,那么false
    // for (let item of this.goodsList) {
    // 	if (!item.checked) {
    // 		return false;
    // 	}
    // }
    // return true

    // 3.所有项都满足指定条件就返回true
    return this.goodsList.every(item=>{
        return item.checked
    })
}

15.购物车-全选点击

  1. 点击全选,全选状态切换, 勾选/不勾选

    1. 点击@click: toggleAll

    2. 在isAll的计算属性里面把isAll改变后的值,设置给它的依赖(goodsList每一项的checked)

      set(status){
          // 把isAll改变状态和每个商品状态同步
          this.goodsList.forEach(item=>{
              item.checked= status
          })
      }
      

16.购物车-总价与总数量

  1. 总数量是选中的商品数量之和

    1. 计算属性totalNum

    2. 如何计算

      1. reduce
      return this.goodsList.reduce((sum,item)=>{
          return sum+(item.checked?item.num:0)
      },0)
      
  2. 总价:选中的商品数量*商品价格之和

    1. 计算属性totalPrice
    2. 如何计算
      1. reduce

17.购物车-状态存storage

  1. 现象:在界面上改变(勾选的状态,数量改变),data属性goodsList改变,但并没有改变storage.重新编译后,界面状态没有了。
  2. 解决方案:界面的改变应该同时存到storage
    1. isAll点击,商品勾选点击,数量++,数量–,商品删除都需要更新到storage
    2. watch goodsList即可
// isAll点击,商品勾选点击,数量++,数量--会改变goodsList
goodsList:{
    handler(){
        console.log(this.goodsList)
        // 不用从storage取,然后存. 因为goodsList已经有存到storage cart里面所有的数据
        let cart = this.goodsList.map(item=>{
            return{
                goodsId:item.goodsId,
                num:item.num,
                checked:item.checked
            }
        })
        // 设置到storage
        uni.setStorageSync('cart',cart)
    },
        deep:true
}
注意点:
  1. 深度监听
  2. goodsList已经有构造cart的所有的数据,所有没必要取cart

Array的方法总结

  1. find

    1. 概念:在数组里面找一项符合条件的元素
    2. 如何作用的:遍历数组,对每一项执行指定函数,如果为ture,返回这一项,并中断遍历;如果一直没找到,返回undefined
  2. findIndex

    1. 概念:在数组里面找一项符合条件的元素的下标
  3. forEach

    1. 遍历数组
    2. 注意点:
      1. 不能中断遍历,而且不能修改元素
  4. map

    1. 概念:一般用来返回一个新的数组,新数组和原数组结构不一样
    2. 如何作用的:返回新数组,遍历原数组,每一项执行指定函数,返回值作为新数组的项
  5. for …of

    1. 遍历
    2. for(let item of arr), item是指元素并不是指下标。遍历可以叫断
  6. every

    1. 遍历数组,每一项执行指定函数,所有结果为true,就返回true
  7. some

    1. 遍历数组,每一项执行指定函数,只要有一项结果为true,就返回true
  8. reduce

    1. 如何作用
      1. 第一遍历时,中间变量被第2个参数赋值
      2. 中间变量和元素的计算都会赋值给中间变量
      3. 遍历结束后,reduce返回中间变量
    2. 应用场景:累加,和阶乘
    数组.reduce((中间变量,元素)=>{
    	return 中间变量和元素的计算
    },中间变量的初始值)
    
  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我可以帮你解答这个问题。 首先,我们可以定义一个数组来包含产品的名称、单价和购买数量,如下所示: ```javascript let products = [ { name: 'Product A', price: 10, quantity: 2 }, { name: 'Product B', price: 5, quantity: 3 }, { name: 'Product C', price: 8, quantity: 1 } ]; ``` 接下来,我们可以使用计算属性来计购物车中产品的总价格,代码如下: ```javascript computed: { totalPrice() { return this.products.reduce((total, product) => { return total + product.price * product.quantity; }, 0); } } ``` 在上面的代码中,我们使用了数组的 `reduce` 方法来计总价格。 最后,我们可以使用侦听器来监听购买数量变化,并重新计总价格,代码如下: ```javascript watch: { 'products': { handler: function() { this.totalPrice = this.products.reduce((total, product) => { return total + product.price * product.quantity; }, 0); }, deep: true } } ``` 在上面的代码中,我们使用了侦听器来监听 `products` 数组变化,并在数组发生变化时重新计总价格。 整个示例代码如下所示: ```javascript <template> <div> <ul> <li v-for="(product, index) in products" :key="index"> {{ product.name }} - {{ product.price }} - {{ product.quantity }} <button @click="product.quantity++">+</button> <button @click="product.quantity--">-</button> </li> </ul> <div>Total Price: {{ totalPrice }}</div> </div> </template> <script> export default { data() { return { products: [ { name: 'Product A', price: 10, quantity: 2 }, { name: 'Product B', price: 5, quantity: 3 }, { name: 'Product C', price: 8, quantity: 1 } ], totalPrice: 0 }; }, mounted() { this.totalPrice = this.products.reduce((total, product) => { return total + product.price * product.quantity; }, 0); }, computed: { totalPrice() { return this.products.reduce((total, product) => { return total + product.price * product.quantity; }, 0); } }, watch: { 'products': { handler: function() { this.totalPrice = this.products.reduce((total, product) => { return total + product.price * product.quantity; }, 0); }, deep: true } } }; </script> ``` 希望这个示例能够帮助你解决问题。如果你有任何疑问,可以随时向我提问。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值