微信小程序-小米Lite

微信小程序-小米Lite

事先聲明,這是一個高仿小米Lite的微信小程序。

我呢如今是一個大三快大四的學生,這個小程序花了我很長時間,把能寫的功能基本上都寫了。我秉着分享開源的心理,儘可能把我寫的這個小程序怎麼寫的,爲何這樣寫,詳細的告訴你們。爲何是儘可能?這是由於,我不太會說,可能說的不是很清楚,因此只能儘可能.html

項目預覽



ok實現的效果就是這樣。前端

使用的工具

  1. easy-moke
  2. VSCode
  3. 微信小程序開發者工具
  4. (阿里巴巴矢量圖標庫)

文件目錄

├<assets>
│  ├<images>
├<components>
│  ├<goodList>
│  ├<icon>
│  ├<tabbar>
│  ├<userList>
├<pages>
│  ├<cart>
│  ├<category>
│  ├<deleteGoods>
│  ├<find>
│  ├<goodDetails>
│  ├<index>
│  ├<selectGoods>
│  ├<user>
├<utils>
│  └util.js
├<weui>
│  └weui.wxss
├<wxapi>
│  ├Api.js
│  ├main.js
│  └mock.js

對於初學者來講,可能拿到設計圖就立馬寫,其實這樣很很差,寫出來的代碼會有不少重複的代碼,這樣不利於以後的維護。因此應該把一些公用的代碼封裝,以後直接調用就好了,以後維護起來也更加的方便。git

API封裝

咱們前端想要獲取頁面的數據,就須要發送HTTP請求後端提供給咱們的API接口,從API接口中獲取咱們想要的數據。在微信小程序中,微信官方給咱們提供了一個方法wx.request來請求.github

一個程序,須要的HTTP請求會不少,若是咱們每一個請求都去寫一個wx.request,這樣寫出來的代碼,看起來會很冗長,他人看咱們的代碼時也會很累,也不利於咱們以後的修改。所以爲了代碼的整潔,和以後的修改方便。我就把全部的API請求請求封裝在wxapi文件目錄下。web

// Api.js
const banners = 'https://www.easy-mock.com/mock/5cf9c392006feb28c7eedf28/banners'

const navdata = 'https://www.easy-mock.com/mock/5cf9c392006feb28c7eedf28/navdata'

const goodList = 'https://www.easy-mock.com/mock/5cf9c392006feb28c7eedf28/goodList'

const category = 'https://www.easy-mock.com/mock/5cf9c392006feb28c7eedf28/category'

const findData = 'https://www.easy-mock.com/mock/5cf9c392006feb28c7eedf28/findData'

const userData = 'https://www.easy-mock.com/mock/5cf9c392006feb28c7eedf28/userData'

const goodDetail = 'https://www.easy-mock.com/mock/5cf9c392006feb28c7eedf28/goodDetail'

const QQ_MAP_KEY = 'NNFBZ-6DRCP-IRLDU-VEQ4F-TXLP2-PFBEN'

const MAPURL = 'https://apis.map.qq.com/ws/geocoder/v1/'

