初學微信小程序實戰-簡易小米商城

前言

做爲一名前端初學者,前段時間學習了關於微信小程序的內容,以爲頗有意思,忍不住本身動手擼了一個小米商城的微信小程序。固然,是不完整的,由於如出一轍實太大了(┬_┬),只是簡單完成了基本功能和幾個分類商品頁面。因爲找不到小米的數據接口,因此這個小程序裏全部的數據都是我本身寫的,在EasyMock裏。所以有些圖片和數據看起來會有些不協調,這也是我第一次作一個比較完整的項目,不足之處但願你們多多包涵。寫下這篇文章既是對本身這段時間學習微信小程序的總結和回顧,也但願對看到這篇文章的微信小程序初學者有所幫助。css

工具

  • 微信開發者工具
  • Easy Mock(我本身寫的數據,有接口的能夠直接使用接口)
  • 微信小程序官方文檔
  • 阿里巴巴矢量庫(圖標)
  • 官方小米商城微信小程序(模仿)

小程序部分功能展現

基本結構

  • components 自定義組件
  • images 小程序圖標和圖片
  • pages 頁面
  • 配置文件

tabbar

tabbar的配置須要在微信小程序的根文件app.json中配置(圖片名字請忽略(┬_┬))html

app.json前端

"tabBar": {
    "selectedColor": "#ff6700",
    "color": "#666666",
    "borderStyle": "black",
    "list": [
      {
        "pagePath": "pages/index/index",
        "text": "首頁",
        "iconPath": "./images/system-icon/首頁.png",
        "selectedIconPath": "./images/system-icon/首頁1.png"
      },
      {
        "pagePath": "pages/classify/classify",
        "text": "分類",
        "iconPath": "./images/system-icon/分類.png",
        "selectedIconPath": "./images/system-icon/分類1.png"
      },
      {
        "pagePath": "pages/discover/discover",
        "text": "發現",
        "iconPath": "./images/system-icon/發現.png",
        "selectedIconPath": "./images/system-icon/發現1.png"
      },
      {
        "pagePath": "pages/cart/cart",
        "text": "購物車",
        "iconPath": "./images/system-icon/購物車.png",
        "selectedIconPath": "./images/system-icon/購物車1.png"
      },
      {
        "pagePath": "pages/user/user",
        "text": "個人",
        "iconPath": "./images/system-icon/個人.png",
        "selectedIconPath": "./images/system-icon/個人1.png"
      }
    ]
  },
複製代碼

頭部導航欄

由於官方小米商城小程序並無自定義導航欄,並且如今支持單頁設置,因此我也只是在每一個頁面單獨設置了名字和基本樣式,在每一個頁面的app.json裏直接添加下面幾個定義導航欄的屬性git

效果程序員

app.json

{
  "usingComponents": {},
  "navigationBarBackgroundColor": "#f8f8f8",
  "navigationBarTextStyle": "black",
  "navigationBarTitleText": "手機頻道",
  "backgroundColor": "#eeeeee",
  "backgroundTextStyle": "light"
}
複製代碼

首頁

搜索商品

由於數據都是本身寫的,因此搜索也沒有api能夠用了(┬_┬),只能本身寫了,在網上找了很久應該怎麼寫搜索,最後仍是問了大佬同窗纔有了個思路,將全部商品數據都放在一個數組裏,經過匹配關鍵詞篩選出匹配的商品。github

由於數據都寫在EasyMock裏,經過搜索頁面input輸入框bindkeyInput函數實時獲取到輸入的關鍵詞(e.detail.value),經過模板字符串動態傳入關鍵詞到Easy Mock裏傳回匹配的數據。json

html小程序

<input class="input" maxlength="10" bindinput="bindKeyInput" placeholder="輸入關鍵詞" />
複製代碼

js微信小程序

//獲取輸入框輸入的關鍵詞匹配搜索數據
  bindKeyInput: function (e) {
    this.setData({
      inputValue: e.detail.value
    })
    wx.request({
      url: `https://www.easy-mock.com/mock/5d030bd22c61271f2b41de46/search?goodsname=${e.detail.value}`,
      success: (res) => {
        this.setData({
          searchgoods:res.data.data
        })
      }
    })
  },
複製代碼

Easy Mock _data=[] 存放的是全部能夠搜索到的商品數據,太多我就不放了,經過正則匹配關鍵詞返回符合條件的數組data,沒有匹配項返回空數組並在下面使用for循環換渲染出來api

Easy Mock搜索接口

{
  "success": true,
  "data": function({
    _req,
    Mock
  }) {
    let i = 0,
    _data=[],
     goodsname = _req.query.goodsname;
    if (goodsname != '') {
      let data = []
      for (let j = 0; j < _data.length; j++) {
        if (eval('/' + goodsname + '/').test(_data[j].goodsname)) {
          data.push(_data[j])
        }
        if (data.length > 8) break;
      }
      return data
    } else {
      return []
    }
  },
  "msg": "數據請求成功"
}
複製代碼

由於_data數組裏放了全部商品的所有數據,所以在點擊下面搜索項時我寫了個點擊函數toDetail將經過index拿到的具體商品數據存入了全局app.js裏的goodsdetail數組裏,而後在商品詳情頁拿到這個數組裏的數據來渲染詳情頁

//將商品詳情存入全局變量goodsdetail
toDetail:function(e){
    var index = e.currentTarget.dataset.index;
    app.goodsdetail = this.data.searchgoods[index];

    wx.navigateTo({
      url: '/pages/goods/goods',
    })
  },
複製代碼

搜索基本就寫了這麼多,如今寫的時候回頭看其實還有歷史記錄啥的都沒寫o(︶︿︶)o ,仍是有不少能夠修改,但在這裏俺就不說這些沒用的了。

swiper 展現熱門商品

通常首頁的輪播圖都是用來展現最近的熱賣商品,也是一個電商平臺必不可少的東西,能讓用戶第一時間瞭解新產品和熱銷商品。我在輪播圖中加了點擊事件跳轉詳情頁,方法跟上面同樣,直接上代碼:

html

<swiper indicator-dots="true" autoplay="true" interval="{{interval}}" duration="{{duration}}" circular="true" bindchange="swiperChange">
      <block wx:for="{{imgUrls}}" wx:key="{{index}}">
        <swiper-item>
          <image src="{{item.url}}" class="slide-image" width="100%" bindtap="toDetail" />
        </swiper-item>
      </block>
    </swiper>
複製代碼

js

//輪播圖的切換事件
  swiperChange: function (e) {
    // console.log(e.detail.current)
    this.setData({
      swiperCurrent: e.detail.current
    })
  },
  //輪播圖點擊事件
  toDetail:function(e){
    var index = this.data.swiperCurrent;
    let detail = this.data.imgUrls[index];
    app.goodsdetail = detail;
    this.setData({
      detail: detail
    })
    wx.navigateTo({
      url: '/pages/goods/goods',
    })
  },
複製代碼

分類

這裏展現的是平臺上全部商品的大分類,經過點擊能夠進入相應的分類頁面,都是些結構和樣式,關鍵是經過浮動佈局給擠上去 float:left。

html

<view class='goods-classify'>
    <view class='classify-list' wx:for="{{classlist}}" wx:key="{{index}}">
      <navigator url='{{item.url}}' hover-class='other-navigator-hover'>
        <image src='{{item.imgsrc}}'></image>
        <view class='classify-text'>
          <text>{{item.text}}</text>
        </view>
      </navigator>
    </view>
  </view>
複製代碼

商品列表

由於這裏是我寫的第一段商品列表,以前也沒寫過相似須要渲染多組數據的,在這裏犯了很大錯誤,商品列表的每個不一樣樣式的商品的結構和樣式都是直接擼。一開始爲了寫商品列表左右兩邊的樣式,強行在數據裏把兩組商品數據放進了商品數組每一項中,雖然最後仍是實現了功能,可是極其麻煩(由於兩邊要分別寫html,css和點擊事件的js,數據結構根本不成樣子),原本想放代碼,看了看實在太多,並且很醜陋及繁雜,這裏就不放了。如今看還不如直接分兩邊盒子寫出商品列表錯開的效果,看起來更酷炫,但願剛開始學習微信小程序的朋友引覺得戒(不過應該也沒有人跟我同樣犯這種低級錯誤吧(┬_┬));

以後的組件化商品列表

以前的錯誤讓我懊惱了很久,也意識到這樣寫的效率過低,由於是電商平臺,不論是分類仍是推薦,大多數都是商品列表,只不過可能不一樣的分類風格樣式不同。因而我就想把商品列表寫成一個組件,只要以後須要用到商品列表的時候,就能夠把不一樣樣式的商品列表組件放上去從新渲染數據就行。

商品列表組件 html

<view class='goodsList' wx:for='{{goodsList}}' wx:key='{{index}}'>
  <view class='bgcline'></view>
  <view class=" {{item.big ? 'big' : 'goods-Box'}}" data-index='{{index}}' bindtap='toDetail' style=''>
    <image src="{{item.url}}" />
    <view class="goodsText">
    <view class='box-left'>
      <text class="title">{{item.goodsname}}</text>
      <text class="disc">{{item.goodsspecial}}</text>
    </view>
    <view class='box-right'>
      <text class="price">¥{{item.goodsprice}}</text>
      <view class='lijibuy'>
        <view class='buy-box'>
          <view class='text-box'>
            <text>{{item.buy}}</text>
          </view>
        </view>
      </view>
      </view>
    </view>
  </view>
</view>
複製代碼

以前寫重點推薦商品時,每一個大圖都要從新寫樣式和結構太麻煩了。在這個組件裏我添加了一個判斷條件,判斷在每條數據中是否有big屬性,若是爲true,就添加一個類名,使用大圖的樣式,若是沒有,則使用另外一套小圖的樣式。

js

const app = getApp()
Component({
  properties: {
    goodsList:{
      type:Object,
      value:[]
    },
    detail:{
      type: Object,
      value: []
    }
  },
  data: {
  },
  methods: {
    toDetail: function (e) {
      const goodslist = this.data.goodslist
      var index = e.currentTarget.dataset.index;
      var detail = this.properties.goodsList[index];
      app.goodsdetail = detail;
      this.setData({
        detail
      })
      wx.navigateTo({
        url: '/pages/goods/goods',
      })
    },
  }
})
複製代碼

分類

分類分爲左右兩個scroll-view。經過點擊獲取當前id和index,改變toView和curIndex的值來實現兩邊的互動,右邊經過計算滾動的高度來計算大概的區域計算curIndex進行定位。

html

<scroll-view class='classify-left'>
    <view wx:for="{{classify}}" wx:key="{{classify.id}}" data-id='{{item.id}}' data-index='{{index}}' bindtap='scrollleft' class="classify-list {{curIndex == index ?'on':'' }}">
      {{item.name}}
    </view>
  </scroll-view>
  <scroll-view class='classify-right' scroll-y scroll-into-view="{{toView}}" scroll-with-animation="{{scrollanimation}}" bindscroll="scrollright">
    <block wx:for="{{clsgoods}}" wx:key="{{item.title}}">
      <view class='classify-box' id='{{item.id}}'  data-index1="{{index}}" bindtap="getindex" id="{{item.id}}">
        <view class="classify-title">
          <text>{{item.title}}</text>
        </view>
          <view class='product-list' wx:for="{{item.detail}}" wx:for-item="product" wx:key="{{index}}" bindtap='toDetail' data-index2="{{index}}" data-id='{{item.id}}'>
              <image src='{{product.url}}'></image>
              <view class='product-name'>
                <text>{{product.goodsname}}</text>
              </view>
          </view>
      </view>
    </block>
  </scroll-view>
複製代碼

js

//左邊scroll-view的bindscroll方法
scrollleft(e) {
    this.setData({
      toView: e.target.dataset.id,
      curIndex: e.target.dataset.index
    })
  },
//右邊scroll-view的bindscroll方法
  scrollright(e) {
    let index = Math.floor(e.detail.scrollTop / 500);
    this.setData({
      curIndex: index
    })
  },
複製代碼

點擊進入詳情頁時仍是以前的方法,經過id和index定位當前商品,將數據傳遞給全局變量goodsdetail,以後在商品詳情頁獲取goodsdetail數據渲染

商品詳情頁

做爲一個電商小程序最重要的固然是商品,可是每一個商品的詳情頁不可能每一個都寫,這時候就要利用數據來渲染,上面已經說過,每次點擊商品時,會將當前點擊的商品數據傳入全局變量goodsdetail中,而後在打開詳情頁時拿到它渲染頁面

商品數據

展現商品是最顯眼的就是圖片和視頻,因此這裏放的是一個swiper,可是我每條數據裏都只放了一張圖片地址,因此只有一張圖片輪播,有多的圖片只要放在數據源的swiper裏就行。

地理位置

這裏選擇地理位置採用的是微信的一個api 點擊能夠進入一個頁面選擇地址,而且能夠搜索地址

js

// 選擇位置
  selectLocation: function(e) { //自行定義tap事件
    var that = this
    wx.chooseLocation({ //微信API--打開地圖選擇位置。
      success: function(res) { //成功以後,返回四組參數
        console.log(res.address)  
        that.setData({
          address: res.address     // 我這裏只返回了詳細地址
        })
        wx.setStorageSync('address', res.address)
      },
      fail: function(error) {
      },
      complete: function(e) {
      }
    })
  },
複製代碼

商品參數和說明彈出框

我在數據裏並無寫每一個商品的具體參數和評價,由於實在太多了(┬_┬),因此這裏我放的只是寫死的假數據,固然,若是有數據只要拿到渲染出來就行。

說明彈出框

html和css代碼太多了我就不放進來了,我會在文章最後放上個人github連接源碼,有興趣的朋友能夠去看看,我在這裏就說下原理

仍是經過三目運算符判斷是否顯示遮罩層,經過點擊改變變量狀態來修改類名,同時會有不一樣的樣式出現,實現彈出框的彈出,點擊再次改變,實現彈出框消失。

//打開說明
  showexplain: function () {
    this.setData({
      isshowTrue: true
    })
  },
  //關閉說明
  hideshow: function () {
    this.setData({
      isshowTrue: false
    })
  },
複製代碼

加入購物車

加購物車是每一個電商類都須要的,結構的關鍵就是要使用相對於瀏覽器窗口進行絕對定位和彈性佈局將購物車那一欄定位在頁面底部

html

<view class="buy">
    <view class="image">
      <image src="../../images/system-icon/goodscarton.png" />
    </view>
    <text class="order" bindtap="addcart">
            加入購物車
        </text>
    <text class="buy1">
            當即購買
        </text>
  </view>
複製代碼

css

.buy{
    position: fixed;
    bottom: 0;
    width: 100%;   
    background: #FFF;
    border-top: 0.5rpx solid rgb(201, 199, 199);
    box-sizing: border-box
    
}
.buy .image image{
    width: 100rpx;
    height: 100rpx;
    float: left;
    flex: 1
}
.buy .order,.buy1{
    display: inline-block;
    flex: 1;
    text-align: center;
    line-height: 100%;
    color: #fff
      
}
.buy .order{
    background: rgb(245, 63, 18);
}
.buy .buy1{
    background: rgb(221, 73, 54);
}
複製代碼

加入購物車我是經過緩存來實現的,點擊加入購物車,給出showtoast提示。將當前商品詳情頁面的數據push進一個緩存數組中,在購物車頁面拿到這個緩存的購物車數據渲染。固然,加入購物車後再次點進來須要加一個判斷是否已經加入購物車。直接上代碼:

js

//加入購物車,將數據放入緩存
addcart: function() {
    this.setData({
      cartmsg: this.data.goodsdetail
    })
    const nowgoodsname = this.data.goodsdetail.goodsname
    const addcartsuccess = this.data.addcartsuccess
    const cartMsg = app.globalData.cartMsg
    if (addcartsuccess == true) {
      wx.showToast({
        title: '已經加入購物車!',
        icon: 'none',
        duration: 2000
      })
    } else {
      app.globalData.cartMsg.push(this.data.cartmsg);
      wx.showToast({
        title: '成功加入購物車',
        icon: 'success',
        duration: 2000
      })
      this.setData({
        addcartsuccess: true
      })
    }
  },
  //每次進入商品詳情頁在生命週期函數onload中經過商品名稱判斷是否已經在購物車中
  onLoad: function(options) {
    this.setData({
      goodsdetail: app.goodsdetail
    })
    const nowgoodsname = this.data.goodsdetail.goodsname
    const addcartsuccess = this.data.addcartsuccess
    const cartMsg = app.globalData.cartMsg
    for (let i = 0; i < cartMsg.length; i++) {
      if (cartMsg[i].goodsname == nowgoodsname) {
        this.setData({
          addcartsuccess: true
        })
      }
    }
    const address = wx.getStorageSync('address')
    this.setData({
      address
    })
  },
複製代碼

購物車

對於用戶來講,最重要的固然是購物車。須要實現的功能就是展現用戶已經加入購物車的商品,並對商品的參數進行修改以及價格的計算。

購物車是否爲空

進入購物車首先須要判斷你的購物車裏是否有商品,若是購物車爲空時,顯示一套購物車爲空時的結構和樣式,若是不爲空則將緩存中購物車的數據拿到並渲染。

html

<scroll-view class='main' scroll-y wx:if="{{flag}}">
  <view class='orderlist' wx:for="{{cartlist}}" wx:key="{{item}}">
    <icon wx:if="{{item.selected}}" type="success" color="red" data-index="{{index}}" class="cart-pro-select" bindtap="selectList" />
    <icon wx:else type="circle" class="cart-pro-select" data-index="{{index}}" bindtap="selectList" />
    <navigator class="cart-pro-goods" >
      <image class="cart-thumb" src="{{item.url}}"></image>
    </navigator>
    <text class="cart-pro-name">{{item.goodsname}}</text>
    <text class="cart-pro-price">¥{{item.goodsprice}}</text>
    <view class="cart-count-box">
      <text class="cart-count-down" bindtap="minusCount" data-index="{{index}}">-</text>
      <text class="cart-count-num">{{item.number}}</text>
      <text class="cart-count-add" bindtap="addCount" data-index="{{index}}">+</text>
    </view>
    <text class="cart-del" bindtap="deleteList" data-index="{{index}}">刪除</text>
    <view class="cart-footer">
      <icon wx:if="{{selectAllStatus}}" type="success_circle" class="total-select" color="red" bindtap="selectAll" />
      <icon wx:else type="circle" class="total-select" color="#010" bindtap="selectAll" />
      <text class="selAl">全選</text>
      <text class="cart-total-price">合計:</text>
      <text class="pricCount">{{totalPrice}}元</text>
      <text class="pay">結算{{totalPrice}}元</text>
    </view>
  </view>
</scroll-view>
<view class='kongcart' wx:else>
  <view class='kongcart'>
    <view class='cart-circle'>
      <view class='carticon'>
        <image src='{{carticon}}'></image>
      </view>
    </view>
  </view>
  <view class='kongtip'>
    <view class='tiptext'>
      <text>{{kongtip}}</text>
    </view>
  </view>
  <view class='tomilite'>
    <navigator url='/pages/index/index' open-type='switchTab' hover-class='other-navigator-hover'>
      <view class='tolitebutton'>
        <view class='textbutton'>
          <text>{{tolitebutton}}</text>
        </view>
      </view>
    </navigator>
  </view>
</view>
複製代碼

js

// 商品數量作減法時
minusCount: function (e) {
    let cartlist = this.data.cartlist;
    const index = e.target.dataset.index;
    let num = this.data.cartlist[index].number;
    num -= 1;
    cartlist[index].number = num;
    if (num == 0) {
      cartlist.splice(index, 1)
    }
    if (this.data.cartlist.length == 0) {
      this.setData({
        flag: false
      })
    }
    this.setData({
      cartlist
    })
    this.getTotalPrice()
  },
  // 商品數量作加法時
  addCount: function (e) {
    let cartlist = this.data.cartlist;
    const index = e.target.dataset.index;
    let num = this.data.cartlist[index].number;
    num += 1;
    cartlist[index].number = num;
    this.setData({
      cartlist
    })
    this.getTotalPrice()
  },
  //點擊是否選中全部商品或取消全部選中並計算價格
  selectAll: function (e) {
    let selectAllStatus = this.data.selectAllStatus;
    selectAllStatus = !selectAllStatus;
    let cartlist = this.data.cartlist;
    for (let i = 0; i < cartlist.length; i++) {
      cartlist[i].selected = selectAllStatus;
    }
    this.setData({
      cartlist,
      selectAllStatus,
    })
    this.getTotalPrice()
  },
  //計算當前選中商品的總價格
  getTotalPrice: function (e) {
    let cartlist = this.data.cartlist;
    let total = 0;
    for (let i = 0; i < cartlist.length; i++) {
      if (cartlist[i].selected) {
        total += (+cartlist[i].goodsprice * +cartlist[i].number);
      }
    }
    this.setData({
      totalPrice: total
    });
  },
  //計算選中商品的價格
  selectList: function (e) {
    const index = e.currentTarget.dataset.index;
    let cartlist = this.data.cartlist;
    const selected = cartlist[index].selected;
    cartlist[index].selected = !selected;
    const a = [];
    for (let i = 0; i < cartlist.length; i++) {
      if (cartlist[i].selected) {
        a.push(cartlist[index])
      }
    }
    if (cartlist.length <= a.length) {
      this.setData({
        selectAllStatus: true, cartlist
      });
    } else {
      this.setData({
        selectAllStatus: false, cartlist
      });
    }
    this.getTotalPrice()
  },
  //刪除商品,當數量爲0時也刪除
  deleteList: function (e) {
    const index = e.target.dataset.index;
    let cartlist = this.data.cartlist;
    cartlist.splice(index, 1)
    if (this.data.cartlist.length == 0) {
      this.setData({
        flag: false
      })
    }
    this.setData({
      cartlist
    })

  },
  //由於數據中沒有數量這個屬性,每次顯示時給新加入沒有數量屬性的商品添加數量=1屬性
  fff() {
    let cartlist = app.globalData.cartMsg
    for(let i =0;i<cartlist.length;i++){
      if (!cartlist[i].number) {
        cartlist.map(e => {
          return e['number'] = 1
        })
      }
    }
    if (cartlist.length > 0) {
      this.setData({
        flag: true,
        cartlist
      })
    }
  },
  //生命週期函數  第一次進入購物車頁面時獲取緩存中購物車數據
  onLoad: function (options) {
    if (wx.getStorageSync('cartMsg')){
      app.globalData.cartMsg = wx.getStorageSync('cartMsg')
      this.setData({
        cartlist: app.globalData.cartMsg
      })
    }
  },
  //生命週期函數,每次顯示購物車頁面時獲取緩存中購物車數據刷新
  onShow: function () {
    if (app.globalData.cartMsg.length > 0) {
      const cartMsg = app.globalData.cartMsg
      wx.setStorageSync('cartMsg', cartMsg)
    }else{
    }
    this.fff()
  },
  //當購物車頁面隱藏時,存一次緩存數據
  onHide: function () {
    const cartMsg = app.globalData.cartMsg
    wx.setStorageSync('cartMsg', cartMsg)
  },

複製代碼

結語

這是個人第一次項目實戰,收穫不少,雖然回頭看看仍是有不少不足跟bug,寫的過程頭皮發麻,可是完成了仍是滿滿的成就感(若是不掉頭髮的話)。在此也但願個人文章能給屏幕前的你帶來幫助,做爲一名萌新程序員,還有許多技術要學習,也迫切須要一個實習的機會來鍛鍊本身,有大佬看到但願能給個機會(づ。◕‿‿◕。)づ,將來也但願能在這與社區的朋友們互相幫助,共同進步!共勉!

最後奉上個人項目源碼地址github項目源碼

相關文章
相關標籤/搜索