Some time ago, with Ma Huateng appeared in many places across the country with micro channel small program to take the bus news, micro channel small program heat can be said to be more on a layer. Wechat small programs appear so far, because of its convenience without downloading can be used and other advantages, the development trend has been good.

The launch of Hema Xiansheng is also full of enthusiasm, realizing fast delivery, which can be described as alibaba’s complete reconstruction of offline supermarkets in the new retail format.

What happens when two things that are so convenient collide?

Recently I happened to be learning wechat applets, so I adapted a wechat applets according to Hema Xiansheng APP.

GitHub source address is at the end of this article, I will continue to update and improve the small program. If you are also interested in this micro channel small program, welcome to exchange, learn together.

Function introduction

In line with the concept of convenience, the main functions of mall APP have been realized.

  • Users can click on different categories of goods, jump to the page to see the list of various goods.
  • Click the goods can be added to the shopping cart, in the shopping cart can also realize the increase or decrease of the number of goods, all anti-selection of goods, delete shopping cart goods and other operations.
  • On the home page, click the button in the upper left corner to add a default shipping address.
  • Click the “Scan” icon in the upper right corner to scan the QR code (the GIF below is the effect of the simulator, which can only be scanned by opening the picture in the computer, but can be scanned by opening the camera on the real machine).
  • On the home page, picture rotation and automatic switching are realized at the top, and the scrolling view is realized at the bottom, which can slide horizontally to display commodity information. Let’s take a look at the renderings first, and we’ll talk more about how each point is implemented later.

Page description

This paper mainly introduces the main interface information of the small program, shows several page jumps and commodity list information. Please pay attention to the picture rotation at the top of the home page and the horizontal scrolling view at the bottom.

About shopping cart operation

Add items to shopping cart.

Add default shipping address and qr code scan

Added the receiving address.


Detailed explanation of function implementation

Home page picture rotation and bottom scrolling view

Wechat mini program has its own component swiper view container, which can realize the swiper view. Each view is placed in a Swiper-Item. Set the parameter auto:play to automatically play the swiper.

<swiper class="page__bd__scroll" current='{{activeIndex}}' bindchange='swiperTab' autoplay="true" interval="2000" duration="1000"<swiper-item> <image class= <swiper-item> <image class="page__scroll__item" src=""/>
  </swiper-item>
  <swiper-item>
    <image class="page__scroll__item" src=""/>
  </swiper-item>
  <swiper-item>
    <image class="page__scroll__item" src=""/>
  </swiper-item>
  <swiper-item>
    <image class="page__scroll__item" src=""/>
  </swiper-item>
  <swiper-item>
    <image class="page__scroll__item" src=""/>
  </swiper-item>
</swiper>
Copy the code

Horizontal scrolling view implementation:

The built-in component of wechat can scroll the scroll-view area. You can scroll the view horizontally or vertically by setting the property name scroll-x or scroll-y.

<scroll-view scroll-x class= <scroll-view scroll-x class="scrollx-section__content"< span style = "box-sizing: border-box; color: RGB (51, 51, 51); line-height: 20px; font-size: 14px! Important; word-break: inherit! Important;" <block wx:for="{{scrollXList}}" wx:key="index" wx:for-index="index">
    <view class="scrollx-section__content__item">
      <view class="scrollx-section__item__wrapper">
        <view class="view__wrapper__image">
            <image src="https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2017/12/15/16057cf8f3865280~tplv-t2oaga2asx-image.image" />
        </view>
        <view class="view__wrapper__intro">
          <view class="wrapper__intro__title">
            <text>{{item.name}}</text>
            <text>{{item.secName}}</text>
          </view>
          <view class="wrapper__intro__content left">
            <text>{{item.leftTitle}}</text>
            <text>{{item.leftSecTitle}}</text>
          </view>
          <view class="wrapper__intro__content right">
              <text>{{item.rightTitle}}</text>
              <text>{{item.rightSecTitle}}</text>
          </view>
          <view class="wrapper__intro__price"> < a > ${{item. Price}} < / a > < a > / {{item. The unit}} < / a > < a id ="{{index}}" bindtap="addInCart">+</a>
          </view>
        </view>
      </view>
    </view>
  </block>
</scroll-view>
Copy the code

About shopping cart operation

Add items to shopping cart

In different pages according to the classification information can jump to different pages to enter the commodity list, for example, in the home page and classification page, can enter different commodity list according to the classification information, add the commodity to the shopping cart. If you want to get the shopping cart list information in the home page, commodity classification interface and shopping cart multiple interfaces, the data scope of a single page is only in this folder, how to operate the same data in multiple pages?

We can set a global variable in app.js, and then introduce this global data in each page, so that multiple pages can share one data.

GlobalData: {cardList: [], goodsSortsChoice: null}Copy the code

Here I set up two global variables. CardList is shopping cart data, and when the user clicks on the item to add to the cart, they add the item to the array. GoodsSortsChoice is a tag. There are different classification introductions on the home page and the classification interface. The mark can remember which category the user clicked on in the classification interface, and then jump to the commodity display interface according to the user’s click to display different information.

In the product list interface, add a click event addCount to the shopping cart option for each item. At the same time, to determine which item the user clicked on, add an index to each item. Here, WHEN I loop through the background product list data, Dynamically bind each loop with data-index=”index”, and set an ID =”{{index}}” for each “+”, click to judge.

<block wx:for="{{goods}}" wx:key="index" wx:for-index="index">
    <view class="weui-cells">
        <view class="weui-cell">
            <view class="weui-cell__hd">
                <image src="https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2017/12/15/16057cf8f3865280~tplv-t2oaga2asx-image.image" />
            </view>
            <view class="weui-cell__bd">
                <view class="goodsList__bd__intro">{{item.name}}</view>
                <view class="view__bd__price">
                    <text class="price left"> ${{item. Price}} / {{item. The unit}} < / text > < text class ="add right" bindtap="addInCart" id="{{index}}">+</text>
                </view>
            </view>
        </view>
    </view>
</block>
Copy the code

The js part is the addInCart method that implements adding items to the cart. Here, before adding the goods to the shopping cart, the existing shopping cart array should be traversed to judge. If the goods are already in the shopping cart, the quantity of the goods in the shopping cart will be directly increased by one; otherwise, the goods will be directly added to the global shopping cart array.

