微信小程序?qū)崙?zhàn)(商城類)

微信小程序,讓你一見傾心


image

前言

小程序發(fā)布以來,憑借無需安裝、用完即走、觸手可及、無需注冊、無需登錄、以及社交裂變等多個優(yōu)勢,一路高歌,變得愈來愈火爆,它革命性的降低了移動應用的開發(fā)成本,也正好迎合了用戶的使用應用的習慣。小程序魅力如此之大,作為一枚程序猿,我想怎么不自己做一個呢?話不多說,咱擼起袖子就是干

準備工作

項目目錄結(jié)構(gòu)

├── assets                   用到的一些圖標文件
├── lib
    ├── weui.wxss            引用了weui
├── modules                    
    ├── showDetail.js        跳轉(zhuǎn)展示商品詳情的公共js文件  
    ├── showcDetail.js      
├── pages                    項目的各個頁面
    ├── index                商城首頁
    ├── categories           商品分類頁
    ├── discovery            發(fā)現(xiàn)頁
    ├── channel              商品頻道目錄
        ├── phone            手機頻道
        ├── tv               電視頻道
        ├── computer         電腦頻道
    ├── cart                 購物車
    ├── mine                 個人信息頁
    ├── goods                商品詳情頁
    ├── selectGoods          商品屬性選擇頁
    ├── search               商品搜索頁
    ├── addr                 收貨地址頁
├── template                 使用到的模版文件               
    ├── slide                輪播圖模版  
    ├── goods_list           商品展示模版
    ├── cover                商品展示模版
├── util                     使用到的工具類               
    ├── mock.js              項目中使用到的一些數(shù)據(jù)  
├── app.js                   項目邏輯
├── app.wxss                 項目公共樣式表
└── app.json                 項目公共設置

功能的展示與實現(xiàn)

一、商城首頁

image

頁面結(jié)構(gòu)分析:

  • 頂部搜索條
    這里看上去是一個搜索框,但其實,它要實現(xiàn)的僅僅是個頁面跳轉(zhuǎn)功能,只要把它的disabled設置為true就可以了,另外要想讓它placeholder占位符居中顯示的話,微信小程序提供了一個placeholder-class的屬性,通過它可以改變placeholder的樣式。

  • 輪播圖區(qū)域
    這里微信小程序給我們提供了swiper組件,直接用就可以了。但是輪播圖在各個頁面都可能存在,只是其中所顯示的圖片不一樣而已,所以使用組件化思想,把它寫成一個模版,哪里要使用,就引入這個模版即可。

<template name="slide">
    <view class="section section-swiper">
        <swiper class="slide" indicator-dots="{{true}}" autoplay="{{true}}" interval="2000" duration="1000">
            <block wx:for="{{slides}}" wx:key="{{index}}">
                <swiper-item>
                    <image src="{{item.slide_url}}" mode="widthFix" class="slide-image" data-id="{{item.id}}" />
                </swiper-item>
            </block>
        </swiper>
    </view>
</template>

使用時,這樣引入

<import src="../../../templates/slide/slide.wxml" />
<view class="container">
    <template is="slide" data="{{slides}}"></template>
</view>
  • 商城導航區(qū)、活動區(qū)
    這里只是個簡單的布局,就不贅述了。但是需要注意的是在微信小程序里,強烈推薦使用彈性布局
  • 首頁商品展示區(qū)
    這里的商品都是分塊展示,很有規(guī)律,因此整個商品展示都可以直接用wx:for遍歷出來。
    wxml:
<!-- 首頁商品版塊 -->
    <view class="section block">
        <block wx:for="{{index_block}}" wx:key="{{item.id}}">
            <view class="section cover">
                <image class="cover-img" src="{{item.img_url}}" data-cid="{{item.id}}" bindtap="showcDetail"/>
            </view>
            <view class="section goods-list">
                <block wx:for="{{item.section}}" wx:key="index" wx:for-item="product">
                    <view class="goods-item">
                        <image class="goods-img {{product.is_new?'new':''}} {{product.on_sale?'on-sale':''}}" src="{{product.goods_cover}}" data-pid="{{product.id}}" mode="aspectFill" bindtap="showDetail"/>
                        <text class="title">{{product.header}}</text>
                        <text class="desp">{{product.description}}</text>
                        <text class="meta">{{product.meta}}</text>
                        <text class="discount">{{product.discount}}</text>
                    </view>
                </block>
            </view>
        </block>
    </view><!-- end-section block -->

這里有個細節(jié),每個版塊里的商品會分成“新品”、“立減”(即有折扣)、“無折扣”三種,著該怎么去做呢?這里我用了一個巧妙的方法:給每個商品的class里綁定布爾值is_newon_sale通過三元運算符判斷是否給該商品掛載一個類名,再使用偽元素給該商品打上“新品”或“立減”的標簽如下:

wxml:

<image class="goods-img {{product.is_new?'new':''}} {{product.on_sale?'on-sale':''}}" src="{{product.goods_cover}}" data-pid="{{product.id}}" mode="aspectFill" bindtap="showDetail"/>

wxss

.goods-img.new:before{      /*新品標簽樣式*/
  position: absolute;
  left: 0;
  top: 0;
  width: 100rpx;
  height: 40rpx;
  line-height: 40rpx;
  content: "新品";
  color: #fff;
  font-size: 9pt;
  text-align: center;
  background: #8CC64A;
}
.goods-img.on-sale:before{   /*立減標簽樣式*/
  position: absolute;
  left: 0;
  top: 0;
  width: 100rpx;
  height: 40rpx;
  line-height: 40rpx;
  content: "立減";
  font-size: 9pt;
  color: #fff;
  text-align: center;
  background: #ec6055;
}

邏輯分析:
首頁只是些商品,所以邏輯層只要根據(jù)每個商品的id來跳到對應商品的詳情頁即可,很顯然這個方法在多個頁面都要使用的,所以使用模塊化思想,創(chuàng)建一個modules文件夾,把方法寫在單獨的js文件里,并向外輸出

const showDetail=(e)=>{
    const id=e.currentTarget.dataset.pid; //獲取每個商品的id
    wx.navigateTo({
        url: `/pages/goods/show?id=${id}`
    })
};
export default showDetail;

哪里要使用,就用import引入

import showDetail from "../../modules/showDetail";

二、商品分類頁

image

頁面結(jié)構(gòu)分析:
商品分類頁分為左側(cè)的商品分類菜單和右邊的商品分類展示區(qū),
用兩個scroll-view就可以了,左右兩邊都設置scroll-y讓它們垂直方向滾動,此外,scroll-view還有一個scroll-into-view屬性能讓我們實現(xiàn)類似a標簽的錨點功能,scroll-into-view的值是某個子元素的id,但是此處有一個小坑這個id不能以數(shù)字開頭
image

當時查了一下文檔就開做了,于是乎給左側(cè)菜單取了些數(shù)字id,現(xiàn)在想起來當時我太自以為然了 ,此外如果內(nèi)容太多,是會產(chǎn)生滾動條的,如圖:
image

這樣看起來也太丑了。。

**解決辦法:給全局樣式加入下面的樣式

//隱藏滾動條
::-webkit-scrollbar{  
  height: 0;
  width: 0;
  color: transparent;
}

嗯,beautiful !!

商品分類功能

邏輯分析:給頁面注冊個curIndex(當前選中菜單的下標),如果當前下標和選中的菜單下標相同,則處于激活狀態(tài)
部分代碼:
wxml:

<view class="main">
    <scroll-view scroll-y class="category-left">
        <view class="cate-nav-list" wx:for="{{cate_nav_list}}" wx:key="{{item.id}}" data-id="{{item.id}}" data-index="{{index}}"
            bindtap="switchCategory">
            <text class="cate-name {{curIndex===index?'on':''}}">{{item.name}}</text>
        </view>
    </scroll-view>
    <scroll-view class="category-right" scroll-y="{{true}}" scroll-into-view="{{toView}}" scroll-with-animation="true">
        <view class="cate-content">
            <view class="cate-list-content" wx:for="{{detail}}" wx:key="{{item.id}}" id="{{item.id}}">
                <view class="banner">
                    <image src="{{item.banner}}"/>
                </view>
                <view class="header">{{item.cate_name}}</view>
                <view class="cate-list">
                    <view class="cate-item"  wx:for="{{item.cate_list}}" wx:key="{{index}}" wx:for-item="cateList">
                        <image src="{{cateList.item_img}}" />
                        <text>{{cateList.item_name}}</text>
                    </view>
                </view>
            </view>
            
        </view>
    </scroll-view>
</view>

js:

const app=getApp();

Page({

  /**
   * 頁面的初始數(shù)據(jù)
   */
  data: {
    cate_nav_list:[
      {name:"新品",id:"new"},
      {name:"手機",id:"phone"},
      {name:"電視",id:"tv"},
      {name:"電腦",id:"laptop"},
      {name:"家電",id:"appliance"},
      {name:"路由",id:"router"},
      {name:"智能",id:"smart"},
      {name:"兒童",id:"kids"},
      {name:"燈具",id:"lignts"},
      {name:"電源",id:"adapter"},
      {name:"耳機",id:"headset"},
      {name:"音箱",id:"voicebox"},
      {name:"生活",id:"life"},
      {name:"服務",id:"service"},
      {name:"米粉卡",id:"card"}
    ],
    curIndex:0,  //初始化當前下標為0
    toView:"new", //默認顯示“新品展示”
    detail:[]
  },
  switchCategory(e){
    const curIndex=e.currentTarget.dataset.index?e.currentTarget.dataset.index:0;  //獲取每個菜單的id
    //更新數(shù)據(jù)
    this.setData({
      toView:e.currentTarget.dataset.id,
      curIndex
    });
  },
  onLoad: function (options) {
    const detail=app.globalData.category; //獲取分類展示數(shù)據(jù)
    this.setData({
      detail
    });
  }
})

三、發(fā)現(xiàn)頁

頁面結(jié)構(gòu)分析:

image

里面展示了一些商品宣傳視頻(當時還是不太想切太多的頁面??)這里用彈性布局+video組件就搞定了。這里是文檔

四、商品詳情頁

image

頁面結(jié)構(gòu)分析:
商品詳情頂部由一個swiper組成,中間部分由一些cells組成(weui)點擊這里快速查看
底部是商品的概述及參數(shù)配置兩部分組成,這個還是比較簡單的, 給兩個元素分別綁定一個布爾值來控制誰顯示誰隱藏。

當然,要使用weui必須引入它的樣式文件,我們在app.wxss里引入,然后全局都可以使用了

@import "./lib/weui.wxss";

嗯,weui的官網(wǎng)和github地址自然少不了。weui官網(wǎng) 、weui github官方文檔,在github上閱讀代碼是一個非常有效的學習方式,但是文件夾嵌套太深找個文件也不容易,這里奉上github閱讀神器

使用到的weui:
請容許我貼一段weui抄來的結(jié)構(gòu)

<view class="weui-cells">
    <view class="weui-cell">
        <view class="weui-cell__bd">
            <view class="title">{{goods.header}}</view>
            <view class="desp">{{goods.description}}</view>
            <view class="meta">{{goods.meta}}</view>
        </view>
    </view>
</view>

商品詳情頁的顯示

邏輯分析:
每個商品通過id來跳轉(zhuǎn)到相應的詳情頁,但是這個id會在哪里呢因為先這個詳情頁是通過一個個商品來打開的,所以在商品詳情頁加載時,可以在 onLoad 中獲取打開當前頁面所調(diào)用的 query 參數(shù)(是條json數(shù)據(jù)),因為在showDetail里只用了id來跳轉(zhuǎn),所以options只有id屬性

onLoad: function (options) {
    console.log(options); //{id:"4"}
    const id=options.id; //獲取options里的id
    const goods=app.globalData.goodsDetail.filter(item=>{
      return item.id==id;  //通過id來篩選顯示對應的商品
    });
    this.setData({
      goods:goods[0] //因為id是唯一的,所以上面篩選出來的數(shù)組只有一條數(shù)據(jù),這條數(shù)據(jù)就是要顯示的商品數(shù)據(jù)
    });
  }

商品圖片預覽實現(xiàn)

微信小程序為我們提供了wx.previewImage()方法來實現(xiàn)圖片的預覽,實現(xiàn)方法如下:

previewImage(e){
    const index=e.currentTarget.dataset.index;  //獲取swiper里的圖片的下標
    const slide=this.data.goods.goods_slides; //獲取商品輪播圖
    const imgList=[]; //定義一個數(shù)組來存放輪播圖的url
    slide.map(item=>{
        imgList.push(item.slide_url); //用js的map方法把圖片的url地址取出來放到數(shù)組里
    });
    wx.previewImage({
        current: imgList[index], // 當前顯示圖片的鏈接,不填則默認為 urls 的第一張
        urls: imgList
    })
  }

五、商品屬性選擇

image

頁面結(jié)構(gòu):整個商品屬性頁的結(jié)構(gòu)是由一些cells組成,所以用weui最合適(插一段:原生的radio真的是很丑,不過weui對它做了改進)
一開始想有weui就簡單多了,直接用form表單的bindsubmit處理就可以了,奈何在weui里使用bindsubmit,取不到radio的值,折騰了很久,還是取不到,但是換成原生的radio竟可以取到??!
image

這個不行,那就換一種吧,用weui radiogroup里的bindchange事件吧,雖然繁瑣了些,但是還是能解決問題的。。
話不多說,看代碼(感覺寫了一些很累贅的代碼。。)

selectVersion(e) {
    const version = e.detail.value;
    const memory = version.split(",")[0];
    const price = version.split(",")[1];
    wx.setStorageSync('memory', memory);
    wx.setStorageSync('price', price);
    this.setData({
      memory,
      price
    });
  },
  selectColor(e) {
    let color = e.detail.value;
    let cover_img=this.data.goods_attrSelect[0].goods_slides[0].slide_url;
    wx.setStorageSync('color', color);
    wx.setStorageSync('cover', cover_img);
    this.setData({
      color,
      cover_img
    });
  },
  colorHasSelected(e) {
    const curcIndex = e.currentTarget.dataset.index ? e.currentTarget.dataset.index : 0;
    console.log(curcIndex);
    this.setData({
      curcIndex
    });
  },
  versionHasSelected(e) {
    const curvIndex = e.currentTarget.dataset.index ? e.currentTarget.dataset.index : 0;
    console.log(curvIndex);
    this.setData({
      curvIndex
    });
  }

對應商品的屬性頁的跳轉(zhuǎn)

邏輯分析:在商品詳情頁中,通過當前商品的id跳轉(zhuǎn)

toSelect(e){
    const id=e.currentTarget.dataset.id;
    wx.navigateTo({
      url:`../selectGoods/selectGoods?id=${id}`
    });
 }

在商品的屬性選擇頁里,同樣是通過id篩選顯示不同商品的屬性選擇信息

onLoad: function (options) {
    const id = options.id;
    console.log(id);
    const goods_attrSelect = app.globalData.goodsDetail.filter(item => {
      return item.id == id;
    });
}

商品屬性的聯(lián)動選擇

既然是商品,沒有屬性選擇怎么行呢?興致一來二話不說就是寫。但是這里有一個難點:用戶的選擇多樣性,難道你會把所有用戶可能做出的選擇都列出來嗎?天哪,商品這么多,這是要累死我嗎?no,no,no,這種方法不可取。哪還有什么解決辦法呢?當時一想到的就是用數(shù)據(jù)緩存,嗯,這種方法可行,但是用緩存存取用戶選擇的值的話,這里有一個很大的問題:微信小程序里的數(shù)據(jù)緩存將data存儲在本地緩存中指定的key中,會覆蓋掉原來該key對應的內(nèi)容,無論是wx.setStorage(異步接口)還是wx.setStorageSync(同步接口),這樣的話,無論用戶選擇了多少個商品,只要key值一樣,緩存數(shù)據(jù)永遠只有一條!?。∥掖藭r的內(nèi)心是痛苦的。