module.exports = {
  banners,
  navdata,
  goodList,
  category,
  findData,
  userData,
  goodDetail,
  QQ_MAP_KEY,
  MAPURL
}
import * as MOCK from "./mock"
import * as API from "./Api"
const request = (url,mock = true,data) => {
  let _url = url
  return new Promise((resolve, reject) => {
    if (mock) {
      let res = {
        statusCode: 200,
        data: MOCK[_url]
      }
      if (res && res.statusCode === 200 && res.data) {
        resolve(res.data)
      } else {
        reject(res)
      }
    } else {
      wx.request({
        url: url,
        data,
        success(request) {
          resolve(request.data)
        },
        fail(error) {
          reject(error)
        }
      })
    }
  });
}
// showLoading
const showLoading = () => {
  wx.showLoading({
    title: '數據加載中',
    mask: true,
  });  
}
// 獲取地理位置
const geocoder = (lat, lon) => {
  return request(API.MAPURL,false,{
    location: `${lat},${lon}`,
    key: API.QQ_MAP_KEY,
    get_poi: 0
  })
}
module.exports = {
  getBanners: () => {
    // return request('banners')
    return request(API.banners,false)  //首頁 banners 
  },
  getNavData: () => {
    // return request('navdata')
    return request(API.navdata,false) //首頁 navdata 
  },
  getGoodList: () => {
    // return request('goodList')
    return request(API.goodList,false)  //首頁 商品列表
  },
  getCategroy: () => {
    // return request('category')
    return request(API.category,false)  //分類頁面
  },
  getFindData: () => {
    // return request('findData')
    return request(API.findData,false)  //發現 頁面
  },
  getUserData: () => {
    // return request('userData')
    return request(API.userData,false)  // 個人 頁面
  },
  getGoodDetail: () => {
    // return request('goodDetail')
    return request(API.goodDetail,false)  //商品詳情
  },
  showLoading,
  geocoder
}

看到這裏,可能就會有一些疑問,爲何我在每一個請求後面都加上了一個false?面試

這是由於,我在寫這個微信小程序開始時,沒有使用easy-mock來模擬http請求數據。我是把假數據都放在mock.js文件中。而後使用 return request('banners')這種方式就能夠獲取我想要的數據。數據庫

API封裝完了,該怎麼調用呢?我就以首頁的banners數據爲例json

// index.js 
const WXAPI = require('../../wxapi/main')

onLoad: function (options) {
    WXAPI.showLoading()
    this.getBanners()
},
getBanners() {
    WXAPI
    .getBanners()
    .then(res => {
      wx.hideLoading()
      this.setData({
        banners: res.data
      })
    })
},

記住,若是想要發送HTTP請求數據的頁面,都必須加上這一句const WXAPI = require('../../wxapi/main')小程序


定義的組件

開始準備OK,如今開始寫頁面。第一步要寫的是tabBar部分。後端

tabBar組件

看起來是否是有點奇怪,爲何有點透明的感受?由於這個tabBar組件是我本身寫的。

通常來將,直接在把tabBar組件寫在app.json中,就能夠了。

可是我以爲不是那麼好看,因此就本身擼了一個tabBar組件出來。

寫完以後查文檔才發現,微信小程序官方提供了自定義tabBar組件的方法,有須要的能夠查看微信小程序文檔

寫完這個組件後我總解了一下,須要注意的問題.

  • 選中了的當前頁面,再次點擊因該無效。

    因此我在app.js中存入了一個page屬性,來存儲當前頁面,而後在點擊事件goToPage()方法中加入判斷去解決。

<!--components/tabbar/tabbar.wxml-->
<view class="tabbar">
  <!-- 首頁 -->
  <view class="shouye {{on === 'index' ? 'on': ''}}" data-page="index" bindtap="goToPage">
    <icon type="shouye" size="42" class="icon" color="{{on === 'index' ? '#f96702': ''}}"/>
    <text >首頁</text>
  </view>
  <!-- 分類 -->
  <view class="fenlei {{on === 'category' ? 'on': ''}}" data-page="category" bindtap="goToPage">
    <icon type="classify" size="42" class="icon" color="{{on === 'category' ? '#f96702': ''}}"/>
    <text >分類</text>
  </view>
  <!-- 發現 -->
  <view class="faxian {{on === 'find' ? 'on': ''}}" data-page="find" bindtap="goToPage">
    <icon type="faxian" size="42" class="icon" color="{{on === 'find' ? '#f96702': ''}}"/>
    <text >發現</text>
  </view>
  <!-- 購物車 -->
  <view class="gouwuche {{on === 'cart' ? 'on': ''}}" data-page="cart" bindtap="goToPage">
    <icon type="gouwuche" size="42" class="icon" color="{{on === 'cart' ? '#f96702': ''}}"/>
    <text >購物車</text>
  </view>
  <!-- 個人 -->
  <view class="wode {{on === 'user' ? 'on': ''}}" data-page="user" bindtap="goToPage">
    <icon type="wode" size="42" class="icon" color="{{on === 'user' ? '#f96702': ''}}"/>
    <text >個人</text>
  </view>
</view>
// components/tabbar/tabbar.js
// 全局裏面存了一個page 表示當前 路由
const app =  getApp();
Component({
  /**
   * 組件的屬性列表
   */
  properties: {
    // 是否選中
    on:{
      type: String,
      value: ''
    }
  },

  /**
   * 組件的初始數據
   */
  data: {
  },

  /**
   * 組件的方法列表
   */
  methods: {
    // 跳轉到相應的頁面
    // 加了一個判斷
    // 由於若是如今顯示的是當前頁面就不須要再跳轉
    goToPage(e) {
      let page = e.currentTarget.dataset.page || 'user';
      if(app.globalData.page === page) {
        return ;
      }
      wx.redirectTo({
        url: `/pages/${page}/${page}`,
      });
      app.globalData.page = page;
    }
  }
})
/* components/tabbar/tabbar.wxss */
.tabbar {
  width: 100%;
  height: 100rpx;
  background-color: #ffffff;
  display: flex;
  position: fixed;
  bottom: 0;
  font-size: 26rpx;
  z-index: 99;
}
.shouye,.fenlei,.faxian,.gouwuche,.wode {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  text-align: center;
  opacity: 0.5;
}
.icon {
  height: 60rpx;
}
.on {
  color:#f96702;
}

關於如何使用的問題,只須要在,須要tabBar功能的頁面底部加上就能夠.

好比index頁面

<tabbar on="index"></tabbar>

記得在json中引入組件

{
  "usingComponents": {
    "goodList": "../../components/goodList/goodList",
    "tabbar": "../../components/tabbar/tabbar"
  }
}

icon組件

tabBar組件中須要圖標,我使用的是阿里的圖標庫

如何使用?

  1. 先去圖標庫中找到你所須要的圖標,加入購物車。
  2. 而後添加至項目,本身新建一個就能夠了。
  3. 在而後下載之本地,把其中的CSS文件裏面全部的內容都複製到wxss文件中就好了.

這個組件很簡單,定義出來就能夠直接使用,而且修改顏色和大小.

<!--components/icon/icon.wxml-->
<text class='iconfont icon-{{type}}' style='color:{{color}}; font-size:{{size}}rpx;'></text>
properties: {
    type: {
      type: String,
      value: ''
    },
    color: {
      type: String,
      value: '#000000'
    },
    size: {
      type: Number,
      value: '45'
    }
  },

goodList組件

在首頁中存在不少這樣的商品列表,一個一個寫,這樣寫出來的代碼會致使首頁的代碼顯得不少,而且很差維護,因此我就封裝成了一個組件.

<!--components/goodList/goodList.wxml-->
<view class="goodList-good">
  <!-- 商品的圖片 -->
  <view class="goodList-good-img">
    <image src="{{url}}" mode="aspectFill" />
  </view>
  <!-- 商品詳細的信息 -->
  <view class="goodList-good_detail">
    <!-- 名稱 -->
    <view class="good_detail_name">
      {{name}}
    </view>
    <!-- 信息 -->
    <view class="good_detail_brief">
      {{brief}}
    </view>
    <!-- 價格 -->
    <view class="good_detail_price">
      <text class="price" >¥{{price}}</text>
      <text class="oldPrice" style="display:{{oldPrice == '' ? 'none': 'inline'}};">¥{{oldPrice}}</text>
    </view>
  </view>
</view>
properties: {
    // 圖片連接
    url: {  
      type: String,
      value: ''
    },
    // 名稱
    name: {
      type: String,
      value: ''
    },
    // 信息
    brief: {
      type: String,
      value: ''
    },
    // 新的價格
    price: {
      type: String,
      value: ''
    },
    // 舊的價格
    oldPrice: {
      type: String,
      value: ''
    }
  },
/* components/goodList/goodList.wxss */

.goodList-good {
  position: relative;
  width: 100%;
  height: 100%;
}
.goodList-good-img {
  width: 100%;
  height: 312rpx;
  position: relative;
}
.goodList-good-img image {
  width: 100%;
  height: 100%;
}
.goodList-good_detail {
  padding: 26rpx 23rpx;
}
.good_detail_name {
  width:100%;
  overflow: hidden;
  text-overflow: ellipsis;
  display: -webkit-box;
  -webkit-line-clamp: 1;
  -webkit-box-orient: vertical;
}
.good_detail_brief {
  width:100%;
  overflow: hidden;
  text-overflow: ellipsis;
  display: -webkit-box;
  -webkit-line-clamp: 1;
  -webkit-box-orient: vertical;
  font-size: 25rpx;
  color: #8c8c8c;
}
.good_detail_price {
  display: flex;
  justify-content: flex-start;
  align-items: flex-end;
}
.good_detail_price .price {
  color: #a36d4a;
  font-size: 28rpx;
  padding-right: 16rpx;
}
.good_detail_price .oldPrice {
  font-size: 24rpx;
  color: #8c8c8c;
  text-decoration: line-through;
}

大家會發現,個人邊框爲何那麼細。


0.5px邊框如何畫

初學者,可能會說,0.5px邊框,不就是border: 0.5px嗎,其實這是錯的。

瀏覽器會把任何小於1px的邊框都解析成1px,因此你寫0.5px其實瀏覽器會解析成1px,這樣就實現不了效果。

其實也很簡單,使用僞類去畫。

例如,goodList組件的右部邊框.

在index頁面的html中,我在包裹goodList的view標籤的class中加上了rightBorder這個類來表示畫出上邊框。

<view class="item topBorder rightBorder" data-id="{{item.id}}" bindtap="goDetails">
  <goodList url="{{item.url}}"
    name="{{item.name}}"
    brief="{{item.brief}}"
    price="{{item.price}}"
    oldPrice="{{item.oldPrice}}" ></goodList>
</view>
.rightBorder::after {
  content: '';
  position: absolute;
  height: 200%;
  width: 1rpx;
  right: -1rpx;
  top: 0;
  transform-origin: 0 0;
  border-right: 1rpx solid#e0e0e0;
  transform: scale(.5);
  z-index: 1;
}

其實畫0.5px邊框就記住。

  1. 使用僞類,而且 position: absolute;
  2. 若是想畫上下的邊框,就把width設置成200%,,左右就把height設置成200%
  3. 而後使用transform: scale(.5); 寬高都縮小0.5倍就成了0.5px邊框.

其它還有一些 細節問題就按照所需寫就行。


userList組件

只是個人頁面中的一個列表信息,這個很簡單

<!--components/userList/userList.wxml-->
<view class="main">
  <image src="{{List.img}}" />
  <view class="text" >
    <text >{{List.text}}</text>
  </view>
  <view class="state" wx:if="{{List.state !== ''}}">
    <text >({{List.state}})</text>
  </view>
</view>
/* components/userList/userList.wxss */
.main {
  width: 100%;
  height: 120rpx;
  display: flex;
  align-items: center;
  background-color: #fff;
  padding: 40rpx;
  box-sizing: border-box;
}
.main image {
  width: 80rpx;
  height: 80rpx;
}
.main .text {
  font-size: 32rpx;
  padding: 0 10rpx 0 5rpx;
}
.main .state {
  font-size: 26rpx;
  color: #8c8c8c;
}
properties: {
    List: {
      type: Object
    }
  },

頁面和功能介紹

首頁搜索部分

我這裏引入的是weui組件的搜索樣式。如何用?

  1. 下載WEUI小程序版,能夠在微信開發者工具中打開。
  2. (推薦)把styly文件夾下的weui.wxss 放到本身項目中weui文件夾下
  3. 在app.wxss中@import "./weui/weui.wxss".就可使用了

首頁輪播部分

這是微信小程序提供的一個組件swiper,微信小程序開發者文檔

swiper和swiper-item組合起來就能夠實現,一些配置信息,請查看官方文檔

具體代碼

<swiper indicator-dots="{{indicatorDots}}" indicator-active-color="#ffffff" autoplay="{{autoPlay}}" interval="{{interval}}" duration="{{duration}}">
    <block wx:for="{{banners}}" wx:key="index">
      <swiper-item>
        <image src="{{item.imgurl}}" mode="aspectFill" class="banner-image" />
      </swiper-item>
    </block>
  </swiper>
data: {
    banners: [],
    indicatorDots: true,
    autoPlay: true,
    interval: 3000,
    duration: 1000,
    navdata: [],
    goodList: [],
    goodListOne: {},
    name:'',
  },

一個經常使用的功能

在商城小程序中常常要作一個這樣的功能.例如:

功能要求:

  1. 點擊左邊的商品列表,右邊的商品信息會滑動到對應位置.
  2. 滑動右邊的商品信息,左邊的商品列表顯示的高亮會對應發生變化.

功能要求並不難,可是對於初學者而言,可能會有些問題。我就直接說功能該怎麼作

首先:分析一下,頁面結構是左右佈局。而且兩邊均可以滑動.因此可使用微信給咱們提供的

scroll-view組件.兩個組件就能夠採用float,分佈在左右兩邊.

<!-- miniprogram/pages/category/category.wxml -->
<view class="container">
  <!-- 左邊商品的標籤信息 -->
  <scroll-view scroll-y scroll-with-animation="{{true}}" class="categroy-left">
    <view wx:for="{{categroy}}" wx:key="{{index}}" data-index="{{index}}" bindtap="switchTab" class="cate-list {{curIndex === index ? 'on': ''}}">
      {{item[0].name}}
    </view>
  </scroll-view>
  <!-- 右邊 標籤對應的商品信息 -->
  <scroll-view scroll-y scroll-into-view="{{toView}}" scroll-with-animation="true" bindscroll="scrollContent" bindscrolltolower="scrollEnd" class="categroy-right">
    <block wx:for="{{categroy}}" wx:key="inedx">
      <view id="right-list" class="right-list" id="{{index}}">
        <view class="right-title">
          <text>{{item[0].name}}</text>
        </view>
        <view class="right-content">
          <block wx:for="{{item}}" wx:key="idex" wx:for-item="product" wx:for-index="idex">
            <view class="list-detail" wx:if="{{idex > 0}}">
              <image src="{{product.picture}}" />
              <view class="detail-name">
                <text>{{product.desc}}</text>
              </view>
            </view>
          </block>
        </view>
      </view>
    </block>
  </scroll-view>
</view>
<tabbar on="category"></tabbar>
/* miniprogram/pages/category/category.wxss */
/*定義滾動條高寬及背景 高寬分別對應橫豎滾動條的尺寸*/
::-webkit-scrollbar
{
width: 0px;
height: 0px;
background-color: pink;
}
.categroy-left {
  height: 100%;
  width: 150rpx;
  float: left;
  border-right: 1px solid #ebebeb;
  box-sizing: border-box;
  position: fixed;
  font-size: 30rpx;
  padding-bottom: 100rpx;
  box-sizing: border-box;
}
.categroy-left .cate-list {
  height: 90rpx;
  line-height: 90rpx;
  text-align: center;
  border: 2px solid #fff;
}
.categroy-left .cate-list.on {
  color: #ff4800;
  font-size: 34rpx;
}
/* 右邊的列表 */
.categroy-right {
  width: 600rpx;
  float: right; 
  height: 1334rpx;
  /* height: 100%; */
  padding-bottom: 100rpx;
  box-sizing: border-box;
  overflow: hidden;
}
.right-title {
  width: 100%;
  text-align: center;
  position: relative;  
  padding-top: 30rpx;
  /* font-size: 30rpx; */
  padding-bottom: 30rpx;
}
 .right-title text::before, .right-title text::after {
  content: '';
  position: absolute;
  width: 60rpx;
  /* height: 1px; */
  top: 50%;
  border-top: 1px solid #e0e0e0;
  /* transform: scale(.5); */
}
.right-title text::before { 
  left: 30%;
}
.right-title text::after {
  right: 30%;
}
.right-list {
  /* height: 100%; */
  background-color: #fff;
}
.right-content {
  width: 100%;
  height: 100%;
  display: flex;
  flex-wrap: wrap;
}
.right-content .list-detail {
  flex-shrink: 0;
  width: 33.3%;
  height: 100%;
  font-size: 26rpx;
  text-align: center;
  
}
.right-content .list-detail image {
  width: 120rpx;
  height: 120rpx;
  padding: 10rpx;
  /* background-color: pink; */
}

這個功能的難點就在於js邏輯

先貼出data中須要的數據

data: {
    categroy:[],    //商品信息
    curIndex: 'A',  //當前的選中的標籤
    toView: 'A',    //去到的標籤
    // 存入每一個list的高度疊加
    heightArr: [],
    // 最後一個list,就是最後一個標籤的id
    endActive: 'A'
  },

點擊左邊右邊滑動

這一功能很簡單就能實現

只須要在右邊scroll-view組件中添加事件scroll-into-view="{{toView}}",toView就是商品顯示的id

注意,右邊每一個商品信息,頁面渲染時必須加上id屬性

而後左邊的scroll-view組件只需添加一個點擊事件去修改toView的值就好了

// 點擊左邊標籤要修改的信息
  switchTab(e) {
    this.setData({
      curIndex: e.target.dataset.index,
      toView: e.target.dataset.index
    })
  },

滑動右邊左邊高亮對應改變

  1. 首先須要計算出 右邊商品每一塊佔據的高度,而且存入數組中,能夠放入onReady生命週期中

    // 計算出右邊每一個商品佔據的高度
      getPageMessage() {
        // console.log(4)
        let self = this
        let heightArr = []
        let h = 0
        const query = wx.createSelectorQuery()
        query.selectAll('.right-list').boundingClientRect()
        query.exec( res => {
          res[0].forEach( item => {
            h += item.height
            heightArr.push(h)
          })
          self.setData({
            heightArr: heightArr
          })
        })
      },
  2. 在右邊的scroll-view組件中加上事件。bindscroll="scrollContent,這是scroll-view提供的事件,在滑動時就會觸發.

    // 頁面滑動時觸發
      scrollContent(e) {
        const scrollTop = e.detail.scrollTop
        const scrollArr = this.data.heightArr
        const length = scrollArr.length - 1
        let endChar = String.fromCharCode(65 + length)
        let curChar = this.getCurrentIndex(scrollTop)
        if(this.data.endActive != endChar) {
          this.setData({
            curIndex: curChar
          })
        } else {
          this.setData({
            endActive: 'A'
          })
        }
      },
    // 判斷curIndex應該是那個
      getCurrentIndex(scrollTop) {
        const scrollArr = this.data.heightArr
        let find = scrollArr.findIndex(item => {
          // 提早10rpx觸發效果
          return scrollTop < item - 10
        })
        let curChar = String.fromCharCode(65 + find)
        return curChar
      },

    以上就能夠實現全部的功能要求了。

    可是這樣的滑動並非很完美,右邊滑動到最下面,左邊高亮卻不是最後一個

    相對完美效果就是這樣

想要完美一點就要在,右邊scroll-view添加一個事件:bindscrolltolower="scrollEnd"

// 頁面滑動到底部觸發
  scrollEnd() {
    const scrollArr = this.data.heightArr
    const length = scrollArr.length - 1
    let endChar = String.fromCharCode(65 + length)
    this.setData({
      curIndex: endChar,
      endActive: endChar
    })
  },

購物邏輯

想要實現這樣的效果並不困難。

邏輯順序: 首頁點擊商品信息 -> 商品詳情頁面顯示對應的商品詳情信息 -> 購物車頁面顯示商品購買的商品信息. -> 修改以後,商品詳情頁面顯示修改的信息。

想要實現這樣的功能,必須有一個 id 在頁面跳轉時,傳入給跳轉的頁面,跳轉的頁面再經過id值獲取頁面所需的數據

例如:首頁 -> 商品詳情頁

這是一條商品的列表的信息,經過點擊事件bindtap="goDetails",跳到對應的頁面.

<view class="list">
      <block wx:for="{{goodList}}" wx:key="{{item.id}}">
        <view class="item topBorder rightBorder" data-id="{{item.id}}" bindtap="goDetails">
          <goodList url="{{item.url}}"
            name="{{item.name}}"
            brief="{{item.brief}}"
            price="{{item.price}}"
            oldPrice="{{item.oldPrice}}" ></goodList>
        </view>  
      </block>
    </view>
goDetails(e) {
    const id = e.currentTarget.dataset.id
    wx.navigateTo({
      url: `/pages/goodDetails/goodDetails?id=${id}`,
    });
  },

商品詳情頁:

傳入的id值能夠再onLoad生命週期的options參數上獲取

onLoad: function (options) {
    WXAPI.showLoading()
    // 獲取用戶的地址信息
    const address = wx.getStorageSync('Address');
    this.setData({
      id: options.id,
      address
    })
    this.getGoodDetail()
  },

數據的存儲邏輯

我是把數據直接存在本地緩存中(也能夠直接存入到雲數據庫中),使用的是 wx.setStorage()

在本地存入了兩個數據,一個是全部購買的商品信息,一個是總的商品購買數量

// 添加到購物車
  toAddCart() {
    let cartData = wx.getStorageSync('goods') || [];    
    let data = {
      id: this.data.id,
      name: this.data.goodData.name,
      memory: this.data.memory,
      color: this.data.color,
      price: this.data.price,
      num: this.data.selectNum,
      img: this.data.imgSrc,
      select: true
    }
    // wx.removeStorageSync('goods');
    cartData.push(data)
    const allNum =this.getAllNum(cartData)
    wx.setStorage({
      key: 'goods',
      data: cartData,
      success: (res) => {
        console.log(res)
        let pageIndex = getCurrentPages()
        let backIndex = pageIndex.length - 2
        wx.navigateBack({
          delta: backIndex
        })
      },
      fail: () => {},
      complete: () => {}
    });
    // 存儲數量到storage
    wx.setStorageSync('allNum', allNum);
    // 寫到外面就可讓showToast 顯示在前一個頁面
    setTimeout(()=>{
      wx.showToast({
        title: '已加入購物車',
        icon: 'success',
        duration: 2000
      });
   },500)
  },
  // 獲取全部的數量
  getAllNum(cartData) {
    return cartData.reduce((sum, item) => {
      return sum + (+item.num)
    },0)
  },

概述的參數切換

實現這個功能只須要加一個狀態,點擊時就修改狀態的值,而且修改相關渲染的數據就行。

data: {
 state: 'details_img', //判斷概述 參數
}
<view class="summarize-parameter">
    <view class="title">
      <view class="summarize" bindtap="changeState">
        <text class="{{state === 'details_img'? 'on' : ''}}">概述</text>
      </view>
      <view class="parameter" bindtap="changeState">
        <text class="{{state === 'param_img'? 'on' : ''}}">參數</text>
      </view>
    </view>
    <view class="state">
      <block wx:for="{{state === 'details_img'? details_img : param_img}}" wx:key="index">
          <image src="{{item}}" mode="widthFix"/>
      </block>
    </view>
  </view>
// 改變概述和參數
  changeState() {
    let state = this.data.state
    if(state === 'details_img') {
      state = 'param_img'
    } else {
      state = 'details_img'
    }
    this.setData({
      state
    })
  },

購物數據改變,商品詳情數據修改

對比一下上面兩張圖的區別.

在購物頁面中選的商品數量和具體的商品信息,以後跳轉回商品詳情頁面中,對應的數據會修改

<view class="sales" bindtap="goSelectGoods">
      <text class="describe">已選</text>
      <view class="detail detail-change">
        {{default_change.name}}
        {{default_change.memory}}
        {{default_change.color}}
        <text >× {{default_change.num}}</text>
      </view>
      <view class="right"></view>
    </view>
<view class="shopping-img" bindtap="goCart">
    <icon type="gouwuche" color="#e0e0e0" size="40"/>
    <text wx:if="{{allNum != 0}}">{{allNum}}</text>
  </view>

上面時兩塊修改的html結構

在購物頁面點擊確認以後,我默認就把商品添加到購物車中,而且位於數據的最後一條

返回商品詳情頁面時,會從新觸發onShow生命週期的函數。

因此我只須要,在onShow中觸發修改方法就行.

// 改變默認的版本數據 default_change
  changeDefauleChange() {
    const goods = wx.getStorageSync('goods') || [];
    if(goods.length === 0) {
      return
    }
    const id = this.data.id
    const default_change = goods[goods.length - 1]
    let memory = default_change.memory.toString()
    memory = memory.substring(0,memory.length - 4)
    default_change.memory = memory
    this.setData({
      default_change
    })
  },

畫一個三角形

這一個三角形是使用CSS畫出來的,並非圖標。

使用CSS畫出一個三角形,也不是那麼困難。使用的是僞類和border屬性

.right:before,
.right:after {
  content: '';
  position: absolute;
  top: 35%;
  right: 0;
  border-width: 8px;
  /* transform: translateY(10000rpx); */
  border-color: transparent transparent transparent transparent;
  border-style: solid;
  transform: rotate(90deg);
}

.right:before {
  border-bottom: 8px #aaaaaa solid;
}

.right:after {
  right: 1px;
  /*覆蓋並錯開1px*/
  border-bottom: 8px #fff solid;
}

修改商品數量

能夠直接使用微信小程序提供的picker組件,具體配置請查看文檔

使用騰訊地圖獲取地理位置

先搜索騰訊地圖,而且註冊開發者信息,申請一個密鑰key.

// 獲取地理位置
const geocoder = (lat, lon) => {
  return request(API.MAPURL,false,{
    location: `${lat},${lon}`,
    key: API.QQ_MAP_KEY,
    get_poi: 0
  })
}

而後把密鑰複製,由於我封裝了全部的API接口。因此使用了 API.QQ_MAP_KEY代替,這裏就填寫申請的密鑰就行.

想要獲取用戶的經緯度信息,可使用wx.getLocation(),就能夠獲取用戶的經緯度信息了.

getLocation() {
    wx.getLocation({
      type: 'gcj02',
      success: this.getAddress,
      fail: () => {
        this.openLocation()
      }
    })
  },
  getAddress(res) {
    let { latitude: lat, longitude: lon} = res
    WXAPI.geocoder(lat, lon)
    .then(res => {
      if(res.status !== 0 || !res.result) {
        return
      } 
      let {address_component
      } = res.result
      const Address = {
        city: address_component.city,
        district: address_component.district
      }
      wx.setStorageSync("Address", Address);
    })
  },

由於我未讓用戶受權,因此直接把獲取的地理位置,保存在本地storage中.

獲取的地理位置,就能夠在商品詳情頁面的送至顯示出來

結語

作這個項目的過程來講是快樂的,沒有使用雲函數(頁面數據並很少,我以爲不須要就能夠寫出來了),因此總共加起來寫的時間也很短,不到一個星期就寫完了。寫完以後的那一刻的成就感也很好。若是你以爲這篇文章有幫到你的地方,不妨給個贊吧!同時也很是但願在下方看到給出的建議!最後奉上源碼.若是有須要就自取吧!

最後,說點題外話,由於我是2020屆的畢業生,如今面臨實習壓力。由於須要話時間去看面試題,因此後面寫的一段文章,我只是簡要的把重要的功能邏輯寫了出來,若是寫的不清楚,請見諒。

相關文章
相關標籤/搜索