addInCart: function(e) { const good = this.data.goods[e.currentTarget.id]; Const cart = app.globalData. CardList; // Set a flag to determine whether the item the user wants to add to the cart already exists in the cartfalse; // some is a new es6 method that iterates through an array and returns if there is one or more elements in the arraytrue
  flag = cart.some((item) => {
    returnitem === good; }) console.log(flag); // If the element is not in the cart, add the item to the cart, otherwise add the purchase quantity of the item by oneif(! flag) { cart.push(good); // Add the item to the shopping cart list after the user selects it.'Goods added to cart',
      icon: 'success',
      duration: 2000
    })
  } else{// Add this.data.goods[e.currenttarget.id].count ++; }},Copy the code

Wx. showToast is a Built-in API of wechat, which can display a pop-up window in the page.

Increase or decrease the number of items in your shopping cart

The idea is to bind the plus and minus signs with two click events, addCount and reduceCount respectively, and add index index for the plus and minus signs to judge which goods the user clicks when the loop outputs the items in the shopping cart list.

<block wx:for="{{goodsList}}" wx:key="index" data-index="index">
    <view class="weui-cell">
        <view class="weui-cell__hd">
            <icon id="{{index}}" bindtap="selectGoods" type="{{item.type}}" color="#23a3ff"></icon>
        </view>
        <view class="weui-cell__bd">
            <image src="https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2017/12/15/16057cf8f3865280~tplv-t2oaga2asx-image.image" />
        </view>
        <view class="weui-cell__ft right">
            <text class="proIntr left">{{item.name}}</text>
            <text class="price left"> ${{item. Price}} / {{item. The unit}} < / text > < the view class ="count">
                <text class="reduce left" bindtap="reduceCount" id="{{index}}">-</text>
                <text class="number left">{{item.count}}</text>
                <text class="add left" bindtap="addCount" id="{{index}}">+</text>
            </view>
        </view>
    </view>
</block>
Copy the code

Js:

// Increase the number of items addCount:function(e) { var that = this; Const goodId = e.currenttarge. id; // Get the user clicked on an item based on the click event const goodId = e.currenttarge. id; that.data.goodsList[goodId].count++; This.setdata ({goodsList: that.data.goodslist}) // Recalculate the total amount of shopping cart each time you add or remove an item this.sumMoney(); }, // Reduce the number of goods reduceCount:function(e) {
  var that = this;
  const goodId = e.currentTarget.id;
  if(that.data.goodsList[goodId].count <= 1) {
    that.data.goodsList[goodId].count = 1;
    wx.showModal({
      title: 'Quantity less than 1',
      content: 'Operation not allowed',
      duration: 2000
    })
  } else{ that.data.goodsList[goodId].count--; } this.setData({goodsList: that.data.goodslist}) // This.sumMoney(); },Copy the code

Calculation of the total price of shopping cart items

For the selected item, call sumMoney() to calculate the total price. The method is to traverse the goods in the shopping cart, get the unit price and number of each item, multiply and add.

// Count all items sumMoney:functionVar count = 0; // goods is an item in the shopping cart, counting the price const goods = this.data.goodslist;for(let i = 0; i < goods.length; i++) {
    count += goods[i].count*goods[i].price;
  }
  this.setData({
    sum: count
  })
},
Copy the code

Full selection and reverse selection of goods

One of the most important differences between selected and unselected items displayed in a list is whether the item is preceded by a blue tick or a hollow dot.

Therefore, you need to set a state for the items in the shopping cart and change the style of the interface. For this status value, it is required before loading the shopping cart, so first I want to add a status value for each item in the background data. However, this has a major disadvantage. For this state value, only the shopping cart interface needs it, which is unnecessary for other interfaces. Adding one more data to the background means changing all the background item data, increasing the complexity of the implementation. Then I thought of another way. Before loading the shopping cart interface, first go through the shopping cart and add an attribute type=”success” for each shopping cart (the nice thing about setting type parameter: Success and circle class name are a status value of wechat component icon, which can display small check marks or hollow dots). The shopping cart onload method iterates through the items in the shopping cart and adds the state type:

onLoad: function (options) {
  const cardList = app.globalData.cardList;
  cardList.map(item => {
    item.type = "success";
  });
},
Copy the code

Front stage interface display part:

<icon id="{{index}}" bindtap="selectGoods" type="{{item.type}}" color="#23a3ff"></icon>
Copy the code

In this way, the method of dynamically changing the state of the commodity is realized. We can create a method that walks through the items in our shopping cart, and if all of them are selected, put all of them on the checkbox.

// Select allSelected:function() { const goods = this.data.goodsList; // some is a new method in ES6 that will return if at least one of the array matches the criteriatrue
  var symbol = goods.some(good => {
    return good.type === "circle"}) // If there is an unselected item in the shopping cart, the all-selected state is a hollow circleif(symbol) {
    this.data.allStatus = "circle"
  } else{// If all items in the cart are selected, the selected status is a check this.data.allStatus ="success"
  }
  this.setData({
    allStatus: this.data.allStatus
  })
},
Copy the code


<view class="shopping__ft">
    <view class="shopping__ft__hd"> <! SelOrUnsel --> <icon bindtap="selOrUnsel" type="{{allStatus}}" color="#23a3ff"></icon> All </view> <view class="shopping__ft__bd"Combined > < text > : < / text > < text > ${{sum}} < / text > < / view > < the view class ="shopping__ft__ft" bindtap="sumMoney"</view>Copy the code

Js:

selOrUnsel: functionConst status = this.data.allStatus; const status = this.data.allStatus; const goods = this.data.goodsList; // Click the button to view the status of the current full selection box, change it to reverse, and select all or reverse selection of goodsif(status === "success") {// If the all button is selected before, it becomes a hollow circle this.data.allStatus ="circle"; Goods. map(good => {good.type ="circle"; })}else {
    this.data.allStatus = "success"; // If the select all button is not selected before clicking, select all. Map (good => {good.type ="success"; This.setdata ({goodsList: this.data.goodslist}) this.setData({allStatus: this.data.allStatus }) },Copy the code

Delete items from shopping cart

There is a delete in the upper right corner of the shopping cart interface to delete selected items. First add a click event delGoods to delete. :

<view class="shopping__hd">
    <view class="shopping__hd__content">
        <view class="shopping__title"> shopping cart <a class="shopping__title__delete right" bindtap="delGoods"</a> </view> </view>Copy the code

Js implements the delGoods method, which stores the selected goods to be deleted in an array, iterates through the array of goods to be deleted, and deletes them one by one using splice method.

// Delete delGoods:function() { const goods = this.data.goodsList; Const selGoods = goods.map(good => {) const selGoods = goods.map(good => {if(good.type === "success") {
      return good;
    }
  })
  wx.showModal({
    title: "Sure you want to delete the selected item?", success: (res) => {// Click OKifSelgoods.map (sel => {goods.splice(sel); selgoods.splice (sel); }} this.setData({goodsList: this.data.goodslist})}}else if (res.cancel) {

      }
    }
  })
},
Copy the code

Add a default shipping address

In the upper left corner of the home page there is a small dot that can be clicked to add the default shipping address.

Adding the default delivery address also requires uploading values on multiple pages, because the display of the default address is not the same as setting the default address. Considering that the default delivery address needs to be stored in the user’s personal information for a long time, we used storage for data storage this time.

Without further ado, to implement the function, bind an event chooseAddr first.

<! --> <view class="page__hd__input-left left">
  <image src="https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2017/12/15/16057cf8f81b6d70~tplv-t2oaga2asx-image.image" bindtap="chooseAddr" />
</view>
Copy the code

Jump to the default shipping address display interface, here can display the entered shipping address

chooseAddr: function() {
  wx.navigateTo({
    url: ".. /chooseAddress/chooseAddress"})},Copy the code

In the display of the default shipping address interface, there is a button in the upper right corner, you can add the shipping address, so let’s jump back to the page to set the default shipping address interface.

<! --> <view class="choose-addr__hd">
    <text class="choose-addr__title"> select the shipping address </text> <text class="choose-addr__add right" bindtap="addNewAddr"> Add new address </text> </view>Copy the code
// I want to jump to set the default shipping address addNewAddr:function() {
  wx.navigateTo({
    url: ".. /newAddr/newAddr"})},Copy the code

On the interface of setting the default delivery address, set the input change event bindinput for each input box to obtain the contents of the input box.

<view class="newAddr__bd">
    <view class="weui-cells weui-cells_form gray-input">
        <view class="weui-cell">
            <view class="weui-cell__hd">
                <text class="weui-label mr60"</text> </view> <view class="weui-cell__bd">
                <input bindinput="getAddress" class="weui-input" placeholder="Please enter delivery address" />
            </view>
        </view>
        <view class="weui-cell">
            <view class="weui-cell__hd">
                <text class="weui-label mr94"> </text> </view> <view class="weui-cell__bd">
                <input bindinput="getNum" class="weui-input" placeholder="House number" />
            </view>
        </view>
    </view>
    <view class="weui-cells weui-cells_form second-weui-cells">
        <view class="weui-cell">
            <view class="weui-cell__hd">
                <text class="weui-label mr48"> Contact </text> </view> <view class="weui-cell__bd">
                <input bindinput="getName" class="weui-input" placeholder="Contact" />
            </view>
        </view>
        <view class="weui-cell">
            <view class="weui-cell__hd">
                <label class="weui-label mr44"</label> </view> <view class="weui-cell__bd">
                <input bindinput="getPhone" class="weui-input" placeholder="Please enter your mobile phone number." />
            </view>
        </view>
    </view>
</view>
Copy the code

The input change event gets the contents of the input box:

data: {
  address: ' ',
  num: ' ',
  name: ' ',
  phone: ' '
},

getAddress: function(e) {
  this.setData({
    address: e.detail.value
  })
},
getNum: function(e) {
  this.setData({
    num: e.detail.value
  })
},
getName: function(e) {
  this.setData({
    name: e.detail.value
  })
},
getPhone: function(e) {
  this.setData({
    phone: e.detail.value
  })
},
Copy the code

Dangdang when! Said so much, storage storage data focus come!

WXML interface, set a click event saveInfo, click to save the data:

<view class="newAddr__hd">
    <text class="newAddr__add left" bindtap="backToChooseAddr"</text> <text class="newAddr__title"> select the shipping address </text> <text bindtap="saveInfo" class="newAddr__add right"> Save </text> </view>Copy the code

Wechat provides an API: wx.setStorage can store data in the cache in the form of key value (data) pairs.

Key is the specified key in the local cache, data is the content to be stored, and SUCCESS is the callback function for the successful invocation of the interface.

// After the user clicks save, the input data will be saved and the storage status will be feedback saveInfo:function() {
  wx.setStorage({
    key: "name",
    data: [{address:this.data.address}, {num: this.data.num}, {name: this.data.name}, {phone: this.data.phone}],
    success: function() {// After the data is set successfully, the popup box prompts that the user information is saved completely and jumps back to the interface showing the default address."Address saved successfully",
        icon: 'success',
        duration: 2000
      })
      setTimeout(function(){
        wx.navigateTo({
          url: ".. /chooseAddress/chooseAddress"})}, 1000); }})Copy the code

After the data is set successfully, go back to the page that displays the default address. In this case, we want to fetch the data in the cache.

Wechat provides an API: wx.getStorage asynchronously retrieves the contents of a specified key from the local cache. Key is the key specified in the local cache, and SUCCESS is the callback function invoked by the interface.

onShow: function () {
  var that = this;
  wx.getStorage({
    key: "name",
    success: function(res) {
      if(res.data.length > 0) {
        that.setData({
          address: res.data[0].address,
          num: res.data[1].num,
          name: res.data[2].name,
          phone: res.data[3].phone
        })
      }
    }
  })
},
Copy the code

Scan the QR code

In the top right corner of the home page, there is a scan picture, click to scan the QR code.

Bind this image with a click event scan:

<view class="page__hd__input-right left">
  <image bindtap="scan" src="https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2017/12/15/16057cf8f3b9287a~tplv-t2oaga2asx-image.image" />
</view>
Copy the code

Call wechat’s own API: wx.scanCode to scan the QR code.

scan: function() {
  wx.scanCode({
    success: (res) => {
      console.log(res)
    }
  })
},
Copy the code

The background data

For the source of the background data, I use EasyMock to build the mock data. Easymock is super handy for programmers who just focus on the foreground interface for now. I wrote earlier about building Mock data using Easy Mock.

Write in the last

Perhaps the most important part of writing wechat applets is checking documents. Wechat provides developers with a detailed introduction and use of various components and apis.

Attached is the wechat applets development document

Finally in making the source address: https://github.com/TeanLee/hema

If you feel good, please give a start to encourage ~

This small program I will continue to update, welcome criticism, guidance, exchange: