黑马优购项目讲解

黑马优购项目讲解

首先在全局app.json配置一下项目需要的页面和底部tabBar

 "pages": [ 
    "pages/index/index",
    "pages/category/index", 
    "pages/goods_list/index",
    "pages/goods_detail/index", 
    "pages/cart/index",
    "pages/collect/index",
    "pages/order/index",
    "pages/search/index",
    "pages/user/index",
    "pages/feedback/index",
    "pages/login/index",
    "pages/auth/index",
    "pages/pay/index"
  ],

底部tabBar

"tabBar": {
    "color": "#999",
    "selectedColor": "#ff2d4a",
    "backgroundColor": "#fafafa",
    "position": "bottom",
    "borderStyle": "black",
    "list": [
      {
        "pagePath": "pages/index/index",
        "text": "首页",
        "iconPath": "icons/home.png",
        "selectedIconPath": "icons/home-o.png"
      },
      {
        "pagePath": "pages/category/index",
        "text": "分类",
        "iconPath": "icons/category.png",
        "selectedIconPath": "icons/category-o.png"
      }
      ,
      {
        "pagePath": "pages/cart/index",
        "text": "购物车",
        "iconPath": "icons/cart.png",
        "selectedIconPath": "icons/cart-o.png"
      }
      ,
      {
        "pagePath": "pages/user/index",
        "text": "我的",
        "iconPath": "icons/my.png",
        "selectedIconPath": "icons/my-o.png"
      }
    ]
  },

接下来是首页的基本布局,顶部搜索框,轮播图、九宫格布局、楼层布局
在这里插入图片描述
对搜索框进行拆分,方便复用
首先创建一个components文件夹用来存储拆分的子组件
在这里插入图片描述
在子组件的json文件中引入微信小程序自带的轮播图组件

{
  "usingComponents": {
    "mp-searchbar": "weui-miniprogram/searchbar/searchbar"
  },
  "component":true
}

在页面上直接使用

  <mp-searchbar bindselectresult="selectResult" search="{{search}}" bindtap="focus" cancel='{{false}}'></mp-searchbar>

在父组件的json文件中注册一下子组件

{
  "usingComponents": {
    "search":"/components/search/index"
  }
}

然后在父组件中直接当作普通标签使用

<search></search>

请求轮播图的数据,将原生的请求方式修改为promise的方式
在这里插入图片描述
在需要用到的页面的js文件中的最上方引入封装好的方法

import { request } from "../../request/index.js";

再对数据进行获取

 // 获取轮播图数据
  getSwiperList(){
    request({ url: "/home/swiperdata" })
    .then(result => {
      this.setData({
        swiperList: result
      })
    })
  },

最后使用小程序自带的轮播图组件将图片渲染上去就好了

然后是分类页面

我们先将数据和页面的关系梳理清楚
在这里插入图片描述
在获取数据的时候,我们将左侧和右侧的数据分别取出来

    // 1 使用es7的async await来发送请求
    const res = await request({ url: "/categories" });
    this.Cates = res;
    // 把接口的数据存入到本地存储中
    wx.setStorageSync("cates", { time: Date.now(), data: this.Cates });
    // 构造左侧的大菜单数据
    let leftMenuList = this.Cates.map(v => v.cat_name);
    console.log(leftMenuList)
    // 构造右侧的商品数据
    let rightContent = this.Cates[0].children;
    this.setData({
      leftMenuList,
      rightContent
    })
  },

然后给左侧的菜单添加点击事件,通过索引找到右侧相应的数据进行渲染就可以了

 handleItemTap(e) {
    /* 
    1 获取被点击的标题身上的索引
    2 给data中的currentIndex赋值就可以了
    3 根据不同的索引来渲染右侧的商品内容
     */
    const { index } = e.currentTarget.dataset;

    let rightContent = this.Cates[index].children;
    this.setData({
      currentIndex: index,
      rightContent,
    })

  }

点击右侧商品跳转到匹配的商品列表
点击的时候将该商品的id传过去

	<view class="goods_list">
       <navigator
          wx:for="{{item1.children}}"
          wx:for-index="index2"
          wx:for-item="item2"
          wx:key="cat_id"
          url="/pages/goods_list/index?cid={{item2.cat_id}}"
          >
          <image mode="widthFix" src="{{item2.cat_icon}}"></image>
          <view class="goods_name">{{item2.cat_name}}</view>
       </navigator>
    </view>

获取商品列表数据的时候将需要用到的id,pagesize等参数带进去

  // 获取商品列表数据
  async getGoodsList(){
    const res=await request({url:"/goods/search",data:this.QueryParams});
    // 获取 总条数
    const total=res.total;
    // 计算总页数
    this.totalPages=Math.ceil(total/this.QueryParams.pagesize);
    // console.log(this.totalPages);
    this.setData({
      // 拼接了数组
      goodsList:[...this.data.goodsList,...res.goods]
    })
  },

1.用户上滑页面 滚动条触底 开始加载下一页数据, 找到滚动条触底事件 微信小程序官方开发文档寻找
2.判断还有没有下一页数据, 获取到总页数 只有总条数
总页数 = Math.ceil(总条数 / 页容量 pagesize)
总页数 = Math.ceil( 23 / 10 ) = 3,
获取到当前的页码 pagenum,
判断一下 当前的页码是否大于等于 总页数
表示 没有下一页数据
3 假如没有下一页数据 弹出一个提示
4 假如还有下一页数据 来加载下一页数据
当前的页码 ++
重新发送请求
数据请求回来 要对data中的数组 进行 拼接 而不是全部替换!!!

  onReachBottom(){
  //  1 判断还有没有下一页数据
    if(this.QueryParams.pagenum>=this.totalPages){
      wx.showToast({ title: '没有下一页数据' });
    }else{
      this.QueryParams.pagenum++;
      this.getGoodsList();
    }
  },

下拉刷新页面
1 触发下拉刷新事件 需要在页面的json文件中开启一个配置项
找到 触发下拉刷新的事件
2 重置 数据 数组
3 重置页码 设置为1
4 重新发送请求
5 数据请求回来 需要手动的关闭 等待效果

  // 下拉刷新事件 
  onPullDownRefresh(){
    // 1 重置数组
    this.setData({
      goodsList:[]
    })
    // 2 重置页码
    this.QueryParams.pagenum=1;
    // 3 发送请求
    this.getGoodsList();
  }
})

点击商品列表中某一条数据的时候,将id传过去,通过id查找到对应的商品详情数据

url="/pages/goods_detail/index?goods_id={{item.goods_id}}"

获取详情页面的数据信息

// 获取商品详情数据
  async getGoodsDetail(goods_id) {
    const goodsObj = await request({ url: "/goods/detail", data: { goods_id } });
    this.GoodsInfo = goodsObj;
    // 1 获取缓存中的商品收藏的数组
    let collect = wx.getStorageSync("collect") || [];
    // 2 判断当前商品是否被收藏
    let isCollect = collect.some(v => v.goods_id === this.GoodsInfo.goods_id);
    this.setData({
      goodsObj: {
        goods_name: goodsObj.goods_name,
        goods_price: goodsObj.goods_price,
        // iphone部分手机 不识别 webp图片格式 
        // 最好找到后台 让他进行修改 
        // 临时自己改 确保后台存在 1.webp => 1.jpg 
        goods_introduce: goodsObj.goods_introduce.replace(/\.webp/g, '.jpg'),
        pics: goodsObj.pics
      },
      isCollect
    })
  },

然后对详情页面的数据进行渲染和布局
在这里插入图片描述
当用户点击加入购物车的时候,先绑定点击事件,获取缓存中的购物车数据,然后判断当前商品是否已经存在购物车,已经存在的话,修改商品数据,执行商品数量++,重新把购物车数组填充回缓存中,不存在的话,直接给购物车数组添加一个新元素,带上数量num属性,重新把购物车数组填充回缓存中,最后弹出添加成功的提示框

