I. Project initialization

1. Create a small program

Because I have registered the small program before, the mailbox used here is xinxin’s mailbox. I won’t go into the details of the creation steps

2. Delete unnecessary content

As shown in the figure:

3. Create a project folder

4. Create a project file

5. Introduce font ICONS

6. Set up tabbar structure of the project

7. Project style initialization

Two, the realization of the small program each page

1. The first page

1.1. The search box

(1) First create a SearchInput component

(2) Then import it in the JSON file of the page to be used, and use it in the HTML file

(3) The search component can be developed to CSS files

.search_input {
  height: 90rpx;
  padding: 10rpx;
  background-color: var(--themeColor);
}
.search_input navigator {
  display: flex;
  color: #Awesome!;
  height: 100%;
  justify-content: center;
  align-items: center;
  background-color: #fff;
  border-radius: 15rpx;
}

Copy the code

Effect:

1.2 round figure

(1) Obtain the data of the rotation chart

onLoad: function (options) {
    // 1 Sends an asynchronous request to obtain the multicast graph data
    wx.request({
      url: 'https://api-hmugo-web.itheima.net/api/public/v1/home/swiperdata'.success: (result) = > {
        this.setData({
          swiperList:result.data.message
        })
        // console.log(this.data.swiperList);
        
      },
Copy the code

(2) Render the rotation diagram

 <swiper autoplay interval="3000" circular indicator-dots indicator-color='skyblue'>
    <swiper-item wx:for="{{swiperList}}"  wx:key="item.goods_id">
     <navigator>
      <image mode="widthFix" src="{{item.image_src}}"></image>
     </navigator>
    </swiper-item>
  </swiper>
Copy the code

Effect drawing of rotation drawing:

1.3. Encapsulate request data functions

Use:

1.4 Category List

Request data:

// Get the navigation category array
getCatesList(){
  request({url: 'https://api-hmugo-web.itheima.net/api/public/v1/home/catitems'}).then(result= >{
    // console.log(result);
    this.setData({
   catesList:result.data.message
        })
  })
},
Copy the code
<view class="index_cate">
    <navigator
    wx:for="{{catesList}}"
    wx:key="name"
    >
  <image mode="widthFix" src="{{item.image_src}}"></image></navigator>
  </view>
Copy the code

Style:

/**index.wxss**/
.index_swiper swiper {
  width: 750rpx;
  height: 340rpx;
}
.index_swiper swiper image {
  width: 100%;
}
.index_cate {
  display: flex;
}
.index_cate navigator {
  padding: 20rpx;
  flex: 1;
}
.index_cate navigator image {
  width: 100%;
}

Copy the code

Effect:

The 1.5 floor

Request to obtain floor data:

getFloorList() {
        request({ url: 'https://api-hmugo-web.itheima.net/api/public/v1/home/floordata' }).then(result= > {
            console.log(result);
            this.setData({
                floorList: result.data.message
            })
        })
    },
Copy the code

HTML:

<! -- Floor start --><view class="index_floor">
    <view class="floor_group"
    wx:for="{{floorList}}"
    wx:for-item="item1"
    wx:for-index="index1"
    wx:key="floor_title"
    >
      <! - the title -- -- >
      <view class="floor_title">
        <image mode="widthFix" src="{{item1.floor_title.image_src}}"></image>
      </view>
      <! - content - >
      <view class="floor_content">
        <navigator 
        wx:for="{{item1.product_list}}"
        wx:for-item="item2"
    wx:for-index="index2"
        wx:key="name"
        >
        <image mode="widthFix" src="{{item2.image_src}}"></image>
      </navigator>
      </view>
    </view>
  </view><! -- End of floor -->Copy the code

Style:

// Floor style
.index_floor{
  .floor_group{
    .floor_title{
      padding: 10rpx 0;
      image{
    width: 100%;
      }
    }
    .floor_content{
      // Clear the float
      overflow: hidden;
      navigator {
        float: left;
        width: 33.33%;
        // The last four hyperlinks
        &:nth-last-child(-n+4){
          // The width and height of the original image is 232*386
          / / 232/386 = 33.33 vw/height
          // The height of the first image is 33.33vw*386/232
          height:27.72711vw ;
          border-left: 10rpx solid #fff;
        }
        &:nth-child(2),
        &:nth-child(3){
          border-bottom: 10rpx solid #fff;
        }
        image{
          height: 100%;
          width: 100%;
        }
      }
    }
  }
}
Copy the code

Effect:

Classification of 2.

Design:

2.1. Obtaining classified data:

// pages/category/index.js
// Introduce a wrapped method to send the request
import { request } from ".. /.. /request/index.js"
Page({

  /** * initial data for the page */
  data: {
  // Menu data on the left
leftMenuList: [].// Commodity data on the right
rightGoodsContent:[]
  },
  // Data returned by the interface
  CatesList: []./** * lifecycle function -- listens for page loading */
  onLoad: function (options) {
this.getCates();
  },
  // Get classified data
  getCates(){
    request({
      url:'https://api-hmugo-web.itheima.net/api/public/v1/categories'
    }).then(result= >{
      this.CatesList=result.data.message
      // Construct the large menu data on the left
      let leftMenuList=this.CatesList.map(v= >v.cat_name);
      let rightGoodsContent =this.CatesList[0].children
      this.setData({
        leftMenuList,
        rightGoodsContent
      })
      console.log(result); })}})Copy the code

2.2 Layout + Click the left menu bar to jump

wxml:

<! --pages/category/index.wxml--><view class="cate_index">
<! -- Search box starts -->
<SearchInput></SearchInput>
  <! -- End of search box -->
  <view class="cates_container">
    <! Start from left menu -->
    <scroll-view class="left_menu" scroll-y> 
    <view 
    class="menu_item {{index===currentIndex? 'active':''}}"
    wx:for="{{leftMenuList}}"
    wx:key="*this"
    bindtap="handleItemTap"
    data-index="{{index}}"
    >{{item}}</view>
    </scroll-view>
    <! -- End of left menu -->
    <! -- Start of product content on the right -->
    <scroll-view class="right_content" scroll-y>
     <view class="goods_group"
        wx:for="{{rightGoodsContent}}"
        wx:for-index="index1"
        wx:for-item="item1"
       wx:key='cat_id'>
       <view class="goods_title"
      >
      <text class="delimiter">/</text>
      <text class="title">{{item1.cat_name}}</text>
      <text class="delimiter">/</text>
      </view>
       <view class="goods_list">
      <navigator
        wx:for="{{item1.children}}"
        wx:for-item="item2"
        wx:for-index="index2"
        wx:key="cat_id"
         >
        <image mode="widthFix" src="{{item2.cat_icon}}"></image>
        <view class="goods_name">{{item2.cat_name}}</view>
      </navigator>
      </view>
     </view>
    </scroll-view>
    <! -- End of goods on the right -->
  </view>
  </view>

Copy the code

wxss:

/* pages/category/index.wxss */
page {
  height: 100%;
}
.cate_index .cates_container {
  height: calc(100vh - 90rpx);
  display: flex;
}
.cate_index .cates_container .left_menu {
  flex: 2;
}
.cate_index .cates_container .left_menu .menu_item {
  height: 80rpx;
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 30rpx;
}
.cate_index .cates_container .left_menu .active {
  color: var(--themeColor);
  border-left: 5rpx solid currentColor;
}
.cate_index .cates_container .right_content {
  flex: 5;
}
.cate_index .cates_container .right_content .goods_group .goods_title {
  height: 80rpx;
  display: flex;
  justify-content: center;
  align-items: center;
}
.cate_index .cates_container .right_content .goods_group .goods_title .delimiter {
  color: #ccc;
  padding: 0 10rpx;
}
.cate_index .cates_container .right_content .goods_group .goods_list {
  display: flex;
  flex-wrap: wrap;
}
.cate_index .cates_container .right_content .goods_group .goods_list navigator {
  width: 33.33%;
  text-align: center;
}

Copy the code

js:

// pages/category/index.js
// Introduce a wrapped method to send the request
import { request } from ".. /.. /request/index.js"
Page({
  /** * initial data for the page */
  data: {
  // Menu data on the left
leftMenuList: [].// Commodity data on the right
rightGoodsContent: [].// Click the left menu
currentIndex:0
  },
  // Data returned by the interface
  CatesList: []./** * lifecycle function -- listens for page loading */
  onLoad: function (options) {
this.getCates();
  },
  // Get classified data
  getCates(){
    request({
      url:'https://api-hmugo-web.itheima.net/api/public/v1/categories'
    }).then(result= >{
      this.CatesList=result.data.message
      // Construct the large menu data on the left
      let leftMenuList=this.CatesList.map(v= >v.cat_name);
      let rightGoodsContent =this.CatesList[0].children
      this.setData({
        leftMenuList,
        rightGoodsContent
      })
      // console.log(result);})},// Left menu click events
  handleItemTap(e){
    // console.log(e);
    // 1 gets the index on the clicked title
    // 2 to currentIndexfuzhi in data
    // 3 Render the page on the right according to different indexes
    const {index} =e.currentTarget.dataset;
    let rightGoodsContent = this.CatesList[index].children;
    this.setData({
      currentIndex:index,
      rightGoodsContent
    })
  }
  
})
Copy the code

Effect:

2.3. Use caching

 onLoad: function (options) {
    SetItem ("key","value") localstorage.getiitem ("key") localstorage.getiitem ("key") wxwx.setStorageSync('key', 'value); Wx.getstoragesync ('key') 2 Is there any type conversion in the local storage? {time: date.now (),data:[...] } if the old data has not expired, use the old data in the local storage */
  // 1 Get data from local storage, (small programs also exist local storage technology)
   const Cates=wx.getStorageSync("cates");
  / / 2
  if(! Cates){this.getCates();
  }else{
    // There is old data, define expiration time
    if(Date.now()-Cates.time>1000*600) {// Send the request
      this.getCates();
    }else{
      // Old data can be used
      this.Cates =Cates.data
       // Construct the large menu data on the left
       let leftMenuList=this.Cates.map(v= >v.cat_name);
       let rightGoodsContent =this.Cates[0].children
       this.setData({
         leftMenuList,
         rightGoodsContent
       })

      
    }

  }
Copy the code

When the classified data is retrieved, the data is stored in the local cache

2.4 Optimized the classification page

When clicking on each left category, the right content page is displayed at the top

2.5 Defining Public Interfaces

export const request=(params) = >{
  // Define the public URL
  / / url:https://api-hmugo-web.itheima.net/api/public/v1
  const baseUrl ='https://api-hmugo-web.itheima.net/api/public/v1'
  return new Promise((resolve,reject) = >{ wx.request({ ... params,url:baseUrl+params.url,
     success:(result) = >{
     resolve(result);
     },
     fail:(err) = >{ reject(err); }})})}Copy the code

2.6 Support ES7 async syntax in applets

3 Commodity List

3.1 Realizing page hopping and parameter transfer (category ID)

The parameters passed are in options in the onLoad lifecycle function of the goods list

3.2 Implement the search box and tabs components

Custom components, the method is similar to the above custom components, here to illustrate the GIF

3.3. Static structure of the list of goods

Write with a static image first, adjust the style, and then process dynamically

HTML:

<SearchInput></SearchInput> <! -- Listen for custom events --><Tabs tabs="{{tabs}}" bindtabsItemChange="handleTabsItemChange" >
  
  <block wx:if="{{tabs[0].isActive}}">
    <view class="first_tab">
        <navigator class="goods_item"
        wx:for="{{goodsList}}"
        wx:key="goods_id"
        url="/pages/goods_detail/index? goods_id={{item.goods_id}}"
        >
            <! -- Left image container -->
            <view class="goods_img_wrap">
              <image mode="widthFix" src="{{item.goods_small_logo? item.goods_small_logo:'https://ww1.sinaimg.cn/large/007rAy9hgy1g24by9t530j30i20i2glm.jpg'}}"></image>
            </view>
            <! -- Right commodity container -->
            <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}}">sales</block>
  <block wx:elif="{{tabs[2].isActive}}">The price</block>

</Tabs>
Copy the code

css:

/* pages/goods_list/index.wxss */
.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: 70%;
}
.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(--themeColor);
  font-size: 32rpx;
}

Copy the code

3.4 Loading Data on the next page

Effect:

3.5 Drop-down Refresh

Effect:

3.6 Adding the Global Loading icon Effect

Effect:

4 Product details page

4.1 Obtaining product details data

4.2 Render the product details page (including the rote map, etc.)

<! --pages/goods_detail/index.wxml--><view class="goods_detail">
  <view class="detail_swiper">
    <! -- Rotation chart start -->
    <swiper autoplay interval="3000" circular indicator-dots indicator-color='skyblue'>
    <swiper-item wx:for="{{goodsObj.pics}}"  wx:key="pics_id">
      <image mode="widthFix" src="{{item.pics_mid}}"></image>

    </swiper-item>
  </swiper>
 </view>
  <! -- End of rotation chart -->
  <! -- Commodity prices start -->
  <view class="goods_price">${{goodsObj. Goods_price}}</view>
  <! -- End of commodity prices -->
<! -- Commodity name + Start of collection -->
<view class="goods_name_row">
    <! -- Commodity name -->
    <view class="goods_name">
        {{goodsObj.goods_name}}
    </view>
    <view class="goods_collect">
        <text class="iconfont icon-shoucang"></text>
        <view class="collect_text">collection</view>
          
    </view>
</view>
<! -- Commodity name + End of collection -->

<! -->
<view class="goods_info">
    <! - the title -- -- >
    <view class="goods_info_title">Graphic details</view>
    <! - content - >
    <view class="goods_info_content">
        <! -- Rich text -->
        <rich-text class="" nodes="{{goodsObj.goods_introduce}}">
            
        </rich-text>
          
    </view>
</view>

<! -- End of graphic details -->

</view>

Copy the code

Style:

/* pages/goods_detail/index.wxss */
.goods_detail .detail_swiper swiper {
  height: 65vw;
  text-align: center;
}
.goods_detail .detail_swiper swiper image {
  width: 60%;
}
.goods_detail .goods_price {
  padding: 15rpx;
  font-size: 32rpx ;
  font-weight: 600;
  color: var(--themeColor);
}
.goods_detail .goods_name_row {
  border-top: 5rpx solid #dedede;
  border-bottom: 5rpx solid #dedede;
  padding: 10rpx 0;
  display: flex;
}
.goods_detail .goods_name_row .goods_name {
  flex: 5;
  color: #000;
  font-size: 30rpx;
  padding: 0 10rpx;
  display: -webkit-box;
  overflow: hidden;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
}
.goods_detail .goods_name_row .goods_collect {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  border-left: 1rpx solid #000;
}
.goods_detail .goods_info .goods_info_title {
  font-size: 32rpx;
  color: var(--themeColor);
  font-weight: 700;
  padding: 20rpx;
}


Copy the code

Js:

// Get commodity details data
    async getGoodsDetail(goods_id) {
        const goodsObj = await request({ url: "/goods/detail".data: { goods_id } })
        this.setData({
                // Since this data is only used, it is only needed to be saved for better performance
                goodsObj: {
                    pics: goodsObj.pics,
                    goods_name: goodsObj.goods_name,
                    goods_price: goodsObj.goods_price,
                    // Convert image format, compatible with iPhone
                    goods_introduce: goodsObj.goods_introduce.replace(/\.webp/g.'.jpg')}})// console.log(this.data.goodsObj);
    }
Copy the code

Effect:

4.4. Enlarge preview image

The urls in this API will display as many links as they contain in them

Effect:

4.5. Bottom toolbar

<! Start from bottom toolbar --><view class="btm_tool">
  <view class="tool_item">
    <view class="iconfont icon-kefu"></view>
    <view>Customer service</view>
    <button open-type="contact"></button>
  </view>
  <view class="tool_item">
    <view class="iconfont icon-yixianshi-"></view>
    <view>share</view>
    <button open-type="share"></button>
  </view>
  <navigator open-type="switchTab" url="/pages/cart/index" class="tool_item">
    <view class="iconfont icon-gouwuche"></view>
    <view>The shopping cart</view>
  </navigator>
  <view class="tool_item btn_cart " bindtap="handleCartAdd">Add to shopping cart</view>
  <view class="tool_item btn_buy">Buy now</view>
</view><! End of bottom toolbar -->Copy the code

css:

// Bottom toolbar style
.btm_tool{
    border-top: 1rpx solid #ccc;
    position: fixed;
    left: 0;
    bottom: 0;
    width: 100%;
    height: 90rpx;
    background-color: #fff;
    display: flex;
    .tool_item{
      flex: 1;
      display: flex;
      flex-direction: column;
      justify-content: center;
      align-items: center;
      font-size: 24rpx;
      position: relative;
      button{
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        opacity: 0;
      }
    }
    .btn_cart{
      flex: 2;
      display: flex;
      flex-direction: column;
      justify-content: center;
      align-items: center;
      background-color: #ffa500;
      color: #fff;
      font-size: 30rpx;
      font-weight: 600;
    }
    .btn_buy{
      flex: 2;
      display: flex;
      flex-direction: column;
      justify-content: center;
      align-items: center;
      background-color: #eb4450;
      color: #fff;
      font-size: 30rpx;
      font-weight: 600; }}Copy the code

The button is used in very few seconds, to avoid the style effects of the button, so it is set this way

Effect:

4.6. Add to shopping cart

There are currently no interfaces, only local storage

// Click add to cart
    handleCartAdd() {
        // 1. Get the cart array in the cache
        let cart = wx.getStorageSync('cart') | | [];// 2. Check whether the item object exists in the cart
        let index = cart.findIndex(v= > v.goods_id === this.goodsInfo.goods_id);
        if (index === -1) {
            // 3. The product is added for the first time because it does not exist
            this.goodsInfo.num = 1;
            cart.push(this.goodsInfo)
        } else {
            // 4. Execute num++ if shopping cart data already exists
            cart[index].num++
        }
        // 5. Add the shopping cart back to the cache
        wx.setStorageSync("cart", cart);
        / / 6. Popup window
        wx.showToast({
            title: 'Join successful'./ / image stabilization
            icon: 'sucess'.mask: true
        });
    }
Copy the code

5. The shopping cart

Effect: