微信小程序洲守,讓你一見傾心
前言
小程序發(fā)布以來疑务,憑借無需安裝、用完即走梗醇、觸手可及知允、無需注冊、無需登錄叙谨、以及社交裂變等多個(gè)優(yōu)勢温鸽,一路高歌,變得愈來愈火爆手负,它革命性的降低了移動(dòng)應(yīng)用的開發(fā)成本涤垫,也正好迎合了用戶的使用應(yīng)用的習(xí)慣。小程序魅力如此之大竟终,作為一枚程序猿蝠猬,我想怎么不自己做一個(gè)呢?話不多說统捶,咱擼起袖子就是干
準(zhǔn)備工作
- 前端開發(fā)利器:VSCode
- 調(diào)試:微信開發(fā)者工具
- 自己Mock的一些數(shù)據(jù)
- 微信開發(fā)文檔
項(xiàng)目目錄結(jié)構(gòu)
├── assets 用到的一些圖標(biāo)文件
├── lib
├── weui.wxss 引用了weui
├── modules
├── showDetail.js 跳轉(zhuǎn)展示商品詳情的公共js文件
├── showcDetail.js
├── pages 項(xiàng)目的各個(gè)頁面
├── index 商城首頁
├── categories 商品分類頁
├── discovery 發(fā)現(xiàn)頁
├── channel 商品頻道目錄
├── phone 手機(jī)頻道
├── tv 電視頻道
├── computer 電腦頻道
├── cart 購物車
├── mine 個(gè)人信息頁
├── goods 商品詳情頁
├── selectGoods 商品屬性選擇頁
├── search 商品搜索頁
├── addr 收貨地址頁
├── template 使用到的模版文件
├── slide 輪播圖模版
├── goods_list 商品展示模版
├── cover 商品展示模版
├── util 使用到的工具類
├── mock.js 項(xiàng)目中使用到的一些數(shù)據(jù)
├── app.js 項(xiàng)目邏輯
├── app.wxss 項(xiàng)目公共樣式表
└── app.json 項(xiàng)目公共設(shè)置
功能的展示與實(shí)現(xiàn)
一榆芦、商城首頁
頁面結(jié)構(gòu)分析:
頂部搜索條
這里看上去是一個(gè)搜索框,但其實(shí)喘鸟,它要實(shí)現(xiàn)的僅僅是個(gè)頁面跳轉(zhuǎn)功能匆绣,只要把它的disabled
設(shè)置為true
就可以了,另外要想讓它placeholder占位符居中顯示的話什黑,微信小程序提供了一個(gè)placeholder-class
的屬性崎淳,通過它可以改變placeholder的樣式。輪播圖區(qū)域
這里微信小程序給我們提供了swiper組件愕把,直接用就可以了凯力。但是輪播圖在各個(gè)頁面都可能存在,只是其中所顯示的圖片不一樣而已礼华,所以使用組件化思想咐鹤,把它寫成一個(gè)模版,哪里要使用圣絮,就引入這個(gè)模版即可祈惶。
<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>
使用時(shí),這樣引入
<import src="../../../templates/slide/slide.wxml" />
<view class="container">
<template is="slide" data="{{slides}}"></template>
</view>
- 商城導(dǎo)航區(qū)、活動(dòng)區(qū)
這里只是個(gè)簡單的布局捧请,就不贅述了凡涩。但是需要注意的是在微信小程序里,強(qiáng)烈推薦使用彈性布局 - 首頁商品展示區(qū)
這里的商品都是分塊展示疹蛉,很有規(guī)律活箕,因此整個(gè)商品展示都可以直接用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 -->
這里有個(gè)細(xì)節(jié)可款,每個(gè)版塊里的商品會(huì)分成“新品”育韩、“立減”(即有折扣)、“無折扣”三種闺鲸,著該怎么去做呢筋讨?這里我用了一個(gè)巧妙的方法:給每個(gè)商品的class
里綁定布爾值is_new
和on_sale
通過三元運(yùn)算符判斷是否給該商品掛載一個(gè)類名,再使用偽元素給該商品打上“新品”或“立減”的標(biāo)簽如下:
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{ /*新品標(biāo)簽樣式*/
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{ /*立減標(biāo)簽樣式*/
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ù)每個(gè)商品的id
來跳到對應(yīng)商品的詳情頁即可悉罕,很顯然這個(gè)方法在多個(gè)頁面都要使用的,所以使用模塊化思想立镶,創(chuàng)建一個(gè)modules
文件夾壁袄,把方法寫在單獨(dú)的js文件里,并向外輸出
const showDetail=(e)=>{
const id=e.currentTarget.dataset.pid; //獲取每個(gè)商品的id
wx.navigateTo({
url: `/pages/goods/show?id=${id}`
})
};
export default showDetail;
哪里要使用媚媒,就用import引入
import showDetail from "../../modules/showDetail";
二然想、商品分類頁
頁面結(jié)構(gòu)分析:
商品分類頁分為左側(cè)的商品分類菜單和右邊的商品分類展示區(qū),
用兩個(gè)
scroll-view
就可以了欣范,左右兩邊都設(shè)置scroll-y
讓它們垂直方向滾動(dòng),此外令哟,scroll-view
還有一個(gè)scroll-into-view
屬性能讓我們實(shí)現(xiàn)類似a
標(biāo)簽的錨點(diǎn)功能恼琼,scroll-into-view
的值是某個(gè)子元素的id,但是此處有一個(gè)小坑屏富,這個(gè)id不能以數(shù)字開頭當(dāng)時(shí)查了一下文檔就開做了晴竞,于是乎給左側(cè)菜單取了些數(shù)字id,現(xiàn)在想起來當(dāng)時(shí)我太自以為然了 狠半,此外如果內(nèi)容太多噩死,是會(huì)產(chǎn)生滾動(dòng)條的,如圖:
這樣看起來也太丑了神年。已维。
**解決辦法:給全局樣式加入下面的樣式
//隱藏滾動(dòng)條
::-webkit-scrollbar{
height: 0;
width: 0;
color: transparent;
}
嗯,beautiful R讶铡垛耳!
商品分類功能
邏輯分析:給頁面注冊個(gè)curIndex(當(dāng)前選中菜單的下標(biāo)),如果當(dāng)前下標(biāo)和選中的菜單下標(biāo)相同,則處于激活狀態(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:"手機(jī)",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:"耳機(jī)",id:"headset"},
{name:"音箱",id:"voicebox"},
{name:"生活",id:"life"},
{name:"服務(wù)",id:"service"},
{name:"米粉卡",id:"card"}
],
curIndex:0, //初始化當(dāng)前下標(biāo)為0
toView:"new", //默認(rèn)顯示“新品展示”
detail:[]
},
switchCategory(e){
const curIndex=e.currentTarget.dataset.index?e.currentTarget.dataset.index:0; //獲取每個(gè)菜單的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)分析:
里面展示了一些商品宣傳視頻(當(dāng)時(shí)還是不太想切太多的頁面??)這里用彈性布局+video組件就搞定了栈雳。這里是文檔
四、商品詳情頁
頁面結(jié)構(gòu)分析:
商品詳情頂部由一個(gè)swiper組成缔莲,中間部分由一些cells組成(weui)點(diǎn)擊這里快速查看
底部是商品的概述及參數(shù)配置兩部分組成哥纫,這個(gè)還是比較簡單的, 給兩個(gè)元素分別綁定一個(gè)布爾值來控制誰顯示誰隱藏痴奏。
當(dāng)然蛀骇,要使用weui必須引入它的樣式文件,我們在app.wxss里引入,然后全局都可以使用了
@import "./lib/weui.wxss";
嗯,weui的官網(wǎng)和github地址自然少不了。weui官網(wǎng) 强窖、weui github官方文檔敞咧,在github上閱讀代碼是一個(gè)非常有效的學(xué)習(xí)方式,但是文件夾嵌套太深找個(gè)文件也不容易富雅,這里奉上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>
商品詳情頁的顯示
邏輯分析:
每個(gè)商品通過id來跳轉(zhuǎn)到相應(yīng)的詳情頁,但是這個(gè)id會(huì)在哪里呢因?yàn)橄冗@個(gè)詳情頁是通過一個(gè)個(gè)商品來打開的,所以在商品詳情頁加載時(shí)屠列,可以在 onLoad 中獲取打開當(dāng)前頁面所調(diào)用的 query 參數(shù)(是條json數(shù)據(jù)),因?yàn)樵趕howDetail里只用了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來篩選顯示對應(yīng)的商品
});
this.setData({
goods:goods[0] //因?yàn)閕d是唯一的笛洛,所以上面篩選出來的數(shù)組只有一條數(shù)據(jù),這條數(shù)據(jù)就是要顯示的商品數(shù)據(jù)
});
}
商品圖片預(yù)覽實(shí)現(xiàn)
微信小程序?yàn)槲覀兲峁┝?a target="_blank">wx.previewImage()方法來實(shí)現(xiàn)圖片的預(yù)覽乃坤,實(shí)現(xiàn)方法如下:
previewImage(e){
const index=e.currentTarget.dataset.index; //獲取swiper里的圖片的下標(biāo)
const slide=this.data.goods.goods_slides; //獲取商品輪播圖
const imgList=[]; //定義一個(gè)數(shù)組來存放輪播圖的url
slide.map(item=>{
imgList.push(item.slide_url); //用js的map方法把圖片的url地址取出來放到數(shù)組里
});
wx.previewImage({
current: imgList[index], // 當(dāng)前顯示圖片的鏈接苛让,不填則默認(rèn)為 urls 的第一張
urls: imgList
})
}
五、商品屬性選擇
頁面結(jié)構(gòu):整個(gè)商品屬性頁的結(jié)構(gòu)是由一些cells組成湿诊,所以用weui最合適(插一段:原生的radio真的是很丑狱杰,不過weui對它做了改進(jìn))
一開始想有weui就簡單多了,直接用form表單的
bindsubmit
處理就可以了厅须,奈何在weui里使用bindsubmit仿畸,取不到radio的值,折騰了很久朗和,還是取不到错沽,但是換成原生的radio竟可以取到!眶拉!這個(gè)不行千埃,那就換一種吧,用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
});
}
對應(yīng)商品的屬性頁的跳轉(zhuǎn)
邏輯分析:在商品詳情頁中备韧,通過當(dāng)前商品的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)動(dòng)選擇
既然是商品,沒有屬性選擇怎么行呢织堂?興致一來二話不說就是寫叠艳。但是這里有一個(gè)難點(diǎn):用戶的選擇多樣性,難道你會(huì)把所有用戶可能做出的選擇都列出來嗎易阳?天哪附较,商品這么多,這是要累死我嗎潦俺?no拒课,no,no事示,這種方法不可取早像。哪還有什么解決辦法呢?當(dāng)時(shí)一想到的就是用數(shù)據(jù)緩存肖爵,嗯卢鹦,這種方法可行,但是用緩存存取用戶選擇的值的話劝堪,這里有一個(gè)很大的問題:微信小程序里的數(shù)據(jù)緩存將data存儲(chǔ)在本地緩存中指定的key中冀自,會(huì)覆蓋掉原來該key對應(yīng)的內(nèi)容,無論是wx.setStorage(異步接口)還是wx.setStorageSync(同步接口)秒啦,這樣的話熬粗,無論用戶選擇了多少個(gè)商品,只要key值一樣帝蒿,緩存數(shù)據(jù)永遠(yuǎn)只有一條!O锪葛超!我此時(shí)的內(nèi)心是痛苦的。
有什么方法能讓數(shù)據(jù)緩存不覆蓋原來的值延塑,而是加上去绣张?說實(shí)話,這里卡了我好久关带。廢話不多說侥涵,直接上代碼
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ù)量的加減操作
實(shí)現(xiàn)思路:分別綁定一個(gè)事件來操作商品數(shù)量的加減沼撕,最后將用戶選擇的數(shù)量設(shè)置到數(shù)據(jù)緩存里。
實(shí)現(xiàn)代碼:
data: {
select_num: 1 //默認(rèn)選擇為數(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);
}
六芜飘、購物車操作
頁面結(jié)構(gòu)分析:購物車列表用一個(gè)彈性布局就搞定务豺。底部的操作欄用固定定位 + 彈性布局就搞定。
<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">合計(jì):
<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; //三個(gè)盒子等分所有設(shè)備寬度
font-size: 12pt;
text-align: center;
}
加入購物車操作
邏輯分析:之前解決數(shù)據(jù)緩存問題嗦明,是為加入購物車功能做鋪墊笼沥。在商品屬性的級聯(lián)選擇中,已經(jīng)獲得了用戶的所有要加入購物車的數(shù)據(jù)娶牌,這時(shí)候奔浅,把數(shù)據(jù)取出來在綁定到購物車頁面上就可以了。
實(shí)現(xiàn)代碼:
data: {
cart_list: [], //初始化一個(gè)空數(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ì)算總價(jià)功能
這是一個(gè)很經(jīng)典的問題鉴裹,凡事涉及到購物車的操作舞骆,這個(gè)功能都是少不了的。
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);
//購物車列表里的條目只要有一個(gè)取消壹罚,全選就取消
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() { //定義一個(gè)計(jì)算總價(jià)的方法
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ù)量和價(jià)格取出來
}
}
//更新總價(jià)
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, //開始坐標(biāo)
startY: 0,
},
//滑動(dòng)事件處理
touchmove(e) {
let
index = e.currentTarget.dataset.index, //獲取當(dāng)前索引
startX = this.data.startX, //獲取開始X坐標(biāo)
startY = this.data.startY, //獲取開始Y坐標(biāo)
touchMoveX = e.changedTouches[0].clientX, //滑動(dòng)變化坐標(biāo)
touchMoveY = e.changedTouches[0].clientY, //滑動(dòng)變化坐標(biāo)
//獲取滑動(dòng)角度
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;//用戶滑動(dòng)超過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()返回?cái)?shù)字的反正切值
return 360 * Math.atan(Y / X) / (2 * Math.PI);
},
delCartItem(e) {
const index=e.currentTarget.dataset.index; //獲取購物車要?jiǎng)h除商品的下標(biāo)
this.data.cart_list.splice(index, 1);
wx.clearStorageSync("select_num");
this.setData({
cart_list: this.data.cart_list
});
}
七辨泳、商品的匹配及搜索功能實(shí)現(xiàn)
頁面結(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>
邏輯分析:
我的實(shí)現(xiàn)思路是:
- 如果匹配到商品菠红,搜索框下方就要讓搜索提示框顯示第岖;
- 當(dāng)用戶輸入搜索的內(nèi)容為空,搜索提示框隱藏
- 用戶點(diǎn)擊搜索按鈕试溯,則把所有匹配到的商品列表顯示出來蔑滓,注意要模糊搜索,不區(qū)分大小寫遇绞,提高用戶體驗(yàn)键袱;
- 用戶點(diǎn)擊匹配到的商品條目,則搜索該商品
實(shí)現(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){
//按關(guān)鍵字篩選商品,如果關(guān)鍵字匹配到商品名稱付鹿,則返回該商品列表
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){
//按關(guān)鍵字篩選商品蚜迅,如果關(guān)鍵字匹配到商品名稱,則返回該商品列表
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){ //定義一個(gè)獲取商品標(biāo)題的方法
return app.globalData.phone.goods_list.filter(item=>{
return item.header.toString().toLowerCase().indexOf(attr)>-1;
});
}
})
八俊抵、收貨地址頁
實(shí)現(xiàn)思路:用數(shù)據(jù)緩存和數(shù)據(jù)綁定來控制input的disabled實(shí)現(xiàn)實(shí)時(shí)編輯
代碼如下:
// 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)){ //判斷手機(jī)號格式
wx.showModal({
title:"提示",
content:"手機(jī)號格式不規(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é):
在做這個(gè)項(xiàng)目的時(shí)候遇到了很多問題谁不,中途因?yàn)橐粋€(gè)問題都要卡很久,但是現(xiàn)在想想务蝠,經(jīng)歷過肯定是能學(xué)到東西的拍谐,之前對于一些東西想都不敢想,但是沒關(guān)系馏段,只要你想做轩拨,那就去做吧,去網(wǎng)上查資料院喜,多去社區(qū)問問大牛亡蓉,你總是能學(xué)到東西的。對于這個(gè)項(xiàng)目喷舀,很多功能都還沒完善砍濒,比如商品評論,生成訂單等等硫麻,但是我會(huì)不定時(shí)的更新??爸邢,有時(shí)間的話,我會(huì)用mpvue或者wepy改寫拿愧,又能學(xué)到新技術(shù)??
最后:
碼字不易杠河,如果大家喜歡的話,就star一下吧,項(xiàng)目地址浇辜,我會(huì)不定時(shí)更新的哦券敌。
項(xiàng)目還存在很多缺陷,希望大家提出寶貴建議??