image

有什么方法能讓數(shù)據(jù)緩存不覆蓋原來的值,而是加上去?說實話,這里卡了我好久。廢話不多說,直接上代碼

submit(e) {
    const pre_item = wx.getStorageSync('attr_item');
    const temp = {
      'goods_name': wx.getStorageSync('goods_name'),
      'memory': wx.getStorageSync('memory'),
      'price': wx.getStorageSync('price'),
      'color': wx.getStorageSync('color'),
      'select_num': wx.getStorageSync('select_num'),
      'cover': wx.getStorageSync('cover'),
      'selected': false,
      'isTouchMove': false
    }
    wx.setStorageSync('attr_item', [temp, ...pre_item]); //把獲取到的pre_item和temp的數(shù)據(jù)緩存存入attr_item
    wx.showToast({
      title: '已加入購物車',
      icon: 'success',
      duration: 3000,
      success() {
        setTimeout(() => {
          wx.navigateBack({
            url: "../goods/show"
          });
        }, 1000)
      }
    });
  }

商品數(shù)量的加減操作

實現(xiàn)思路:分別綁定一個事件來操作商品數(shù)量的加減,最后將用戶選擇的數(shù)量設置到數(shù)據(jù)緩存里。
實現(xiàn)代碼:

 data: {
    select_num: 1  //默認選擇為數(shù)量為1
  },
minusCount(e) {    //用戶減操作
    let select_num = this.data.select_num;
    select_num--;
    if (select_num < 1) {
      return;
    }
    this.setData({
      select_num
    });
    wx.setStorageSync('select_num', select_num);
  },
  addCount(e) {     //用戶加操作
    let select_num = this.data.select_num;
    select_num++;
    if (select_num > 5) {
      return;
    }
    this.setData({
      select_num
    });
    wx.setStorageSync('select_num', select_num);
  }

六、購物車操作

image

頁面結(jié)構(gòu)分析:購物車列表用一個彈性布局就搞定。底部的操作欄用固定定位 + 彈性布局就搞定。

<view wx:if="{{cart_list==''}}">
    <view class="empty-cart">
        <view class="cart-icon">
            <image src="../../assets/icons/cart_empty.png" mode="aspectFill" />
        </view>
        <view class="prompt">購物車還是空的</view>
        <button type="warn" class="btn-warn" style="background: #ff6700;" bindtap="goIndex">到小米商城逛逛</button>
    </view>
</view>
<view wx:else>
    <view class="cart-box">
        <view class="cart-list" wx:for="{{cart_list}}" wx:key="{{index}}">
            <view class="cart-item {{item.isTouchMove? 'touch-move-active': ''}}" bindtouchstart="touchstart" bindtouchmove="touchmove" data-index="{{index}}">
                <view class="cart-content">
                    <icon type="{{item.selected?'success':'circle'}}" class="" color="#ff6700" size="20" bindtap="selectList" data-index="{{index}}"
                    />
                    <image src="{{item.cover}}"
                        mode="aspectFill" />
                    <text class="item-title">{{item.goods_name}} {{item.memory}}</text>
                    <text class="item-num">{{item.color}}</text>
                    <text class="item-price">{{item.select_num}}×</text>
                    <text class="item-price">{{item.price}}</text>
                    <view class="del-cart-item" catchtap="delCartItem">刪除</view>
                </view>
            </view>
        </view>
    </view>
    <view class="user-operation">
        <view class="select-all">
            <icon wx:if="{{selectAllStatus}}" type="success" class="total-select" color="#ff6700" bindtap="selectAll" />
            <icon wx:else type="circle" class="total-select" color="#ff6700" size="20" bindtap="selectAll" />
            <text>全選</text>
        </view>
        <view class="total-price">合計:
            <text>{{totalPrice}}元</text>
        </view>
        <view class="btn-primary pay" bindtap="checkOut">結(jié)算</view>
    </view>
</view>

底部操作欄樣式

.user-operation{
    width: 100%;
    height: 100rpx;
    line-height: 100rpx;
    display: flex;
    flex-direction: row;
    justify-content: space-between;
    align-items: center;
    position: fixed;
    left: 0;
    bottom: 0;
}
.select-all,.total-price,.btn-primary.pay{
    flex: 1;  //三個盒子等分所有設備寬度
    font-size: 12pt;
    text-align: center;
}

加入購物車操作

邏輯分析:之前解決數(shù)據(jù)緩存問題,是為加入購物車功能做鋪墊。在商品屬性的級聯(lián)選擇中,已經(jīng)獲得了用戶的所有要加入購物車的數(shù)據(jù),這時候,把數(shù)據(jù)取出來在綁定到購物車頁面上就可以了。

實現(xiàn)代碼:

data: {
    cart_list: [],   //初始化一個空數(shù)組用來存放購物車列表
  },
  goIndex() {  //如果購物車為空,則讓用戶去首頁
    wx.switchTab({
      url: "../index/index"
    })
 },
onShow: function () {
    const attr_item = wx.getStorageSync('attr_item'); //獲取數(shù)據(jù)緩存里將要加入購物車的數(shù)據(jù)
    let cart_list = this.data.cart_list;
    cart_list = [...attr_item]; //把緩存里的數(shù)據(jù)加到購物車列表里
    const select_num = cart_list.map(item => { //獲取用戶每次選擇的數(shù)量
      return item.select_num;
    })
    let goods_sum=select_num.reduce(function(prev,cur){
       return prev+cur;  //用es6的reduce()方法把用戶每次選擇的數(shù)量相加
    });
    wx.setStorageSync('goods_sum', goods_sum);  //再次存入緩存
    this.setData({   //更新購物車列表
      cart_list
    });
  }

購物車全選、反選、計算總價功能

這是一個很經(jīng)典的問題,凡事涉及到購物車的操作,這個功能都是少不了的。

data: {
    cart_list: [],
    totalPrice: 0,
  },
selectList(e) {
    let selectAllStatus = this.data.selectAllStatus;
    const index = e.currentTarget.dataset.index;
    let cart_list = this.data.cart_list;
    // console.log(cart_list[index].selected);
    const selected = cart_list[index].selected;
    cart_list[index].selected = !selected;
    console.log(selected);
    //購物車列表里的條目只要有一個取消,全選就取消
    const symbol = cart_list.some(cart => {  //這里用es6的some()函數(shù)
      return cart.selected === false;
    });
    if (symbol) {  //如果找到false,全選就取消
      this.data.selectAllStatus = false;
    } else {
      this.data.selectAllStatus = true;
    }
    this.setData({  //更新數(shù)據(jù)
      cart_list,
      selectAllStatus: this.data.selectAllStatus
    });
    this.getTotalPrice();
  },
  getTotalPrice() {  //定義一個計算總價的方法
    let cart_list = this.data.cart_list;
    let totalPrice = 0;
    for (let i = 0; i < cart_list.length; i++) {
      if (cart_list[i].selected) {
        totalPrice += parseInt(cart_list[i].select_num) * parseInt(cart_list[i].price);  //注意這里要用parseInt()把數(shù)量和價格取出來
      }
    }
    //更新總價
    this.setData({
      totalPrice
    });
  },
  selectAll(e) {
    let selectAllStatus = this.data.selectAllStatus;
    selectAllStatus = !selectAllStatus;
    let cart_list = this.data.cart_list;
    for (let i = 0; i < cart_list.length; i++) {
      cart_list[i].selected = selectAllStatus; //全選為true,則所有購物車列表為true,全選為false,則所有購物車列表為false
    }
    //更新數(shù)據(jù)
    this.setData({
      cart_list,
      selectAllStatus
    });
    this.getTotalPrice();
  }

刪除購物車操作

data: {
    startX: 0, //開始坐標
    startY: 0,
  },
//滑動事件處理
  touchmove(e) {
    let
      index = e.currentTarget.dataset.index, //獲取當前索引
      startX = this.data.startX, //獲取開始X坐標
      startY = this.data.startY, //獲取開始Y坐標
      touchMoveX = e.changedTouches[0].clientX, //滑動變化坐標
      touchMoveY = e.changedTouches[0].clientY, //滑動變化坐標
      //獲取滑動角度
      angle = this.getAngle({
        X: startX,
        Y: startY
      }, {
        X: touchMoveX,
        Y: touchMoveY
      });
    this.data.cart_list.forEach(function (v, i) {
      v.isTouchMove = false
      
      if (Math.abs(angle) > 30) return;//用戶滑動超過30度,刪除按鈕就不出來 
      if (i == index) {
        if (touchMoveX > startX) //右滑
          v.isTouchMove = false
        else //左滑
          v.isTouchMove = true
      }
    })
    //更新數(shù)據(jù)
    this.setData({
      cart_list: this.data.cart_list
    })
  },
  getAngle(start, end) {
    let X = end.X - start.X,
      Y = end.Y - start.Y
    //返回角度 /Math.atan()返回數(shù)字的反正切值
    return 360 * Math.atan(Y / X) / (2 * Math.PI);
  },
  delCartItem(e) {
    const index=e.currentTarget.dataset.index;  //獲取購物車要刪除商品的下標
    this.data.cart_list.splice(index, 1);
    wx.clearStorageSync("select_num");
    this.setData({
      cart_list: this.data.cart_list
    });
  }

七、商品的匹配及搜索功能實現(xiàn)

image

頁面結(jié)構(gòu)分析:先把搜索提示框固定定位到搜索欄下方,如果搜索到商品,則用商品展示模版輸出該數(shù)據(jù)

<import src="../../templates/goods_list/goods_list.wxml" />
<view class="weui-search-bar">
    <view class="weui-search-bar__form">
        <view class="weui-search-bar__box">
            <icon class="weui-icon-search_in-box" type="search" size="14"></icon>
            <input type="text" class="weui-search-bar__input" placeholder="搜索" placeholder-class="plac" bindinput="searchInput" />
        </view>
    </view>
    <view class="weui-search-bar__cancel-btn" bindtap="search">搜索</view>
</view>
<view class="search-list {{is_hidden?'hidden':''}}">
    <block wx:for="{{search_list}}" wx:key="{{item.id}}">
        <text class="search-item" bindtap="showItemDetail" data-header="{{item.header}}">{{item.header}}</text>
    </block>
</view>
<template is="goods_list" data="{{goods_list}}"></template>

邏輯分析:
我的實現(xiàn)思路是:

  • 如果匹配到商品,搜索框下方就要讓搜索提示框顯示;
  • 當用戶輸入搜索的內(nèi)容為空,搜索提示框隱藏
  • 用戶點擊搜索按鈕,則把所有匹配到的商品列表顯示出來,注意要模糊搜索,不區(qū)分大小寫,提高用戶體驗;
  • 用戶點擊匹配到的商品條目,則搜索該商品

實現(xiàn)方法:

  • filter()+indexOf()+toLowerCase();

代碼如下:

import showDetail from "../../modules/showDetail";
const app=getApp();

Page({

  /**
   * 頁面的初始數(shù)據(jù)
   */
  data: {
    goods_list:[],
    search_list:[],
    is_hidden:true
  },
  searchInput(e){
    let search_list=this.getList(e.detail.value); //獲取用戶的輸入值
    if(e.detail.value==""){ //如果用戶沒輸入,搜索提示列表置空,并且讓搜索提示框隱藏
      search_list=[]; 
      this.data.is_hidden=true;
    }else{
      this.data.is_hidden=false;
    } 
    //更新數(shù)據(jù)
    this.setData({
      search_list,
      is_hidden:this.data.is_hidden
    });
  },
  search(e){
     //按關鍵字篩選商品,如果關鍵字匹配到商品名稱,則返回該商品列表
    const keywords=wx.getStorageSync('keywords');
    wx.showLoading({
      title: '請稍等',
    });
    setTimeout(()=>{
      this.setData({
        goods_list:this.getList(keywords),
        is_hidden:true  //如果搜索到了商品,就讓搜索框隱藏
      });
      wx.hideLoading();
    },500);
  },
  showDetail,
  showItemDetail(e){
    //按關鍵字篩選商品,如果關鍵字匹配到商品名稱,則返回該商品列表
      const header=e.currentTarget.dataset.header.toLowerCase(); 
      console.log(header);
      wx.showLoading({
        title: '請稍等',
      })
      setTimeout(()=>{
        wx.hideLoading()
        this.setData({
          goods_list:this.getList(header),
          is_hidden:true
        });
      },500)
  },
 /**
   * attr:需要匹配篩選的數(shù)據(jù)
   */
  getList(attr){  //定義一個獲取商品標題的方法
    return app.globalData.phone.goods_list.filter(item=>{
      return item.header.toString().toLowerCase().indexOf(attr)>-1;
    });
  }
})

八、收貨地址頁

image

實現(xiàn)思路:用數(shù)據(jù)緩存和數(shù)據(jù)綁定來控制input的disabled實現(xiàn)實時編輯
代碼如下:

// pages/address/address.js
Page({
  data: {
    receiverName: "",
    mobile: "",
    addressDetail: "",
    postCode: "",
    isDisabled: false,
    isComplete: false,
    buttonTitle: "保存"
  },
  formSubmit(e) {
    const addrInfo = e.detail.value;
    let {receiverName,mobile,addressDetail,postCode}=addrInfo; //把data里的數(shù)據(jù)結(jié)構(gòu)出來
    if(receiverName==""||mobile==""||addressDetail==""||postCode==""){
      this.data.isComplete=false;
      wx.showModal({
        title:"提示",
        content:"請完善信息",
        showCancel:false
      }); 
    }else if(!/^[1][3,4,5,7,8]\d{9}$/.test(mobile)){ //判斷手機號格式
      wx.showModal({
        title:"提示",
        content:"手機號格式不規(guī)范",
        showCancel:false
      }); 
    }else if(!/^[0-9]{6}$/.test(postCode)){
      wx.showModal({
        title:"提示",
        content:"郵政編碼不規(guī)范",
        showCancel:false
      }); 
    }else{
      this.data.isComplete=true;
      wx.setStorageSync('addrInfo', addrInfo);
      
    }
    this.setData({
        isDisabled: true,
        isComplete: this.data.isComplete
      });
  },
  updateAddr(e){
    this.setData({
      isDisabled:false,
      isComplete:false,
      buttonTitle: "保存"
    });
  },
  /**
   * 生命周期函數(shù)--監(jiān)聽頁面加載
   */
  onLoad: function (options) {
    
    let addrInfo=wx.getStorageSync("addrInfo");
    console.log(addrInfo);
    let {receiverName,mobile,addressDetail,postCode}=addrInfo;
    this.setData({
      receiverName,
      mobile,
      addressDetail,
      postCode,
      isDisabled: true,
      isComplete:true,
      buttonTitle: "修改"
    });
  }
})

總結(jié):

在做這個項目的時候遇到了很多問題,中途因為一個問題都要卡很久,但是現(xiàn)在想想,經(jīng)歷過肯定是能學到東西的,之前對于一些東西想都不敢想,但是沒關系,只要你想做,那就去做吧,去網(wǎng)上查資料,多去社區(qū)問問大牛,你總是能學到東西的。對于這個項目,很多功能都還沒完善,比如商品評論,生成訂單等等,但是我會不定時的更新??,有時間的話,我會用mpvue或者wepy改寫,又能學到新技術??

最后

碼字不易,如果大家喜歡的話,就star一下吧,項目地址,我會不定時更新的哦。
項目還存在很多缺陷,希望大家提出寶貴建議??

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容