优购商城项目 详细步骤流程

优购商城项目 详细步骤流程

一、准备的工作

1.文档

  1. 写项目之前必须要有接口文档 准备工作接口文档是必不可少的
  2. 参考文档我们还可以参考 小程序的开发文档、阿里巴巴字体 iconfont 、mdn…

2.项目的搭建

1.搭建项目目录的结构 相当于分模块的去放我们需要的文件 使项目的结构可以清晰明了
在这里插入图片描述
2.然后就是分析页面 搭建项目基本项目的页面 (有语义化的 名字可以很方便我们后期的维护 习惯的养成)

{
    
    
  "pages": [    //项目页面的路由信息
    "pages/index/index",
    "pages/category/index",
  ]}

引入项目中需要的字体图标库 并且可以保证全局引入 这样才可以在所有的页面使用


 - 打开阿⾥巴巴字体图标 ⽹站

     . 选择的图标 
     . 添加⾄项⽬ 
     . 下载到本地 
     . 将样式⽂件 由 css 修改为 wxss 
     . 在app.wxss⼩程序中引⼊ 

在这里插入图片描述
页面使用图标 对应的图标名称
在这里插入图片描述

3.项目的搭建

在这里插入图片描述

4.搭建项目的tabber 结构 参考 小程序 API 文档

5.请求数据的接口进行封装 这样就可以 不必要的重复的代码 http文件去封装

(图)具体封装的步骤

三个部分:
0ne:api.js ------------放接口地址集合 统一的整体的来管理

  • module.exports={}导出 有多个地址 对象的形式导出
    在这里插入图片描述

two:fach.js ----------------封装微信 网络请求模块 导出一个promis 实例对象 会接收三个形参 (url,data,method)
分别是 请求的路径、请求数据的参数、请求数据的方法
promis对象中的(resolve, reject) 分别代表成功和失败之后执行的回调函数

  • 导出一个 Promise 对象实例 里面封装接口请求的方法用来重复使用
    在这里插入图片描述

三、http.js --------- 封装请求的方法 首先需要 引入 fach.js 和 api.js 这样才可以进行完美的封装

  • 为了减少重复 无用的代码 可设置基本路径的地址 baseUrl
    接口的理解 api ---- 接口 h8------ 版本号

let baseUrl = “https://api-hmugo-web.itheima.net/api/public/v1”

在这里插入图片描述

然后就是定义函数 分别请求对应的接口

需要值得注意的是 必须要在全局的app.js 中 全局的引入http 并且 全局的导出 这样在需要的页面 引入 才可以使用它获取
到数据 否则就会报错

到这里 差不多项目的基本准备工作就差不多真被完毕了 接下来就是 分析 各个页面之间的联系 并且 对组件进行拆分和封装

二、单个页面的逻辑 组件的拆分

1.首页页面

是我们看到的home 首页 搜索、轮播图、导航、和楼层都可以进行封装
子组件我们注册在 components 中
另外可以根据页面 json 中的

 {
    
    
  "component": true,   //来判断当前组件是否是子组件
  "usingComponents": {
    
    }
} 

我们在home 父组件页面 请求到轮播图的数据 首先 在api.js 中定义好 轮播图数据的路径
然后在http.js 中 请求数据 接口不需要参数的话就 不写参数 为空 请求的方法为get 统一导出后 在 父组件
home.js 中 我们要全局的引入我们封装的请求方法

* 生命周期函数--监听页面加载  的时候请求数据
  onLoad: function (options) {
    
    
    // 请求轮播图数据
    // /home/swiperdata
    app.http.banner().then(res => {
    
    
      // console.log(res)

数据保存到data中  
      this.setData({
    
    
        banner: res.data.message
      })
    })

并且需要我们传递给子组件

<!-- 轮播图的组件 -->
<w-swiper list="{
    
    {
    
    banner}}"></w-swiper>
<!-- 轮播图的组件 -->

使用自定义属性的方法
在子组件js来接收数据

properties:{
    
    
list:{
    
    
type:Array 
}
}

接收数据 并且可以 定义数据类型 和默认数据

然后在页面中渲染我们接受到的数据

 <swiper autoplay="true" indicator-dots="true" indicator-color="pink" class="tops-s">  
  <block wx:for="{
    
    {
    
    list}}" wx:key="index">
  <swiper-item>
      <image src="{
    
    {
    
    item.image_src}}"></image>
  </swiper-item>
</block>
</swiper> 

可以参考 小程序API 文档来对
来实现轮播图的效果 导航部分 和 楼层部分也是一样的流程 父传子 只需要
对页面进行css的样式进行修改

2.分类页面

首先一眼页面是分为左右两部分 右边是侧边导航 左边是数据的渲染 也是一个二级导航的效果 首先根据接口 请求到数据

数据拿到之后进分析 只有对数据最够 明白才能让我们更快更好的的完成页面
这边 拿到的数据是 先渲染左边的侧边导航栏 然后我们给侧边导航地每一项一个点击事件 change

  <view class="lefts" wx:for="{
    
    {
    
    srot}}" wx:key="index">
  <view  bindtap="change" data-index="{
    
    {
    
    index}}">
    {
    
    {
    
    item.cat_name}}
  </view>
</view>

并且使用自定义属性 data-index="{ {index}}" 把他的下标传递过去
在js 页面

  // 方法
  change(e) {
    
    
    // 保存点击的下标    ---
    this.setData({
    
    
      i: e.currentTarget.dataset.index
    });
    // 根据 保持的·下标来获取右边的数据
    this.setData({
    
    
      tabs: this.data.srot[this.data.i].children
    })
    // tabs:this.data.srot[this.data.i].children[0].children
    // console.log(this.data.tabs);

},
通过e 事件源 来保存下来 我们点击的每一项数据的下标

然后 把符合当前下标的数据 的children 中的数据保存下来 这样就可以实现 点击左边的哪一项 切换到哪一项的数据 了,因为
拿到的数据结构就是 每一下项数据里面都有自己的children 右边展示的也是根据左边的数据而展示他的children的

3.列表页面

<!-- 右边的部分图 -->
<view class="con" wx:for="{
    
    {
    
    item.children}}" 
wx:key="index"   data-cid="{
    
    {
    
    item.cat_id}}" bindtap="gotolist">

```css
  <data-cid="{
    
    {
    
    item.cat_id}}" 自定义属性 保存 一下需要的cid

给每一项的数据一个点击事件 然后 同样保存 代表每一项的cat_id 并给每一项一个点击事件 gotolist

  // 点击跳转
  gotolist(e) {
    
    
    // console.log(e)
    // 保存 自己定义的属性 从事件源里获取  
    let cid = e.currentTarget.dataset.cid;
    // 页面跳转 把保存 的 cid 参数到另一个页面 使用 
    wx.navigateTo({
    
    
      url:'/pages/goods_list/goods_list?cid=' + cid,
    })
  },  

在页面跳转的时候 吧 保存来的 cat_cid 保存下来 并且 使用 字符串拼接的形式 传递参数 到 列表页面

通过(options) 吧参数保存下来 然后在请求 页面数据的时候 携带参数 这样才可以 获取到 数据 最后进行数据的渲染即可

  /**
   * 生命周期函数--监听页面加载
   */
  // options 获取 需要接受的数据  
  onLoad: function (options) {
    
    
    console.log(options)
    // 保存一下动态的cid
    this.Paramsztt.cid = options.cid;
    // console.log(options);
    // 请求到的数据    参数信息------必须按照接口来写    {
    
    参数的位置 不需要参数默认是空 需要的话是对象形式的传递参数 }
    // pagenum ---请求到的页码    pagesize---请求到的每页多少条数据
    // 保存下餐数信息

    // 请求接口里的数据  
    app.http.shoplist(this.Paramsztt).then(res => {
    
    
      console.log(options)
      // 获取 总条数
      const total = res.data.message.total;
      console.log(total)

      // 计算总页数
      this.data.totalPages = Math.ceil(total / this.Paramsztt.pagesize);
      console.log(total);
      console.log(this.Paramsztt.pagesize);
      console.log(this.data.totalPages)
      // 拼接了数组
      // this.setData({
    
    
      //   // shoplist: [...this.data.shoplist, ...res.goods]
      // })
      this.setData({
    
    
        // 保存获取到的数据 哈哈哈哈
        shoplist: res.data.message.goods
      })
    })
  },

下拉刷新

/**
   * 页面相关事件处理函数--监听用户下拉动作
   */
  // 下拉的事件
  onPullDownRefresh() {
    
    

  
    // 1 重置数组
    this.setData({
    
    
      shoplist: []
    }),
      // 2 重置页码
      this.Paramsztt.pagenum = 1;
    // 3 发送请求

    // 请求接口里的数据  
    app.http.shoplist(this.Paramsztt).then(res => {
    
    
      // console.log(options)
      // 获取 总条数
      const total = res.data.message.total;
      console.log(total)

      // 计算总页数
      this.data.totalPages = Math.ceil(total / this.Paramsztt.pagesize);
      console.log(total);
      console.log(res)
      console.log(this.Paramsztt.pagesize);
      console.log(this.data.totalPages)
      // 拼接了数组
      // this.setData({
    
    
      //   shoplist: [...this.data.shoplist,]
      // }),
        this.setData({
    
    
          // 保存获取到的数据 哈哈哈哈
          shoplist: res.data.message.goods
          // 需要来拼接的数据
        })
        // 
    })
    wx.stopPullDownRefresh()
    // this.getGoodsList();
  },

///下拉 数据 重新的返回第一页数据

 /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom: function () {
    
    
    // 先判断还有几页数据
    // 如果当前的页面大于总条数
    if (this.Paramsztt.pagenum >= this.totalPages) {
    
    
      // 就显示没有下一页的数据
      wx.showToast({
    
    
        title: '没有下一页了',
      })

    } else {
    
    
      // 还有下一页数据
      
      this.Paramsztt.pagenum++;

    // 请求接口里的数据  
    app.http.shoplist(this.Paramsztt).then(res => {
    
    
      // console.log(options)
      // 获取 总条数
      const total = res.data.message.total;
      console.log(total)

      // 计算总页数
      this.data.totalPages = Math.ceil(total / this.Paramsztt.pagesize);
      // console.log(total);
      console.log(res)
      // console.log(this.Paramsztt.pagesize);
      // console.log(this.data.totalPages)
      // 拼接了数组
      // this.setData({
    
    
      //   shoplist: [...this.data.shoplist,]
      // }),
        // this.setData({
    
    
        //   // 保存获取到的数据 哈哈哈哈
        //   shoplist:res.data.message.goods
        // })
    })

      // this.getGoodsList();
    }
  },

4.详情页面

循环shoplist 数据 
<view wx:for="{
    
    {
    
    shoplist}}" wx:key="index" class="box" 
bindtap="gotodetail" data-goods_id="{
    
    {
    
    item.goods_id}}">

点击的时候吧每一项的goods_id 保存下来 然后传给详情页

// 跳转到 详情页
  gotodetail(e) {
    
    
    // console.log(ad)
    // console.log(e.currentTarget.dataset.goods_id)
    let i = e.currentTarget.dataset.goods_id
    wx.redirectTo({
    
    
      url: '/pages/goods_detail/goods_detail?goods_id=' + i,
    })
    this.setData({
    
    
      i: e.currentTarget.dataset.goods_id
    })
  },

在详情页面

  * 生命周期函数--监听页面加载
   */
  onShow: function () {
    
    
    // 获取本地数据里的 数据
    this.obj.cart = wx.getStorageSync('cart') || [];

    // // getGoodsDetail
    // let pages = getCurrentPages();
    // let currentPage = pages[pages.length - 1];
    // let options = currentPage.options;
    // const {
    
     goods_id } = options;
    // // this.getGoodsDetail(goods_id);
  },
  // 请求的数据保存携带的参数  使用的是封装的方法
  // onLoad 的时间段
  onLoad: function (options) {
    
    
    console.log(options);
    // 保存点击传过来的id 
    this.setData({
    
    
      id: options.goods_id
    })
    //  console.log(this.data.id);
    // 请求数据  携带保存的参数 
    app.http.detail({
    
     goods_id: this.data.id }).then(res => {
    
    
      console.log(res)
      // this.goodsObj=res.data.message
      this.setData({
    
    

        //保存获取到的详情的信息 
        GoodsInfo: res.data.message,
        // 保存一个对象  用来添加字段
        // goodsObj:res.data.message
      });
      console.log(this.data.GoodsInfo)
      // 获取缓存中的商品收藏的数组
      let collect = wx.getStorageSync("collect") || []
      // 判断是否被收藏数据
      let isCollect = collect.some(v => v.goods_id == this.GoodsInfo.goods_id);
    })
  },

5.购物车页面

// 添加购物车
  handleCartAdd() {
    
    
    //console.log(this.data.GoodsInfo)
    let k = false;
    // 保存
    let price = this.data.GoodsInfo.goods_price;
    let image = this.data.GoodsInfo.goods_small_logo;
    console.log(image);
    let flag = false;
    // 选中的状态
    let num = 1;
    let name = this.data.GoodsInfo.goods_name;
    let id = this.data.GoodsInfo.goods_id;
    // 循环
    this.obj.cart.forEach(item => {
    
    
      if (item.id == id) {
    
    
        k = true;
        item.num++
      }
    })
    if (!k) {
    
    
      // 直接push 一个对象 存到 购物车的数组中去数据 
      this.obj.cart.push({
    
    
        price,
        image,
        flag,
        num,
        name,
        id
      })
    }
    console.log(this.obj.cart);
    // 存到本地存储
    wx.setStorageSync('cart', this.obj.cart);
    // 提示弹窗
    wx.showToast({
    
    
      title: '加入成功',
      icon: 'success',
      //     // true 防止用户 手抖 疯狂点击按钮 
      mask: true
      //     // 无语可可可可可
    })
  },

6.收藏页面

// 点击 商品收藏图标  有问题
  // handleCollect
  handleCollect() {
    
    
    // 定义图标的变量 一开始是 false 状态
    let isCollect = false;
    // 1 获取缓存中的商品收藏数组 没有就是空数组  
    let collect = wx.getStorageSync("collect") || [];
    // 2 判断该商品是否被收藏过    findIndex  查找 是否存在这一项  如果存在就返回下边  
    // 如果不存在就返回 -1 
    // index 保存下来     循环遍历拿到本地数组的每一项  
    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 把数组存入到缓存中  本地的缓存中  并且名字叫 setStorageSync 
    wx.setStorageSync("collect", collect);
    // 5 修改data中的属性  isCollect
    this.setData({
    
    
      isCollect
    })
  }
})

7.客服、分享页面

 <view class="iconfont icon-kefu"></view>
    <view>客服</view>
    <button open-type="contact"></button>
  </view>
  <view class="tool_item">
    <view class="iconfont icon-yixianshi-"></view>
    <view>分享</view>
    <button open-type="share"></button>
  </view>

8.结算的页面

全选 判断

 // 全选  上面控制下面的数据
  checkAll(e) {
    
    
    // console.log(e)
    // 判断 
    if (this.data.active == true) {
    
    
      this.data.cart.forEach(item => {
    
    
        item.flag = false;
      })
      this.data.active = false
    }
    // 选中的要放在新的本地数据的数组里面
    else {
    
    
      this.data.cart.forEach(item => {
    
    
        item.flag = true;
      })
      this.data.active = true
    }
    // 保存确定过状态后的数据状态
    this.setData({
    
    
      cart: this.data.cart,
      active: this.data.active
    });

    // 判断购物车里的数据是否是选中的状态  支付页面需要使用
    // 只展示的是选中过的数据
    console.log(this.data.cart);
    this.maxprice()
  },

复选框的全选

  // 全选
  changebox(e) {
    
    
    console.log(e)
    let that = this
    let ids = e.detail.value;
    that.data.cart.forEach(item => {
    
    
      item.flag = false;
    });
    ids.forEach(i => {
    
    
      that.data.cart.forEach((item, index) => {
    
    
        if (item.id == i) {
    
    
          that.data.cart[index].flag = true;
        }
      })
    })
    // 单选
    let arrLength = ids.length
    // 
    let shopLength = that.data.cart.length
    // 判断
    if (arrLength == shopLength) {
    
    
      that.setData({
    
    
        active: true,
      })
    } else {
    
    
      that.setData({
    
    
        active: false
      })
    }
    this.maxprice()
  },

根据选中的状态来计算总价

//计算总价
  maxprice() {
    
    
    let arr = this.data.cart.filter(item => {
    
    
      return item.flag == true
    })
    let num = arr.length
    // 初始数据

    let price = 0
    arr.forEach(item => {
    
    
      price = price + item.num * item.price
    })
    this.setData({
    
    
      sum: price,
      num: num
    })
  },

数据的数量加和减

  // 加加加
  jia(e) {
    
    
    let id = e.currentTarget.dataset.id
    // console.log(this.data.id)
    // 判断数据 是否是和当前点击的数据一致,一致就让他减减
    this.data.cart.forEach((item, index) => {
    
    
      if (item.id == id) {
    
    
        item.num++;
        // 判断减不能为零
      }
    })
    this.setData({
    
    
      cart: this.data.cart
    })
    // 
    this.maxprice()
  },
  // 减减减
  jian(e) {
    
    
    // console.log(this.data.cart)
    let id = e.currentTarget.dataset.id
    this.data.cart.forEach((item, index) => {
    
    
      // 判断数据 
      if (item.id == id) {
    
    
        item.num--;
      }
    })
    this.setData({
    
    
      cart: this.data.cart
    })
    // console.log(e)
    this.maxprice()
  },

数据每发生一次变化都需要 对总价进行调用

9.获取地址页面

 <!-- 当收货地址 不存在 按钮显示  对象 空对象 bool类型也是true  -->
  <view class="address_btn" wx:if="{
    
    {
    
    !address.userName}}" class="shou">
    <view class="add" bindtap="add"> + 获取收货地址</view>
  </view>

// 收货地址 的方法 使用chooseAddress 微信小程序的内置的方法

  add() {
    
    
    wx.chooseAddress({
    
    
      success: (result) => {
    
    
        console.log(result)
        this.setData({
    
    
          address: result
        })
        // 存到本地存储
        wx.setStorageSync('address', this.data.address)
        console.log(this.data.address)
        // let address = result
        // address.all = address
      },
    })
  },

10.支付页面

在这里插入图片描述

1、点击 支付**

>  async handleOrderPay() {
>     try {
>       // 判断缓存中有没有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 } });

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);

9、支付成功了 跳转到订单页面*

>      wx.navigateTo({
    
    
>         url: '/pages/order/index'
>       });
>         
>     } catch (error) {
    
    
>       await showToast({
    
     title: "支付失败" })
>       console.log(error);
>     }   }

11. 微信小程序的授权登录

// 小程序授权登录 流程 (auth)
例如

1、首先 获取用户信息

const {
    
     encryptedData, rawData, iv, singature } = e.detail;

2、获取小程序 登录成功后的code

const {
    
     code } = await login();

// 保存到一个对象中获取到的用户的参数信息

const loginParams = {
    
     encryptedData, rawData, 
iv, signature, code };

3、发送请求 获取用户信息

const { token } = await request({ url: "/users/wxlogin", data: loginParams, method: "post" });

4、把token 存入缓存中 同时跳回到上一个页面

wx.setStorageSync("token", token);

// 回到 上一页 wx的内置方法

wx.navigateBack({
    
    
  delta: 1
});

// try方法 是跳过报错 直接进入下一步 不会影响代码的执行

// try {
    
    }catch(error){
    
    
  // await showToast({
    
     title: "支付失败" })
//  console.log(error)
// }

Guess you like

Origin blog.csdn.net/m0_57349005/article/details/116947997