小程序购物城项目实战(上篇)

提示

文章中代码可能有粘贴不完整的地方,极少数地方,完整代码在(下篇)中贴出。(中篇)的链接如下
(中篇)

小程序的第三方框架

  • 腾讯的 wepy 类似vue框架
  • 美团的 mpvue 类似vue框架
  • 京东的 taro 类似react框架
  • 滴滴的 chameleon
  • uni-app 类似vue框架

资料和文件准备

接口文档地址。(地址
小程序开发文档。地址
阿里巴巴字体图标库。地址
mdn。添加链接描述

开始搭建

新建一个工程。并填入自己的Appid
在这里插入图片描述
目录下新增以下文件夹。
在这里插入图片描述

在这里插入图片描述
然后搭建项目的页面,在pages中增添页面。在全局配置的app.json中修改代码,然后pages中自动添加页面。
代码如下

{
  "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"],
  "window":{
    "backgroundTextStyle":"light",
    "navigationBarBackgroundColor": "#fff",
    "navigationBarTitleText": "购物城",
    "navigationBarTextStyle":"black"
  }
}

在这里插入图片描述
在这里插入图片描述
引入字体图标。阿里巴巴字体图标库。
首先进入阿里图标库官网,搜索购物相关图标。
在这里插入图片描述
然后点击添加入库。
在这里插入图片描述
然后点击网页右上角图标,选择添加进项目。没有项目的要自己新建一个。
在这里插入图片描述
然后点击生成的代码。
在这里插入图片描述
进入到一个网页,然后全选网页内容,复制。
在这里插入图片描述
在styles中新建文件,并把代码粘贴到该文件内。
在这里插入图片描述
然后引入图标库,
在这里插入图片描述
测试一下,在index文件夹下的index.wxml输入代码。
在这里插入图片描述
效果如下
在这里插入图片描述
搭建tabbar结构,即小程序页面最底部的结构。新建icons文件夹,并放入以下图片,这些图片可自行替换。
在这里插入图片描述

在这里插入图片描述
然后在全局配置的app.json中书写代码。

{
  "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"
  ],
  "window": {
    "backgroundTextStyle": "light",
    "navigationBarBackgroundColor": "#fff",
    "navigationBarTitleText": "购物城",
    "navigationBarTextStyle": "black"
  },
  "tabBar": {
    "color": "#000",
    "selectedColor": "#ff2d4a",
    "backgroundColor": "#fafafa",
    "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"
      }
    ]
  },
  "sitemapLocation": "sitemap.json"
}

效果如下
在这里插入图片描述
初始化页面的样式。在全局配置文件app.wxss中书写代码。

/**app.wxss**/
/* 引入阿里图标库 */
@import"./styles/iconfont.wxss";

/* 在小程序中不支持通配符 “*” */
/* 注意:所以给以下标签写初始化样式时,最外层还要加一个page */
page,
view,
text,
swiper,
swiper-item,
image,
navigator {
  padding: 0;
  margin: 0;
  box-sizing: border-box;
}

/* 主题颜色,通过一个变量来实现 */
page {
  /* 定义主题颜色 */
  --themColor: #eb4450;
  /* 定义统一的字体大小,小程序中1px=2rpx */
  font-size: 28rpx;
}

然后在index文件夹下的index.wxss测试一下使用

/* 使用主题颜色 */
view{
  color: var(--themColor);
}

效果如下
在这里插入图片描述

随后修改页面顶部的背景样式,在全局配置文件app.json中的window内的代码修改。

  "window": {
    "backgroundTextStyle": "light",
    "navigationBarBackgroundColor": "#eb4450",
    "navigationBarTitleText": "购物城",
    "navigationBarTextStyle": "white"
  },

效果如下
在这里插入图片描述

首页-搜索框

在组件文件夹下,新建SearchInput文件夹,用来保存搜索框组件。然后右键选择该文件夹,选择新建components。建好后的效果如下
在这里插入图片描述
接下来是引入组件,那个页面要用就在哪个页面的文件夹内引入。在index文件夹下的index.json中引入。

{
  "usingComponents": {
    "SearchInput":"../../components/SearchInput/SearchInput"
  },
  "navigationBarTitleText": "首页"
}

然后测试一下在index.wxml中输入

<view class="gouwu">
<!-- 搜索框 -->
<SearchInput></SearchInput>
</view>

效果如下

在这里插入图片描述
然后修改搜索框样式,首先在searchinput.wxml中修改结构。

<view class="search_input">
  <navigator>搜索</navigator>
</view>

然后在searchinput.wxss中修改样式。

.search_input {
  height: 90rpx;
  padding: 10rpx;
  background-color: var(--themColor);
}
.search_input navigator {
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  background-color: #fff;
  color:slategrey;
}

效果如下
在这里插入图片描述
增加跳转功能,点击搜索按钮,跳转到搜索页面。
在searchinput.wxml内修改代码

<!--components/SearchInput/SearchInput.wxml-->
<view class="search_input">
<!-- 搜索框一点击就会跳转到搜索页面 -->
  <navigator url="/pages/search/index">搜索</navigator>
</view>

首页-轮播图

在之前准备的资料接口文档里,获取首页轮播图的API。
在这里插入图片描述
在index文件夹下的index.js文件修改代码。

Page({

  /**
   * 页面的初始数据
   */
  data: {
    // 轮播图数组
    swiperList:[]
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    // 开始发送异步请求,获取轮播图数据
    wx.request({
      url: 'https://api-hmugo-web.itheima.net/api/public/v1/home/swiperdata',
      method: 'GET',
      success: (result) => {
        //查看返回的数据是什么
        console.log(result);
        //设置获取返回的数据
        this.setData({
          swiperList:result.data.message
        })
      },
      fail: (res) => {},
      complete: (res) => {},
    })
  },

  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady: function () {
    
  },

  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function () {
    
  },

  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide: function () {
    
  },

  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload: function () {
    
  },

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

  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom: function () {
    
  },

  /**
   * 用户点击右上角分享
   */
  onShareAppMessage: function () {
    
  }
})

可以看到已经成功取到返回数据。
在这里插入图片描述

首页-轮播图渲染

在首页index文件夹下的index.wxml书写轮播图结构。

<view class="gouwu">
  <!-- 搜索框 -->
  <SearchInput></SearchInput>
  <!-- 轮播图 -->
  <view class="lunbotu">
    <!-- swiper、image等标签一开始设置过了默认的宽度和高度 -->
    <!-- 在swiper标签上开始autoplay自动轮播属性,并显示轮播指示点 和衔接轮播-->
    <swiper autoplay="true" indicator-dots="true" circular="true">
      <!-- 需要给swiper-item进行循环 -->
      <!-- 循环的内容都是从服务器端返回并存入swiperList中获得的 -->
      <swiper-item wx:for="{{swiperList}}" wx:key="goods_id">
        <navigator>
          <!-- 图片标签增加mode属性widthFix,图片标签的内容的高宽等比例变化 -->
          <image mode="widthFix" src="{{item.image_src}}"></image>
        </navigator>
      </swiper-item>
    </swiper>
  </view>
</view>

在index.wxss中书写相关标签的样式。

/* 使用主题颜色 */
view{
  color: var(--themColor);
}
/* view标签内的image样式 */
.lunbotu image{
width: 100%;
}
/* swiper标签的样式,高和宽遵从原图的尺寸 */
.lunbotu swiper{
  width: 750rpx;
  height: 340rpx;
}

最后的效果如下
在这里插入图片描述

优化数据请求方式

优化的手段可以通过es6的技术promise解决。在request文件夹下新建index.js,然后输入代码

// params是参数
export const request = (params) => {
  return new Promise((
    // resolve是请求数据成功的结果,reject是请求失败
    resolve,
    reject
   ) => {
    wx.request({
      // ...params是解构参数
      ...params,
      success: (result) => {
        resolve(result)
      },
      fail:(err)=>{
        reject(err);
      }
    });
  })
}

随后在index文件夹下的index.js内修改代码。

//引入用来发送请求的方法,优化后的
import{request} from "../../request/index.js"
Page({
  /**
   * 页面的初始数据
   */
  data: {
    // 轮播图数组
    swiperList:[]
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    // 开始发送异步请求,获取轮播图数据,优化的手段可以通过es6的技术promise解决
    request({url:"https://api-hmugo-web.itheima.net/api/public/v1/home/swiperdata"}).then(result=>{
      this.setData({
        swiperList:result.data.message
      })
    })
  },

  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady: function () {
    
  },

  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function () {
    
  },

  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide: function () {
    
  },

  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload: function () {
    
  },

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

  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom: function () {
    
  },

  /**
   * 用户点击右上角分享
   */
  onShareAppMessage: function () {
    
  }
})

首页-分类导航

查看相关接口文档的信息。
在这里插入图片描述
在index文件夹下,首先是构建分类导航的结构,index.wxml内代码

<view class="gouwu">
  <!-- 搜索框 -->
  <SearchInput></SearchInput>
  <!-- 轮播图 -->
  <view class="lunbotu">
    <!-- swiper、image等标签一开始设置过了默认的宽度和高度 -->
    <!-- 在swiper标签上开始autoplay自动轮播属性,并显示轮播指示点 和衔接轮播-->
    <swiper autoplay="true" indicator-dots="true" circular="true">
      <!-- 需要给swiper-item进行循环 -->
      <!-- 循环的内容都是从服务器端返回并存入swiperList中获得的 -->
      <swiper-item wx:for="{{swiperList}}" wx:key="goods_id">
        <navigator>
          <!-- 图片标签增加mode属性widthFix,图片标签的内容的高宽等比例变化 -->
          <image mode="widthFix" src="{{item.image_src}}"></image>
        </navigator>
      </swiper-item>
    </swiper>
  </view>
  <!-- 分类导航 -->
  <view class="fenlei">
    <navigator wx:for="{{cateList}}" wx:key="name">
      <image mode="widthFix" src="{{item.image_src}}"></image>
    </navigator>
  </view>
</view>

然后是实现请求数据,在index.js下。

//引入用来发送请求的方法,优化后的
import {
  request
} from "../../request/index.js"
Page({
  /**
   * 页面的初始数据
   */
  data: {
    // 轮播图数组
    swiperList: [],
    //导航数组
    cateList:[]
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    // 调用获取轮播图数据方法
    this.getSwiperList(),
    // 调用获取分类导航数据方法
    this.getCateList()
  },
  // 获取轮播图数据方法
  getSwiperList() {
    // 开始发送异步请求,获取轮播图数据,优化的手段可以通过es6的技术promise解决
    request({
      url: "https://api-hmugo-web.itheima.net/api/public/v1/home/swiperdata"
    }).then(result => {
      this.setData({
        swiperList: result.data.message
      })
    })
  },
  // 获取分类导航数据
  getCateList() {
    // 开始发送异步请求,获取轮播图数据,优化的手段可以通过es6的技术promise解决
    request({
      url: "https://api-hmugo-web.itheima.net/api/public/v1/home/catitems"
    }).then(result => {
      this.setData({
        cateList: result.data.message
      })
    })
  },
  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady: function () {

  },

  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function () {

  },

  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide: function () {

  },

  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload: function () {

  },

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

  },

  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom: function () {

  },

  /**
   * 用户点击右上角分享
   */
  onShareAppMessage: function () {

  }
})

然后是书写样式在index.wxss下

/* 使用主题颜色 */
view{
  color: var(--themColor);
}
/* 轮播图的view标签内的image样式 */
.lunbotu image{
width: 100%;
}
/* swiper标签的样式,高和宽遵从原图的尺寸 */
.lunbotu swiper{
  width: 750rpx;
  height: 340rpx;
}
/* 分类导航内的样式 */
.fenlei{
  display: flex;
}
.fenlei navigator{
  padding: 20rpx;
  flex: 1;
}
/* 这里的图片与它的父元素一样宽 */
.fenlei image{
  width: 100%;
}

最终效果
在这里插入图片描述

首页-楼层

查看接口文档。
在这里插入图片描述
同理进行,发送请求,书写楼层部分的结构,书写样式。
index.wxml代码

<view class="gouwu">
  <!-- 搜索框 -->
  <SearchInput></SearchInput>
  <!-- 轮播图 -->
  <view class="lunbotu">
    <!-- swiper、image等标签一开始设置过了默认的宽度和高度 -->
    <!-- 在swiper标签上开始autoplay自动轮播属性,并显示轮播指示点 和衔接轮播-->
    <swiper autoplay="true" indicator-dots="true" circular="true">
      <!-- 需要给swiper-item进行循环 -->
      <!-- 循环的内容都是从服务器端返回并存入swiperList中获得的 -->
      <swiper-item wx:for="{{swiperList}}" wx:key="goods_id">
        <navigator>
          <!-- 图片标签增加mode属性widthFix,图片标签的内容的高宽等比例变化 -->
          <image mode="widthFix" src="{{item.image_src}}"></image>
        </navigator>
      </swiper-item>
    </swiper>
  </view>
  <!-- 分类导航 -->
  <view class="fenlei">
    <navigator wx:for="{{cateList}}" wx:key="name">
      <image mode="widthFix" src="{{item.image_src}}"></image>
    </navigator>
  </view>
  <!-- 楼层 -->
  <view class="louceng">
    <view class="floor_group" wx:for="{{floorList}}" wx:for-item="item1" wx:for-index="index1" wx:key="floor_title">
      <!-- 楼层的标题 -->
      <view class="title">
        <image mode="widthFix" src="{{item1.floor_title.image_src}}"></image>
      </view>
      <!-- 楼层的具体内容 -->
      <view class="list">
        <navigator wx:for="{{item1.product_list}}" wx:for-item="item2" wx:for-index="index2" wx:key="name">
          <image mode="{{index2===0? 'widthFix':'scaleToFill'}}" src="{{item2.image_src}}"></image>
        </navigator>
      </view>
    </view>
  </view>
</view>

index.wxss代码

/* 使用主题颜色 */
view{
  color: var(--themColor);
}
/* 轮播图的view标签内的image样式 */
.lunbotu image{
width: 100%;
}
/* swiper标签的样式,高和宽遵从原图的尺寸 */
.lunbotu swiper{
  width: 750rpx;
  height: 340rpx;
}
/* 分类导航内的样式 */
.fenlei{
  display: flex;
}
.fenlei navigator{
  padding: 20rpx;
  flex: 1;
}
/* 这里的图片与它的父元素一样宽 */
.fenlei image{
  width: 100%;
}

/*楼层的样式*/
.louceng .title image{
width: 100%;
}
.louceng .list{
  overflow: hidden;
}
.louceng .list navigator{
  float: left;
  width: 33.33%;
}
/* 每一楼层的后四个小图片样式 */
.louceng .list navigator image:nth-last-child(-n+4){
  height: 25vw;
  border-right: 10rpx solid #fff;
}
/*每一楼层的第一张大图片样式*/
.louceng .list navigator image:nth-child(1){
  height: 25vw;
  border-left: 10rpx solid #fff;}
/*每一楼层的四个小图片中的第二行样式*/
.louceng .list navigator image:nth-child(2),image:nth-child(3){
  border-bottom: 10rpx solid #fff;
}
.louceng .list navigator image{
  width: 100%;
}

index.js代码

//引入用来发送请求的方法,优化后的
import {
  request
} from "../../request/index.js"
Page({
  /**
   * 页面的初始数据
   */
  data: {
    // 轮播图数组
    swiperList: [],
    //导航数组
    cateList: [],
    //楼层数组
    floorList: []
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    // 调用获取轮播图数据方法
    this.getSwiperList(),
      // 调用获取分类导航数据方法
      this.getCateList(),
    //调用获取楼层数据的方法
    this.getFloorList()
  },
  // 获取轮播图数据方法
  getSwiperList() {
    // 开始发送异步请求,获取轮播图数据,优化的手段可以通过es6的技术promise解决
    request({
      url: "https://api-hmugo-web.itheima.net/api/public/v1/home/swiperdata"
    }).then(result => {
      this.setData({
        swiperList: result.data.message
      })
    })
  },
  // 获取分类导航数据
  getCateList() {
    // 开始发送异步请求,获取轮播图数据,优化的手段可以通过es6的技术promise解决
    request({
      url: "https://api-hmugo-web.itheima.net/api/public/v1/home/catitems"
    }).then(result => {
      this.setData({
        cateList: result.data.message
      })
    })
  },
  // 获取楼层数据
  getFloorList() {
    // 开始发送异步请求,获取轮播图数据,优化的手段可以通过es6的技术promise解决
    request({
      url: "https://api-hmugo-web.itheima.net/api/public/v1/home/floordata"
    }).then(result => {
      this.setData({
        floorList: result.data.message
      })
    })
  },

  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady: function () {

  },

  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function () {

  },

  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide: function () {

  },

  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload: function () {

  },

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

  },

  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom: function () {

  },

  /**
   * 用户点击右上角分享
   */
  onShareAppMessage: function () {

  }
})

最终效果
在这里插入图片描述

分类页面-获取数据

还是看接口文档,分类页面的url。
在这里插入图片描述
获取接口数据,在category文件夹下的index.js输入以下代码

//引入用来发送请求的方法,优化后的
import {
  request
} from "../../request/index.js"

// pages/category/index.js
Page({

      /**
       * 页面的初始数据
       */
      data: {
        //左侧的菜单数据
        leftMenuList: [],
        //右侧的菜单数据
        rightMenuList: [],
      },
      //接口的返回数据
      Cates: [],

      /**
       * 生命周期函数--监听页面加载
       */
      onLoad: function (options) {
        this.getCates();
      },
      // 获取分类数据
      getCates() {
        request({
            url: "https://api-hmugo-web.itheima.net/api/public/v1/categories"
          })
          .then(res => {
            this.Cates = res.data.message;
            // // 把接口的数据存入到本地存储中
            // wx.setStorageSync("cates", {
            //   time: Date.now(),
            //   data: this.Cates
            // });
            // 构造左侧的大菜单数据
            let leftMenuList = this.Cates.map(v => v.cat_name);
            // 构造右侧的商品数据
            let rightMenuList = this.Cates[0].children;
            this.setData({
              leftMenuList,
              rightMenuList
            })
          })},
          /**
           * 生命周期函数--监听页面初次渲染完成
           */
          onReady: function () {

          },

          /**
           * 生命周期函数--监听页面显示
           */
          onShow: function () {

          },

          /**
           * 生命周期函数--监听页面隐藏
           */
          onHide: function () {

          },

          /**
           * 生命周期函数--监听页面卸载
           */
          onUnload: function () {

          },

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

          },

          /**
           * 页面上拉触底事件的处理函数
           */
          onReachBottom: function () {

          },

          /**
           * 用户点击右上角分享
           */
          onShareAppMessage: function () {

          }
      })

可以看到返回的数据
在这里插入图片描述

分类-页面布局

首先配置分类页面的搜索框。与首页的配置方法一样。
在分类文件夹下的index.json修改代码

{
  "usingComponents": {
    "SearchInput": "../../components/SearchInput/SearchInput"
  },
  "navigationBarTitleText": "商品分类"
}

在index.wxml书写结构

<!--pages/category/index.wxml-->
<view class="cates">
  <navigator>
    <!-- 搜索框 -->
    <SearchInput></SearchInput>
  </navigator>
  <!-- 页面主体 -->
  <view class="cates_container">
    <!-- 左侧菜单 -->
    
    <!-- 右侧商品内容 -->
  </view>
</view>

效果如下
在这里插入图片描述
实现主体内容页面上下滚动,可以使用小程序内置的scroll-view组件标签。并把页面的结构和样式进行书写。

<!--pages/category/index.wxml-->
<view class="cates">
  <navigator>
    <!-- 搜索框 -->
    <SearchInput></SearchInput>
  </navigator>
  <!-- 页面主体 -->
  <view class="cates_container">
    <!-- 左侧菜单 -->
    <scroll-view class="left_menu " scroll-y>
      <!-- *this表示在for循环中的item本身 -->
      <view class="menu_item {{index===currentIndex? 'active':''}}" wx:for="{{leftMenuList}}" wx:key="*this">
        {{item}}
      </view>
    </scroll-view>
    <!-- 右侧商品内容 -->
    <scroll-view class="right_content" scroll-y="true">
      <view class="goods_group" wx:for="{{rightMenuList}}" wx:for-index="index1" wx:for-item="item1">
        <view class="goods_title">
          <text class="FenGeFu">/</text>
          <text class="title">{{item1.cat_name}}</text>
          <text class="FenGeFu">/</text>
        </view>
        <view class="goods_list">
          <navigator wx:for="{{item1.children}}" wx:key="item1.children.cat_id" wx:for-index="index2"
            wx:for-item="item2">
            <image mode="widthFix" src="{{item2.cat_icon}}"></image>
            <view class="goods_name">{{item2.cat_name}}</view>
          </navigator>
        </view>
      </view>
    </scroll-view>
  </view>
</view>
/* pages/category/index.wxss */
page {
  height: 100%;
}

.cates {
  height: 100%;
}

.cates_container {
  /* 页面主体内容高度为整个页面高度(不包含底部导航栏),减去顶部搜索框部分高度 */
  height: calc(100vh - 90rpx);
  display: flex;
}
/* 左侧菜单样式 */
.cates .cates_container .left_menu {
  flex: 2;
}
.cates .cates_container .menu_item{
  height: 80rpx;
  display:flex;
  justify-content: center;
  align-items: center;
  font-size: 30rpx;
}
.cates .cates_container .active{
  color: var(--themColor);
  border-left: 5rpx solid currentColor;
}
/* 右侧商品内容 */
.cates .cates_container .right_content {
  flex: 5;
}
.cates .cates_container .right_content .goods_group .goods_title{
  height: 80rpx;
  display: flex;
  justify-content: center;
  align-items: center;
}
.cates .cates_container .right_content .goods_group .goods_title .FenGeFu{
  color: #ccc;
  padding: 0 10rpx;
}
.cates .cates_container .right_content .goods_group .goods_title .title{
  
}
.cates .cates_container .right_content .goods_group .goods_list{
  display: flex;
  flex-wrap: wrap;

}
.cates .cates_container .right_content .goods_group .goods_list navigator{
  width: 33.33%;
  text-align: center;
  align-items: center;
}
.cates .cates_container .right_content .goods_group .goods_list image{
  width: 100%;
}
.cates .cates_container .right_content .goods_group .goods_list .goods_name{
  text-align: center;
  align-items: center;
}
// pages/category/index.js

//引入用来发送请求的方法,优化后的
import {
  request
} from "../../request/index.js"


Page({

      /**
       * 页面的初始数据
       */
      data: {
        //左侧的菜单数据
        leftMenuList: [],
        //右侧的菜单数据
        rightMenuList: [],
        //被点击的左侧的菜单
        currentIndex:0
      },
      //接口的返回数据
      Cates: [],

      /**
       * 生命周期函数--监听页面加载
       */
      onLoad: function (options) {
        this.getCates();
      },
      // 获取分类数据
      getCates() {
        request({
            url: "https://api-hmugo-web.itheima.net/api/public/v1/categories"
          })
          .then(res => {
            this.Cates = res.data.message;
            // // 把接口的数据存入到本地存储中
            // wx.setStorageSync("cates", {
            //   time: Date.now(),
            //   data: this.Cates
            // });
            console.log(res);
            // 构造左侧的大菜单数据
            let leftMenuList = this.Cates.map(v => v.cat_name);
            // 构造右侧的商品数据
            let rightMenuList = this.Cates[0].children;
            this.setData({
              leftMenuList,
              rightMenuList
            })
          })},
          /**
           * 生命周期函数--监听页面初次渲染完成
           */
          onReady: function () {

          },

          /**
           * 生命周期函数--监听页面显示
           */
          onShow: function () {

          },

          /**
           * 生命周期函数--监听页面隐藏
           */
          onHide: function () {

          },

          /**
           * 生命周期函数--监听页面卸载
           */
          onUnload: function () {

          },

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

          },

          /**
           * 页面上拉触底事件的处理函数
           */
          onReachBottom: function () {

          },

          /**
           * 用户点击右上角分享
           */
          onShareAppMessage: function () {

          }
      })

效果如下
在这里插入图片描述

点击菜单切换商品内容

在category文件夹下的index.js做修改,

// pages/category/index.js

//引入用来发送请求的方法,优化后的
import {
  request
} from "../../request/index.js"


Page({

  /**
   * 页面的初始数据
   */
  data: {
    //左侧的菜单数据
    leftMenuList: [],
    //右侧的菜单数据
    rightMenuList: [],
    //被点击的左侧的菜单
    currentIndex: 0
  },
  //接口的返回数据
  Cates: [],

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    this.getCates();
  },
  // 获取分类数据
  getCates() {
    request({
        url: "https://api-hmugo-web.itheima.net/api/public/v1/categories"
      })
      .then(res => {
        this.Cates = res.data.message;
        // 构造左侧的大菜单数据
        let leftMenuList = this.Cates.map(v => v.cat_name);
        // 构造右侧的商品数据
        let rightMenuList = this.Cates[0].children;
        this.setData({
          leftMenuList,
          rightMenuList
        })
      })
  },
  //左侧菜单的点击事件
  handleItemTap(e) {
    // console.log(e);
    // 1 获取被点击的标题身上的索引
    const {index}=e.currentTarget.dataset
    //2 给data中的currentIndex赋值就可以了
    // 3 构造此时右侧的商品数据
    let rightMenuList = this.Cates[index].children;
    this.setData({
      currentIndex:index,
      rightMenuList
    })
  },
  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady: function () {

  },

  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function () {

  },

  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide: function () {

  },

  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload: function () {

  },

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

  },

  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom: function () {

  },

  /**
   * 用户点击右上角分享
   */
  onShareAppMessage: function () {

  }
})

效果
在这里插入图片描述

使用缓存技术

每次请求网络上数据时,先查看是否本地有存储且还未过期,如果有,就优先使用本地数据。

// pages/category/index.js

//引入用来发送请求的方法,优化后的
import {
  request
} from "../../request/index.js"


Page({

  /**
   * 页面的初始数据
   */
  data: {
    //左侧的菜单数据
    leftMenuList: [],
    //右侧的菜单数据
    rightMenuList: [],
    //被点击的左侧的菜单
    currentIndex: 0
  },
  //接口的返回数据
  Cates: [],

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    // 1先判断一下本地存储中有没有旧的数据,形式是{时间戳,数据}的形式
    // 2没有旧数据直接发送新请求
    // 3有旧的数据同时旧的数据也没有过期就使用本地存储中的旧数据即可

    //获取本地存储的数据,小程序中也是有存在本地的技术。
    const Cates = wx.getStorageSync('cates');
    //判断
    if (!Cates) {
      //不存在 发送请求获取数据
      this.getCates();
    }else{
      // 有旧的数据 定义过期时间为10秒
      if(Date.now()-Cates.time>10000){
        this.getCates();
      }else{
        this.Cates=Cates.data;
        console.log(Cates);
        // 构造左侧的大菜单数据
        let leftMenuList = this.Cates.map(v => v.cat_name);
        // 构造右侧的商品数据
        let rightMenuList = this.Cates[0].children;
        this.setData({
          leftMenuList,
          rightMenuList
        })
      }
    }

  },
  // 获取分类数据
  getCates() {
    request({
        url: "https://api-hmugo-web.itheima.net/api/public/v1/categories"
      })
      .then(res => {
        this.Cates = res.data.message;
        // 把接口的数据存入到本地存储中
        wx.setStorageSync("cates", {
          time: Date.now(),
          data: this.Cates
        });
        // console.log(res);
        // 构造左侧的大菜单数据
        let leftMenuList = this.Cates.map(v => v.cat_name);
        // 构造右侧的商品数据
        let rightMenuList = this.Cates[0].children;
        this.setData({
          leftMenuList,
          rightMenuList
        })
      })
  },
  //左侧菜单的点击事件
  handleItemTap(e) {
    // console.log(e);
    // 1 获取被点击的标题身上的索引
    const {
      index
    } = e.currentTarget.dataset
    //2 给data中的currentIndex赋值就可以了
    // 3 构造此时右侧的商品数据
    let rightMenuList = this.Cates[index].children;
    this.setData({
      currentIndex: index,
      rightMenuList
    })
  },
  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady: function () {

  },

  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function () {

  },

  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide: function () {

  },

  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload: function () {

  },

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

  },

  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom: function () {

  },

  /**
   * 用户点击右上角分享
   */
  onShareAppMessage: function () {

  }
})

商品列表

实现点击分类中的商品,跳转到商品列表页面。通过url传递参数。比如点击分类中的电视,其数据中有个cid=5属性,然后这个参数会传递到将要跳转的页面。

<!--pages/category/index.wxml-->
<view class="cates">
  <navigator>
    <!-- 搜索框 -->
    <SearchInput></SearchInput>
  </navigator>
  <!-- 页面主体 -->
  <view class="cates_container">
    <!-- 左侧菜单 -->
    <scroll-view class="left_menu " scroll-y>
      <!-- *this表示在for循环中的item本身 -->
      <view class="menu_item {{index===currentIndex? 'active':''}}" wx:for="{{leftMenuList}}" wx:key="*this" bindtap="handleItemTap" data-index="{{index}}">
        {{item}}
      </view>
    </scroll-view>
    <!-- 右侧商品内容 -->
    <scroll-view class="right_content" scroll-top="{{scrolltop}}" scroll-y="true">
      <view class="goods_group" wx:for="{{rightMenuList}}" wx:for-index="index1" wx:for-item="item1" wx:key="cat_id">
        <view class="goods_title">
          <text class="FenGeFu">/</text>
          <text class="title">{{item1.cat_name}}</text>
          <text class="FenGeFu">/</text>
        </view>
        <view class="goods_list">
        <!-- url传递商品的一些参数 -->
          <navigator open-type="navigate" wx:for="{{item1.children}}" wx:key="cat_id" wx:for-index="index2"
            wx:for-item="item2" 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>
      </view>
    </scroll-view>
  </view>
</view>

然后在goods_list文件夹下的index.js,打印一下看看是否传递过来参数,

// pages/goods_list/index.js
Page({

  /**
   * 页面的初始数据
   */
  data: {

  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    console.log(options);
  }})

效果如下

在这里插入图片描述

商品列表页面

首先是在goods_list文件夹下的index.js引入自定义好的组件搜索框,并在index.wxml文件中使用该组件。另外还有一个顶部导航栏,同理在components文件夹内新建一个tabs文件夹,用来自定义顶部导航栏组件,随后进行引用。
首先是tabs文件夹内代码

// components/tabs/tabs.js
Component({
  /**
   * 组件的属性列表
   */
  properties: {
    tabs: {
      type: Array,
      value: [],

    }
  },

  /**
   * 组件的初始数据
   */
  data: {

  },

  /**
   * 组件的方法列表
   */
  methods: {
    //点击事件
    handleItemTap(e) {
      //获取点击的索引
      const {
        index
      } = e.currentTarget.dataset;
      //触发父组件中的事件,自定义的
      this.triggerEvent("tabsItemChange", {
        index
      });
    }
  }
})
<!--components/tabs/tabs.wxml-->
<view class="tabs">
  <view class="tabs_title">
    <!-- 里边的三目运算符是验证某个item是否被激活 -->
    <view wx:for="{{tabs}}" wx:key="id" class="title_item {{item.isActive?'active':''}}" bindtap="handleItemTap"
      data-index="{{index}}">{{item.value}}</view>
  </view>
  <view class="tabs_content">
  <!-- slot是插槽标签 -->
    <slot></slot>
  </view>
</view>
/* components/tabs/tabs.wxss */
.tabs{}
.tabs_title{
  display: flex;
  padding: 15rpx 0;
}
.title_item{
  display: flex;
  justify-content: center;
  align-items: center;
  flex: 1;
  padding: 15rpx 0;
}
.active{
  color: var(--themColor);
  border-bottom: 5rpx solid currentColor;
}
.tabs_content{}

然后是goods_list内代码

// pages/goods_list/index.js
Page({

  /**
   * 页面的初始数据
   */
  data: {
    tabs: [{
        id: 0,
        value: '综合',
        isActive: true
      },
      {
        id: 1,
        value: '销量',
        isActive: false
      },
      {
        id: 2,
        value: '价格',
        isActive: false
      }
    ]
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    console.log(options);
  },
  //标题的点击事件,从子组件传递过来
  handleTabsItemChange(e){
    //获取被点击的标题索引
    const{index}=e.detail;
    //修改源数组
    let {tabs}=this.data;
    tabs.forEach((v,i)=>i===index?v.isActive=true:v.isActive=false);
    //赋值到data中
    this.setData({
      tabs
    })
  },
  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady: function () {

  },

  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function () {

  },

  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide: function () {

  },

  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload: function () {

  },

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

  },

  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom: function () {

  },

  /**
   * 用户点击右上角分享
   */
  onShareAppMessage: function () {

  }
})
{
  "usingComponents": {
    "SearchInput": "../../components/SearchInput/SearchInput",
    "tabs": "../../components/tabs/tabs"
  },
  "navigationBarTitleText": "商品列表"
}
<!--pages/goods_list/index.wxml-->
<view>
  <SearchInput></SearchInput>
  <tabs tabs="{{tabs}}" bindtabsItemChange="handleTabsItemChange">
  <!-- 如果导航栏tabs中的第0个导航被选中; 就显示0 -->
  <block wx:if="{{tabs[0].isActive}}">0</block>
  <block wx:elif="{{tabs[1].isActive}}">1</block>
  <block wx:elif="{{tabs[2].isActive}}">2</block>
  </tabs>
</view>

最终效果如下
在这里插入图片描述

商品列表的静态样式

在goods_list文件夹内进行修改

<!--pages/goods_list/index.wxml-->
<view>
  <SearchInput></SearchInput>
  <tabs tabs="{{tabs}}" bindtabsItemChange="handleTabsItemChange">
    <!-- 如果导航栏tabs中的第0个导航被选中; 就显示0 -->
    <block wx:if="{{tabs[0].isActive}}">
      <view class="first_tab">
        <navigator class="goods_item">
          <!-- 左侧图片容器 -->
          <view class="goods_img_wrap">
            <image mode="widthFix" src="https://api-hmugo-web.itheima.net/pyg/icon_index_nav_4@2x.png"></image>
          </view>
          <!-- 右侧商品信息容器 -->
          <view class="goods_info_wrap">
            <view class="goods_name">123sssss口口声声老师你打咯密码死哦我司分为哪</view>
            <view class="goods_price">19999</view>
          </view>
        </navigator>
      </view>
    </block>
    <block wx:elif="{{tabs[1].isActive}}">
      <view class="second_tab">
        <navigator></navigator>
      </view>
    </block>
    <block wx:elif="{{tabs[2].isActive}}">
      <view class="third_tab">
        <navigator></navigator>
      </view>
    </block>
  </tabs>
</view>
/* pages/goods_list/index.wxss */
.first_tab {}

.first_tab .goods_item {
  display: flex;
  border-bottom: 1px solid #ccc;
}

.first_tab .goods_item .goods_img_wrap {
  flex: 2;
  display: flex;
  justify-content: center;
  align-items: center;
}

.first_tab .goods_item .goods_img_wrap image {
  width: 60%;
}

.first_tab .goods_item .goods_info_wrap {
  flex: 3;
  display: flex;
  flex-direction: column;
  justify-content: space-around;
}

.first_tab .goods_item .goods_info_wrap .goods_name {
  display: -webkit-box;
  overflow: hidden;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
}

.first_tab .goods_item .goods_info_wrap .goods_price {
  color: var(--themColor);
  font-size: 32rpx;
}

静态样式如下
在这里插入图片描述

商品列表动态渲染

经过查看接口文档,获得请求的接口url。使用了ES7的写法。

// pages/goods_list/index.js
//引入用来发送请求的方法,优化后的
import {
  request
} from "../../request/index.js"
Page({

  /**
   * 页面的初始数据
   */
  data: {
    tabs: [{
        id: 0,
        value: '综合',
        isActive: true
      },
      {
        id: 1,
        value: '销量',
        isActive: false
      },
      {
        id: 2,
        value: '价格',
        isActive: false
      }
    ],
    goodsList: []
  },
  //接口要的参数
  QueryParams: {
    query: "",
    cid: "",
    pagenum: 1,
    pagesize: 10
  },
  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    this.QueryParams.cid = options.cid;
    this.getGoodsList()
  },

  //获取商品列表数据 使用ES7的写法
  async getGoodsList() {
    const res = await request({
      url: "https://api-hmugo-web.itheima.net/api/public/v1/goods/search",
      data: this.QueryParams
    });
    console.log(res)
    this.setData({
      goodsList: res.data.message.goods
    })
  },
  //标题的点击事件,从子组件传递过来
  handleTabsItemChange(e) {
    //获取被点击的标题索引
    const {
      index
    } = e.detail;
    //修改源数组
    let {
      tabs
    } = this.data;
    tabs.forEach((v, i) => i === index ? v.isActive = true : v.isActive = false);
    //赋值到data中
    this.setData({
      tabs
    })
  },
  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady: function () {

  },

  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function () {

  },

  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide: function () {

  },

  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload: function () {

  },

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

  },

  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom: function () {

  },

  /**
   * 用户点击右上角分享
   */
  onShareAppMessage: function () {

  }
})
<!--pages/goods_list/index.wxml-->
<view>
  <SearchInput></SearchInput>
  <tabs tabs="{{tabs}}" bindtabsItemChange="handleTabsItemChange">
    <!-- 如果导航栏tabs中的第0个导航被选中; 就显示0 -->
    <block wx:if="{{tabs[0].isActive}}">
      <view class="first_tab">
        <navigator class="goods_item" wx:for="{{goodsList}}" wx:key="goods_id">
          <!-- 左侧图片容器 -->
          <view class="goods_img_wrap">
          <!-- 若有图片缺失,则用链接的图片代替 -->
            <image mode="widthFix" src="{{item.goods_small_logo?item.goods_small_logo:'http://image1.suning.cn/uimg/b2c/newcatentries/0070078570-000000000147821386_1_400x400.jpg'}}"></image>
          </view>
          <!-- 右侧商品信息容器 -->
          <view class="goods_info_wrap">
            <view class="goods_name">{{item.goods_name}}</view>
            <view class="goods_price">{{item.goods_price}}</view>
          </view>
        </navigator>
      </view>
    </block>
    <block wx:elif="{{tabs[1].isActive}}">
      <view class="second_tab">
        <navigator></navigator>
      </view>
    </block>
    <block wx:elif="{{tabs[2].isActive}}">
      <view class="third_tab">
        <navigator></navigator>
      </view>
    </block>
  </tabs>
</view>

效果如下
在这里插入图片描述

加载下一页数据

滚动浏览商品列表,触底后加载下一页数据。
用户上滑页面滚动条触底开始加载下一页数据步骤。

  • 1找到滚动条触底事件 微信小程序官方开发文档寻找onReachBottom
  • 2判断还有没有下一页数据
  • 3假如没有下一页数据弹出一个提示
  • 4假如还有下一页数据来加载下一页数据
// pages/goods_list/index.js
//引入用来发送请求的方法,优化后的
import {
  request
} from "../../request/index.js"
Page({

  /**
   * 页面的初始数据
   */
  data: {
    tabs: [{
        id: 0,
        value: '综合',
        isActive: true
      },
      {
        id: 1,
        value: '销量',
        isActive: false
      },
      {
        id: 2,
        value: '价格',
        isActive: false
      }
    ],
    goodsList: []
  },

  //接口要的参数
  QueryParams: {
    query: "",
    cid: "",
    pagenum: 1,
    pagesize: 10
  },
  //总页数初始值是1
  totalPages: 1,
  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    this.QueryParams.cid = options.cid;
    this.getGoodsList()
  },

  //获取商品列表数据 使用ES7的写法
  async getGoodsList() {
    const res = await request({
      url: "https://api-hmugo-web.itheima.net/api/public/v1/goods/search",
      data: this.QueryParams
    });
    console.log(res)
    //获取一下商品列表的总条数
    const total = res.data.message.total;
    //计算商品列表的总页数=总条数除以每页10条
    this.totalPages = Math.ceil(total / this.QueryParams.pagesize);
    console.log(this.totalPages);
    this.setData({
      //拼接了数组
      goodsList: [...this.data.goodsList,...res.data.message.goods]
    })
  },
  //标题的点击事件,从子组件传递过来
  handleTabsItemChange(e) {
    //获取被点击的标题索引
    const {
      index
    } = e.detail;
    //修改源数组
    let {
      tabs
    } = this.data;
    tabs.forEach((v, i) => i === index ? v.isActive = true : v.isActive = false);
    //赋值到data中
    this.setData({
      tabs
    })
  },
  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady: function () {

  },

  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function () {

  },

  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide: function () {

  },

  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload: function () {

  },

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

  },

  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom: function () {
//判断是否有下一页
if(this.QueryParams.pagenum>=this.totalPages){
  //没有下一页,弹出提示框
  wx.showToast({
    title: '没有下一页数据了',
  })

}
else{
  //还有下一页
  console.log('%c'+"有下一页数据");
  this.QueryParams.pagenum++;
  this.getGoodsList()
}
  },

  /**
   * 用户点击右上角分享
   */
  onShareAppMessage: function () {

  }
})

下拉刷新功能

下拉时,刷新页面窗口,里边的数据重新请求并显示。
下拉刷新页面步骤

  • 1触发下拉刷新事件 需要在index.json页面配置文件中开启一个配置项,enablePullDownRefresh
  • 2 onPullDownRefresh监听用户下拉操作的函数
  • 3重置数据数组
  • 4重置页码设置为1
  • 5重新发送请求
  • 6请求数据返回后,关闭下拉刷新显示

goods_list文件夹下的index.json代码如下

{
  "usingComponents": {
    "SearchInput": "../../components/SearchInput/SearchInput",
    "tabs": "../../components/tabs/tabs"
  },
  "navigationBarTitleText": "商品列表",
  "enablePullDownRefresh": true,
  "backgroundTextStyle": "dark"
}
// pages/goods_list/index.js
//引入用来发送请求的方法,优化后的
import {
  request
} from "../../request/index.js"
Page({

  /**
   * 页面的初始数据
   */
  data: {
    tabs: [{
        id: 0,
        value: '综合',
        isActive: true
      },
      {
        id: 1,
        value: '销量',
        isActive: false
      },
      {
        id: 2,
        value: '价格',
        isActive: false
      }
    ],
    goodsList: []
  },

  //接口要的参数
  QueryParams: {
    query: "",
    cid: "",
    pagenum: 1,
    pagesize: 10
  },
  //总页数初始值是1
  totalPages: 1,
  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    this.QueryParams.cid = options.cid;
    this.getGoodsList()
  },

  //获取商品列表数据 使用ES7的写法
  async getGoodsList() {
    const res = await request({
      url: "https://api-hmugo-web.itheima.net/api/public/v1/goods/search",
      data: this.QueryParams
    });
    // console.log(res)
    //获取一下商品列表的总条数
    const total = res.data.message.total;
    //计算商品列表的总页数=总条数除以每页10条
    this.totalPages = Math.ceil(total / this.QueryParams.pagesize);
    // console.log(this.totalPages);
    this.setData({
      //拼接了数组
      goodsList: [...this.data.goodsList, ...res.data.message.goods]
    })
    //关闭下拉刷新的窗口
    wx.stopPullDownRefresh({
      success: (res) => {},
    })
  },
  //标题的点击事件,从子组件传递过来
  handleTabsItemChange(e) {
    //获取被点击的标题索引
    const {
      index
    } = e.detail;
    //修改源数组
    let {
      tabs
    } = this.data;
    tabs.forEach((v, i) => i === index ? v.isActive = true : v.isActive = false);
    //赋值到data中
    this.setData({
      tabs
    })
  },
  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady: function () {

  },

  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function () {

  },

  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide: function () {

  },

  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload: function () {

  },

  /**
   * 页面相关事件处理函数--监听用户下拉动作
   */
  onPullDownRefresh: function () {
    //重置数组
    this.setData({
      goodsList: []
    })
    //重置页码为1
    this.QueryParams.pagenum=1;
    //重新发送请求
    this.getGoodsList();
  },

  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom: function () {
    //判断是否有下一页
    if (this.QueryParams.pagenum >= this.totalPages) {
      //没有下一页,弹出提示框
      wx.showToast({
        title: '没有下一页数据了',
      })

    } else {
      //还有下一页
      console.log('%c' + "有下一页数据");
      this.QueryParams.pagenum++;
      this.getGoodsList()
    }
  },

  /**
   * 用户点击右上角分享
   */
  onShareAppMessage: function () {

  }
})

添加页面加载提示效果

在发送数据请求前,出现加载中图标,数据请求回来并显示在页面上之后,关闭这个加载中提示。使用的是wx.showLoading

  • 1把显示页面加载中这个提示封装到request请求函数中。
  • 2当同时发送多个请求时,我们需要在request中进行优化加载关闭函数。

request文件夹下的index.js代码如下

  //发送ajax异步请求的初始次数
 let ajaxTimes = 0;
// params是参数
export const request = (params) => {
  //每发一次请求就自加
  ajaxTimes++;
  //显示加载中效果
  wx.showLoading({
    title: '页面加载中',
    mask: true
  })

  return new Promise((
    // resolve是请求数据成功的结果,reject是请求失败
    resolve,
    reject
  ) => {
    wx.request({
      // ...params是解构参数
      ...params,
      success: (result) => {
        resolve(result)
      },
      fail: (err) => {
        reject(err);
      },
      //无论成功还是失败都会触发的事件
      complete: () => {
        //每发送完一次请求,就自减一,当为0时,表明请求完毕,关闭加载中提示
        ajaxTimes--;
        if (ajaxTimes === 0) {
          //关闭页面加载中图标
          wx.hideLoading()
        }
      }
    });
  })
}

效果如下
在这里插入图片描述

商品详情页面

点击商品列表中的某个商品后,需要跳转到该商品的商品详情页面。所以要给goods_list文件夹下index.wxml的商品列表增加url地址,同时传递点击商品的id。

<!--pages/goods_list/index.wxml-->
<view>
  <SearchInput></SearchInput>
  <tabs tabs="{{tabs}}" bindtabsItemChange="handleTabsItemChange">
    <!-- 如果导航栏tabs中的第0个导航被选中; 就显示0 -->
    <block wx:if="{{tabs[0].isActive}}">
      <view class="first_tab">
      <!-- 点击某个商品后,跳转到商品详情页面 url为要转的地址-->
        <navigator class="goods_item" wx:for="{{goodsList}}" wx:key="goods_id" url="/pages/goods_detail/index?goods_id={{item.goods_id}}">
          <!-- 左侧图片容器 -->
          <view class="goods_img_wrap">
          <!-- 若有图片缺失,则用链接的图片代替 -->
            <image mode="widthFix" src="{{item.goods_small_logo?item.goods_small_logo:'http://image1.suning.cn/uimg/b2c/newcatentries/0070078570-000000000147821386_1_400x400.jpg'}}"></image>
          </view>
          <!-- 右侧商品信息容器 -->
          <view class="goods_info_wrap">
            <view class="goods_name">{{item.goods_name}}</view>
            <view class="goods_price">{{item.goods_price}}</view>
          </view>
        </navigator>
      </view>
    </block>
    <block wx:elif="{{tabs[1].isActive}}">
      <view class="second_tab">
        <navigator></navigator>
      </view>
    </block>
    <block wx:elif="{{tabs[2].isActive}}">
      <view class="third_tab">
        <navigator></navigator>
      </view>
    </block>
  </tabs>
</view>

然后找到商品详情页面goods_detail文件夹。首先是该文件夹下的index.json代码修改

{
  "usingComponents": {},
  "navigationBarTitleText": "商品详情"
}

然后在index.js中修改

// pages/goods_detail/index.js
//引入用来发送请求的方法,优化后的
import {
  request
} from "../../request/index.js"
Page({

  /**
   * 页面的初始数据
   */
  data: {
    //请求返回的数据是以对象形式
    goodsObj: {}
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    //拿到跳转页面时传递过来的商品id
    const {
      goods_id
    } = options;
    this.getGoodsDetail(goods_id);
  },
  /**
   * 获取商品详情数据
   */
  async getGoodsDetail(goods_id) {
    const goodsObj = await request({
      url: "https://api-hmugo-web.itheima.net/api/public/v1/goods/detail",
      data: {
        goods_id
      }
    });
    this.setData({
      goodsObj
    })
  },
  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady: function () {

  },

  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function () {

  },

  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide: function () {

  },

  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload: function () {

  },

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

  },

  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom: function () {

  },

  /**
   * 用户点击右上角分享
   */
  onShareAppMessage: function () {

  }
})

可以看到现在已经能拿到数据了
在这里插入图片描述

  • 16
    点赞
  • 93
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值