// 点击 加入购物车
  handleCartAdd() {
    // 1 获取缓存中的购物车 数组
    let cart = wx.getStorageSync("cart") || [];
    // 2 判断 商品对象是否存在于购物车数组中
    let index = cart.findIndex(v => v.goods_id === this.GoodsInfo.goods_id);
    if (index === -1) {
      //3  不存在 第一次添加
      this.GoodsInfo.num = 1;
      this.GoodsInfo.checked = true;
      cart.push(this.GoodsInfo);
    } else {
      // 4 已经存在购物车数据 执行 num++
      cart[index].num++;
    }
    // 5 把购物车重新添加回缓存中
    wx.setStorageSync("cart", cart);
    // 6 弹窗提示
    wx.showToast({
      title: '加入成功',
      icon: 'success',
      // true 防止用户 手抖 疯狂点击按钮 
      mask: true
    });

当用户点击收藏的时候,先加载缓存中商品收藏的数据,判断当前商品是否被缓存,如果有,把该商品从缓存中删除,并将页面收藏的图标改为false,反之一样。

 // 点击 商品收藏图标
  handleCollect(){
    let isCollect=false;
    // 1 获取缓存中的商品收藏数组
    let collect=wx.getStorageSync("collect")||[];
    // 2 判断该商品是否被收藏过
    let index=collect.findIndex(v=>v.goods_id===this.GoodsInfo.goods_id);
    // 3 当index!=-1表示 已经收藏过 
    if(index!==-1){
      // 能找到 已经收藏过了  在数组中删除该商品
      collect.splice(index,1);
      isCollect=false;
      wx.showToast({
        title: '取消成功',
        icon: 'success',
        mask: true
      });
        
    }else{
      // 没有收藏过
      collect.push(this.GoodsInfo);
      isCollect=true;
      wx.showToast({
        title: '收藏成功',
        icon: 'success',
        mask: true
      });
    }
    // 4 把数组存入到缓存中
    wx.setStorageSync("collect", collect);
    // 5 修改data中的属性  isCollect
    this.setData({
      isCollect
    })
  }

给购物车页面的获取收货地址绑定点击事件,用户点击按钮的时候调用小程序内置 api 获取用户的收货地址 wx.chooseAddress,最后将获取到的地址缓存到本地存储中

// 选择收货地址
async chooseAddress() {
  const res = await wepy.chooseAddress().catch(err => err)

  if (res.errMsg !== 'chooseAddress:ok') {
    return
  }

  this.addressInfo = res
  wepy.setStorageSync('address', res)
  this.$apply()
}

购物车页面渲染,先获取到本地存储中的数据,手动添加选中的状态,和初始数量
全选和反选
1 全选复选框绑定事件 change
2 获取 data中的全选变量 allChecked
3 直接取反 allChecked=!allChecked
4 遍历购物车数组 让里面 商品 选中状态跟随 allChecked 改变而改变
5 把购物车数组 和 allChecked 重新设置回data 把购物车重新设置回 缓存中

 handeItemChange(e) {
    // 1 获取被修改的商品的id
    const goods_id = e.currentTarget.dataset.id;
    // 2 获取购物车数组 
    let { cart } = this.data;
    // 3 找到被修改的商品对象
    let index = cart.findIndex(v => v.goods_id === goods_id);
    // 4 选中状态取反
    cart[index].checked = !cart[index].checked;

    this.setCart(cart);

  },

全选的实现 数据的展示, 获取缓存中的购物车数组,根据购物车中的商品数据 所有的商品都被选中 checked=true 全选就被选中

handleItemAllCheck() {
    // 1 获取data中的数据
    let { cart, allChecked } = this.data;
    // 2 修改值
    allChecked = !allChecked;
    // 3 循环修改cart数组 中的商品选中状态
    cart.forEach(v => v.checked = allChecked);
    // 4 把修改后的值 填充回data或者缓存中
    this.setCart(cart);
  },

商品数量的编辑
“+” “-” 按钮 绑定同一个点击事件 区分的关键 自定义属性
1 “+” “+1”
2 “-” “-1”
1 传递被点击的商品id goods_id
2 获取data中的购物车数组 来获取需要被修改的商品对象
3 当 购物车的数量 =1 同时 用户 点击 “-”
弹窗提示(showModal) 询问用户 是否要删除
1 确定 直接执行删除
2 取消 什么都不做
4 直接修改商品对象的数量 num
5 把cart数组 重新设置回 缓存中 和data中 this.setCart

 async handleItemNumEdit(e) {


    // 1 获取传递过来的参数 
    const { operation, id } = e.currentTarget.dataset;
    // 2 获取购物车数组
    let { cart } = this.data;
    // 3 找到需要修改的商品的索引
    const index = cart.findIndex(v => v.goods_id === id);
    // 4 判断是否要执行删除
    if (cart[index].num === 1 && operation === -1) {
      // 4.1 弹窗提示
      const res = await showModal({ content: "您是否要删除?" });
      if (res.confirm) {
        cart.splice(index, 1);
        this.setCart(cart);
      }
    } else {
      // 4  进行修改数量
      cart[index].num += operation;
      // 5 设置回缓存和data中
      this.setCart(cart);
    }
  },

点击结算
1 判断有没有收货地址信息
2 判断用户有没有选购商品
3 经过以上的验证 跳转到 支付页面!

  // 点击 结算 
  async handlePay(){
    // 1 判断收货地址
    const {address,totalNum}=this.data;
    if(!address.userName){
      await showToast({title:"您还没有选择收货地址"});
      return;
    }
    // 2 判断用户有没有选购商品
    if(totalNum===0){
      await showToast({title:"您还没有选购商品"});
      return ;
    }
    // 3 跳转到 支付页面
    wx.navigateTo({
      url: '/pages/pay/index'
    });
      
  }
})

支付按钮
1 先判断缓存中有没有token
2 没有 跳转到授权页面 进行获取token
3 有token 。。。
4 创建订单 获取订单编号
5 已经完成了微信支付
6 手动删除缓存中 已经被选中了的商品
7 删除后的购物车数据 填充回缓存
8 再跳转页面

async handleOrderPay() {
    try {

      // 1 判断缓存中有没有token 
      const token = wx.getStorageSync("token");
      // 2 判断
      if (!token) {
        wx.navigateTo({
          url: '/pages/auth/index'
        });
        return;
      }
      // 3 创建订单
      // 3.1 准备 请求头参数
      // const header = { Authorization: token };
      // 3.2 准备 请求体参数
      const order_price = this.data.totalPrice;
      const consignee_addr = this.data.address.all;
      const cart = this.data.cart;
      let goods = [];
      cart.forEach(v => goods.push({
        goods_id: v.goods_id,
        goods_number: v.num,
        goods_price: v.goods_price
      }))
      const orderParams = { order_price, consignee_addr, goods };
      // 4 准备发送请求 创建订单 获取订单编号
      const { order_number } = await request({ url: "/my/orders/create", method: "POST", data: orderParams });
      // 5 发起 预支付接口
      const { pay } = await request({ url: "/my/orders/req_unifiedorder", method: "POST", data: { order_number } });
      console.log(pay);
      // 6 发起微信支付 
      await requestPayment(pay);
      // 7 查询后台 订单状态
      const res = await request({ url: "/my/orders/chkOrder", method: "POST", data: { order_number } });
      await showToast({ title: "支付成功" });
      // 8 手动删除缓存中 已经支付了的商品
      let newCart=wx.getStorageSync("cart");
      newCart=newCart.filter(v=>!v.checked);
      wx.setStorageSync("cart", newCart);
        
      // 8 支付成功了 跳转到订单页面
      wx.navigateTo({
        url: '/pages/order/index'
      });
        
    } catch (error) {
      await showToast({ title: "支付失败" })
      console.log(error);
    }
  }

通过给点击按钮设置open-type属性,值为getUserInfo,配合bindgetuserinfo来获取用户信息
在这里插入图片描述
通过点击获取到用户信息,然后存到本地存储中,最后再通过wx.navigateBack跳转到上一页在这里插入图片描述
用户信息打印在这里插入图片描述
最后将用户的头像渲染到页面上,进行简单的布局

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值