项目目录
BIJIAN
app.json
{ "pages":[ "pages/home/home", "pages/category/category", "pages/shopcar/shopcar", "pages/center/center", "pages/detail/detail", "pages/search/search", "pages/searchlist/searchlist", "pages/telform/telform", "pages/auth/auth" ], "window":{ "backgroundTextStyle":"dark", "navigationBarBackgroundColor": "#14c145", "navigationBarTitleText": "购物", "navigationBarTextStyle":"white" }, "tabBar": { "list": [{ "pagePath": "pages/home/home", "text": "主页", "iconPath": "images/home.png", "selectedIconPath": "images/home_light.png" }, { "pagePath": "pages/category/category", "text": "分类", "iconPath": "images/search.png", "selectedIconPath": "images/search_light.png" }, { "pagePath": "pages/shopcar/shopcar", "text": "购物车", "iconPath": "images/camera.png", "selectedIconPath": "images/camera_light.png" }, { "pagePath": "pages/center/center", "text": "我的", "iconPath": "images/my.png", "selectedIconPath": "images/my_light.png" }] }, "style": "v2", "sitemapLocation": "sitemap.json", "useExtendedLib": { "weui": true } }
components
search
<!--components/search/Search.wxml--> <input placeholder="请搜索" bindtap="handleTap"/>
/* components/search/Search.wxss */ input{ border:2rpx solid black; border-radius: 10rpx; margin:10rpx; padding:10rpx; height: 30rpx; background-color: white; }
// components/search/Search.js Component({ /** * 组件的属性列表 */ properties: { }, /** * 组件的初始数据 */ data: { }, /** * 组件的方法列表 */ methods: { handleTap(){ this.triggerEvent("event") } } })
utils
auth.js
function CheckAuth(callback){ if(wx.getStorageSync('tel')){ callback()//处理业务 }else{ if(wx.getStorageSync('token')){ wx.navigateTo({ url: '/pages/telform/telform', }) }else{ wx.navigateTo({ url: '/pages/auth/auth', }) } } } export default CheckAuth
request.js
function request(params,isHeader=false){ return new Promise((resolve,reject)=>{ wx.showLoading({ title: '正在加载中', }) wx.request({ ...params, url: 'http://localhost:5000'+params.url, success:(res)=>{ if(isHeader){ resolve({ list:res.data, total:res.header['X-Total-Count'] }) } resolve(res.data) }, fail:(err)=>{ reject(err) }, complete:()=>{ wx.hideLoading({ success: (res) => {}, }) } }) }) } export default request
pages
auth
<!--pages/auth/auth.wxml--> <button type="primary" bindtap="handleAuth">微信授权</button>
// pages/auth/auth.js Page({ handleAuth(){ wx.getUserProfile({ desc: '用于完善会员资料', success:(res)=>{ // console.log(res.userInfo) wx.setStorageSync('token', res.userInfo) wx.navigateTo({ url: '/pages/telform/telform', }) } }) } })
category
<!--pages/category/category.wxml--> <mp-vtabs vtabs="{{vtabs}}" activeTab="{{activeTab}}" class="test"> <!-- 必须要有title字段 --> <block wx:for="{{vtabs}}" wx:key="title" > <mp-vtabs-content tabIndex="{{index}}"> <view class="vtabs-content-item"> <view wx:for="{{item.goods}}" wx:key="id" class="item" bindtap="handleTap" data-id="{{item.id}}" data-name="{{item.title}}"> <image src="http://localhost:5000{{item.poster}}" mode="widthFix"/> <view> {{item.title}}</view> </view> </view> </mp-vtabs-content> </block> </mp-vtabs>
/* pages/category/category.wxss */ page{ background-color: #FFFFFF; height: 100%; } .vtabs-content-item{ display: flex; flex-wrap: wrap; height: 100vh; } .vtabs-content-item .item{ width: 50%; padding:30rpx; box-sizing: border-box; } .item image{ width: 200rpx; } .item view{ text-align: center; font-size: 13px; }
// pages/category/category.js import request from '../../utils/request' Page({ /** * 页面的初始数据 */ data: { vtabs:[], activeTab:0 }, /** * 生命周期函数--监听页面加载 */ onLoad(options) { request({ url:"/categories?_embed=goods" }).then(res=>{ // console.log(res) this.setData({ vtabs:res }) }) }, handleTap(event){ // console.log(event.currentTarget.dataset) var id = event.currentTarget.dataset.id var name = event.currentTarget.dataset.name wx.navigateTo({ url: `/pages/detail/detail?id=${id}&name=${name}`, }) } })
{ "usingComponents": { "mp-vtabs": "@miniprogram-component-plus/vtabs", "mp-vtabs-content": "@miniprogram-component-plus/vtabs-content" }, "navigationBarTitleText": "分类" }
center
<view class="userInfo"> <image src="{{userInfo.avatarUrl}}" bindtap="handleTap"></image> <view>{{userInfo.nickName}}</view> </view> <mp-cells ext-class="my-cells" > <mp-cell value="完善信息"> <mp-icon slot="icon" type="field" icon="me" color="#14c145" size="{{25}}"></mp-icon> <mp-icon slot="icon" type="field" icon="arrow" size="{{10}}" slot="footer"></mp-icon> </mp-cell> <mp-cell value="个性设置"> <mp-icon slot="icon" type="field" icon="like" color="#14c145" size="{{25}}"></mp-icon> <mp-icon slot="icon" type="field" icon="arrow" size="{{10}}" slot="footer"></mp-icon> </mp-cell> </mp-cells>
/* pages/center/center.wxss */ .userInfo{ background-color: #14c145; text-align: center; } .userInfo image{ width: 200rpx; height: 200rpx; border-radius: 100rpx; }
// pages/center/center.js import CheckAuth from "../../utils/auth" Page({ /** * 页面的初始数据 */ data: { userInfo:null }, /** * 生命周期函数--监听页面显示 */ onShow() { CheckAuth(()=>{ // console.log("我的") this.setData({ userInfo:wx.getStorageSync('token') }) }) }, handleTap(){ //打开摄像头/相册 wx.chooseImage({ count: 1, sizeType: ['original', 'compressed'], sourceType: ['album', 'camera'], success : (res) => { // tempFilePath可以作为img标签的src属性显示图片 const tempFilePaths = res.tempFilePaths // console.log(tempFilePaths) this.setData({ userInfo:{ ...this.data.userInfo, avatarUrl:tempFilePaths[0] } }) wx.setStorageSync('token', { ...wx.getStorageSync('token'), avatarUrl:tempFilePaths[0] }) } }) } })
{ "usingComponents": { "mp-cells": "weui-miniprogram/cells/cells", "mp-cell": "weui-miniprogram/cell/cell", "mp-icon": "weui-miniprogram/icon/icon" }, "navigationBarTitleText": "我的" }
detail
<!--pages/detail/detail.wxml--> <swiper> <swiper-item wx:for="{{info.slides}}" wx:key="index"> <image src="http://localhost:5000{{item}}" mode="aspectFit" bindtap="handleTap" data-current="http://localhost:5000{{item}}"/> </swiper-item> </swiper> <mp-sticky offset-top="0"> <view class="detailtabbar"> <view class="{{current===0?'active':''}}" bindtap="handleActive" data-index="{{0}}">商品详情</view> <view class="{{current===1?'active':''}}" bindtap="handleActive" data-index="{{1}}">用户评价</view> </view> </mp-sticky> <view wx:if="{{current===0}}"> <view style="color: gray;">{{info.feature}}</view> <image wx:for="{{info.desc}}" wx:key="index" src="{{item}}" mode="widthFix" style="width: 100%;"/> </view> <view wx:else> <view wx:for="{{commentList}}" wx:key="index" style="border-bottom: 5rpx solid gray;"> <view class="user"> <image src="http://localhost:5000{{item.userImageUrl}}" mode="widthFix" class="left"/> <view class="left">{{item.nickname}}</view> <view class="right">{{item.creationTime}}</view> </view> <view class="content">{{item.content}}</view> <view class="content"> <image src="http://localhost:5000{{item.imgUrl}}" mode="widthFix"/> </view> </view> </view> <view class="bottom"> <view style="background:#ffd591;" bindtap="handleChange">跳转购物车</view> <view style="background:#F76260;" bindtap="handleAdd">加入购物车</view> </view>
/* pages/detail/detail.wxss */ swiper image{ width: 100%; height: 200px; } swiper{ height: 200px; } .detailtabbar{ width: 100vw; height: 100rpx; line-height: 100rpx; text-align:center; display: flex; background-color: white; padding:20rpx; } .detailtabbar view{ flex:1 } .detailtabbar .active{ border-bottom:3rpx solid red; } .user{ overflow: hidden; padding:20rpx; } .user image{ width: 100rpx; border-radius: 50%; } .user .left{ float:left; height: 100rpx; line-height: 100rpx; } .user .right{ float:right; height: 100rpx; line-height: 100rpx; } .content{ padding:20rpx; } .content image{ width: 200rpx; } .bottom{ height: 100rpx; line-height: 100rpx; text-align: center; position: fixed; bottom: 0; left:0; width: 100%; background-color: white; display: flex; } .bottom view{ flex:1; color:white; }
// pages/detail/detail.js import request from "../../utils/request" import CheckAuth from "../../utils/auth" Page({ /** * 页面的初始数据 */ data: { info:null, current: 0, commentList: [] }, /** * 生命周期函数--监听页面加载 */ onLoad(options) { // console.log(options) wx.setNavigationBarTitle({ title: options.name, }) this.getDetailInfo(options.id) this.getCommentInfo() }, getDetailInfo(id){ request({ url:`/goods/${id}` }).then(res=>{ // console.log(res) this.setData({ info:res }) }) }, getCommentInfo(){ request({ url:"/comments" }).then(res=>{ this.setData({ commentList:res }) }) }, handleTap(event){ // console.log(event) // console.log(event.currentTarget.dataset.current) wx.previewImage({ // 当前显示图片的http链接 current:event.currentTarget.dataset.current, // 需要预览的图片http链接列表 urls: this.data.info.slides.map(item=>`http://localhost:5000${item}`), }) }, handleActive(event){ this.setData({ current:event.currentTarget.dataset.index }) }, handleChange(){ wx.switchTab({ url: '/pages/shopcar/shopcar', }) }, /* 1. 判断本地存储是否有手机号信息,如果有直接加入 2. 没有手机号,判断是否有token信息,如果有,引导调整手机号绑定 3 没有token授权信息, 我们引导用户授权页面 */ handleAdd(){ CheckAuth(()=>{ let nickName = wx.getStorageSync('token').nickName let tel = wx.getStorageSync('tel') var goodId = this.data.info.id // console.log(nickName,tel,goodId) // 晨曦生辉耀匕尖 789 1 request({ url:"/carts", data:{ nickName, tel, goodId } }).then(res=>{ // console.log(res) if(res.length===0){ return request({ url:"/carts", method:"post", data:{ "username": nickName, "tel": tel, "goodId": goodId, "number": 1, "checked": false } }) }else{ return request({ url:`/carts/${res[0].id}`, method:"put", data:{ ...res[0], number:res[0].number + 1 } }) } }).then(res=>{ wx.showToast({ title: '加入购物车成功', }) }) }) } })
{ "usingComponents": { "mp-sticky": "@miniprogram-component-plus/sticky" } }
home
<swiper indicator-dots="{{true}}"> <swiper-item wx:for="{{looplist}}" wx:key="index"> <image src="http://localhost:5000{{item.url}}" mode="widthFix"/> </swiper-item> </swiper> <mp-sticky offset-top="0"> <view style="width: 100vw;"> <bijian-search bindevent="handleEvent"></bijian-search> </view> </mp-sticky> <view wx:for="{{goodlist}}" wx:key="index" class="goodbox" bindtap="handleChangePage" data-id="{{item.id}}" data-name="{{item.title}}"> <image src="http://localhost:5000{{item.poster}}" mode="widthFix"/> <view> <view>{{item.title}}</view> <view style="color: red;">价格:¥{{item.price}}</view> <view>好评率:{{item.goodcomment}}</view> </view> </view>
/* pages/home/home.wxss */ swiper image{ width: 100%; } swiper{ height: 297rpx; } .goodbox{ overflow: hidden; padding: 20rpx; } .goodbox image{ width: 200rpx; float: left; }
// pages/home/home.js import request from "../../utils/request" Page({ /** * 页面的初始数据 */ data: { looplist:[], goodlist:[] }, current:1, total:0, /** * 生命周期函数--监听页面加载 */ onLoad(options) { this.renderSwiper() this.renderGoods() }, renderSwiper(){ request({ url:"/recommends" }).then(res=>{ this.setData({ looplist:res }) }) }, renderGoods(){ request({ url:`/goods?_page=${this.current}&_limit=5` },true).then(res=>{ this.total = Number(res.total), this.setData({ goodlist:[...this.data.goodlist,...res.list] }) }) }, /** * 页面相关事件处理函数--监听用户下拉动作 */ onPullDownRefresh() { // console.log("下拉刷新") setTimeout(()=>{ //更新数据了 wx.stopPullDownRefresh() //停止下拉刷新 },1000) }, /** * 页面上拉触底事件的处理函数 */ onReachBottom() { if(this.data.goodlist.length===this.total){ return } this.current++ this.renderGoods() }, /** * 用户点击右上角分享 */ onShareAppMessage() { }, handleEvent(){ wx.navigateTo({ url: '/pages/search/search', }) }, handleChangePage(event){ // console.log(event.currentTarget.dataset) var id = event.currentTarget.dataset.id var name = event.currentTarget.dataset.name wx.navigateTo({ url: `/pages/detail/detail?id=${id}&name=${name}`, }) } })
{ "usingComponents": { "bijian-search":"../../components/search/Search", "mp-sticky": "@miniprogram-component-plus/sticky" }, "navigationBarTitleText": "主页", "enablePullDownRefresh": true }
search
<!--pages/search/search.wxml--> <mp-searchbar bindselectresult="selectResult" search="{{search}}"></mp-searchbar>
// pages/search/search.js import request from '../../utils/request' Page({ /** * 页面的初始数据 */ data: { }, /** * 生命周期函数--监听页面加载 */ onLoad(options) { this.setData({ search: this.search.bind(this) }) }, search(value){ return Promise.all([ request({ url:`/categories?title_like=${value}` }), request({ url:`/goods?title_like=${value}` }) ]).then(res=>{ return [...res[0].map(item=>({ ...item, text:item.title, type:1 })),...res[1].map(item=>({ ...item, text:item.title, type:2 }))] }) }, selectResult(event){ // console.log(event.detail.item) if(event.detail.item.type===1){ wx.navigateTo({ // url: `/pages/searchlist/searchlist`, url: `/pages/searchlist/searchlist?id=${event.detail.item.id}&name=${event.detail.item.title}`, }) }else{ wx.navigateTo({ url: `/pages/detail/detail?id=${event.detail.item.id}&name=${event.detail.item.name}`, }) } } })
{ "usingComponents": { "mp-searchbar": "weui-miniprogram/searchbar/searchbar" }, "navigationBarTitleText": "搜索" }
searchlist
<!--pages/searchlist/searchlist.wxml--> <view class="sortlist"> <view>价格排序 <mp-icon type="field" icon="refresh" color="black" size="{{25}}" bindtap="handlePrice"></mp-icon> </view> <view>好评排序 <mp-icon type="field" icon="refresh" color="black" size="{{25}}" bindtap="handleComment"></mp-icon> </view> </view> <view class="goodcontainer"> <view wx:for="{{goodList}}" wx:key="index" class="good" data-id="{{item.id}}" data-name="{{item.title}}" bindtap="handleTap"> <image src="http://localhost:5000{{item.poster}}" mode="widthFix"/> <view>{{item.title}}</view> <view style="color:red;">价格:¥{{item.price}}</view> <view>好评率:{{item.goodcomment}}</view> </view> </view>
/* pages/searchlist/searchlist.wxss */ .goodcontainer { display: flex; flex-wrap: wrap; } .good{ width: 50%; padding:20rpx; box-sizing: border-box; text-align: center; } .good image{ width: 100%; } .sortlist{ display: flex; } .sortlist view{ flex:1; text-align: center; height: 100rpx; line-height: 100rpx; }
// pages/searchlist/searchlist.js import request from '../../utils/request' Page({ /** * 页面的初始数据 */ data: { goodList:[] }, priceOrder:true, commentOrder:true, /** * 生命周期函数--监听页面加载 */ onLoad(options) { // console.log(options) wx.setNavigationBarTitle({ title: options.name, }) this.getList(options.id) }, getList(id){ request({ url:`/categories/${id}?_embed=goods` }).then(res=>{ // console.log(res.goods) this.setData({ goodList:res.goods }) }) }, handleTap(event){ // console.log(event.currentTarget.dataset) var id = event.currentTarget.dataset.id var name = event.currentTarget.dataset.name wx.navigateTo({ url: `/pages/detail/detail?id=${id}&name=${name}`, }) }, handlePrice(){ this.priceOrder =!this.priceOrder this.setData({ goodList:this.priceOrder?this.data.goodList.sort((item1,item2)=>item1.price-item2.price):this.data.goodList.sort((item1,item2)=>item2.price-item1.price) }) }, handleComment(){ this.commentOrder =!this.commentOrder this.setData({ goodList:this.commentOrder?this.data.goodList.sort((item1,item2)=>parseInt(item1.goodcomment)-parseInt(item2.goodcomment)):this.data.goodList.sort((item1,item2)=>parseInt(item2.goodcomment)-parseInt(item1.goodcomment)) }) } })
{ "usingComponents": { "mp-icon": "weui-miniprogram/icon/icon" } }
shopcar
<mp-cells title="配送地址" footer="左滑删除" wx:if="{{cartList.length}}"> <mp-slideview buttons="{{slideButtons}}" bindbuttontap="slideButtonTap" wx:for="{{cartList}}" wx:key="index" data-id="{{item.id}}"> <mp-cell > <view slot="footer" class="cellfooter"> <text bindtap="handleMinus" data-item="{{item}}">-</text> <text>{{item.number}}</text> <text bindtap="handleAdd" data-item="{{item}}">+</text> </view> <view class="content"> <checkbox checked="{{item.checked}}" bindtap="handleTap" data-item="{{item}}"></checkbox> <image src="http://localhost:5000{{item.good.poster}}" mode="aspectFit"></image> <view style="font-size:13px;"> <view>{{item.good.title}}</view> <view style="color:red;">¥{{item.good.price}}</view> </view> </view> </mp-cell> </mp-slideview> </mp-cells> <view wx:else style="text-align:center;">购物车为空</view> <wxs src="./shopcar.wxs" module="calObj"></wxs> <view class="footer"> <checkbox-group bindchange="handleAllChecked"> <checkbox value="aaaa" checked="{{calObj.check(cartList)}}"></checkbox> </checkbox-group> <view style="margin-right:20px;">全选</view> <view>合计:¥{{calObj.sum(cartList)}}</view> <button type="primary" size="mini">结算</button> </view>
/* pages/shopcar/shopcar.wxss */ .cellfooter text{ width: 60rpx; display: inline-block; background-color: gainsboro; text-align: center; } .content{ display: flex; } .content image{ width: 150rpx; height: 150rpx; } .footer{ position: fixed; left:0px; bottom: 0px; width: 100%; height: 80rpx; line-height: 80rpx; text-align: center; background-color: white; display: flex; }
function sum(list){ var total = 0 for(var i=0;i<list.length;i++){ if(list[i].checked){ total+= list[i].good.price*list[i].number } } return total } function check(list){ if(list.length===0) return false return list.every(function(item){ return item.checked===true }) } module.exports ={ sum:sum, check:check }
// pages/shopcar/shopcar.js import CheckAuth from "../../utils/auth" import request from "../../utils/request" Page({ /** * 页面的初始数据 */ data: { slideButtons: [{ type: 'warn', text: '删除' }], cartList: [] }, /** * 生命周期函数--监听页面加载 */ onLoad(options) { CheckAuth(()=>{ let nickName = wx.getStorageSync('token').nickName let tel = wx.getStorageSync('tel') request({ url:`/carts?_expand=good&username=${nickName}&tel=${tel}` }).then(res=>{ // console.log(res) //[{...}] this.setData({ cartList:res }) }) }) }, /** * 生命周期函数--监听页面显示 */ onShow() { CheckAuth(()=>{ console.log("显示购物车") }) }, handleTap(event){ // console.log(event) var item = event.currentTarget.dataset.item item.checked = !item.checked this.handleUpdate(item) }, // - handleMinus(event){ var item = event.currentTarget.dataset.item if(item.number===1){ return } item.number-- this.handleUpdate(item) }, // + handleAdd(event){ var item = event.currentTarget.dataset.item item.number++ this.handleUpdate(item) }, // 更新 handleUpdate(item){ //更新当前的cartList this.setData({ cartList:this.data.cartList.map(data=>{ if(data.id===item.id){ return item } return data }) }) //更新数据库 request({ url: `/carts/${item.id}`, method: "put", data: { "username": item.username, "tel": item.tel, "goodId": item.goodId, "number": item.number, "checked": item.checked, } }) }, // 删除 slideButtonTap(event){ // console.log("delete",event.currentTarget.dataset.id) var id = event.currentTarget.dataset.id this.setData({ cartList:this.data.cartList.filter(item=>item.id!==id) }) request({ url:`/carts/${id}`, method:"delete" }) }, //全选 handleAllChecked(event){ //数据库操作搁置 // console.log(event.detail.value) if(event.detail.value.length===0){ // 未全选 this.setData({ cartList:this.data.cartList.map(item=>({ ...item, checked:false })) }) }else{ // 全选 this.setData({ cartList:this.data.cartList.map(item=>({ ...item, checked:true })) }) } } })
{ "usingComponents": { "mp-cells": "weui-miniprogram/cells/cells", "mp-cell": "weui-miniprogram/cell/cell", "mp-slideview":"weui-miniprogram/slideview/slideview" }, "navigationBarTitleText": "购物车" }
telform
<!--pages/telform/telform.wxml--> <mp-form-page title="bijian" subtitle="您的手机号将会与微信绑定"> <mp-cells title="信息" > <mp-cell prop="mobile" title="手机号" ext-class=" weui-cell_vcode"> <input bindinput="formInputChange" data-field="mobile" class="weui-input" placeholder="请输入手机号" /> <view slot="footer" class="weui-vcode-btn">获取验证码</view> </mp-cell> </mp-cells> <view slot="button"> <button class="weui-btn" type="primary" bindtap="submitForm">确定</button> </view> </mp-form-page>
// pages/telform/telform.js import request from '../../utils/request' Page({ /** * 页面的初始数据 */ data: { tel:"" }, formInputChange(event){ // console.log(event.detail.value) this.setData({ tel:event.detail.value }) }, submitForm(){ wx.setStorageSync('tel', this.data.tel) request({ url:`/users?tel=${this.data.tel}&nickName=${wx.getStorageSync('token').nickName}` }).then(res=>{ // console.log(res) if(res.length===0){ request({ url:`/users`, method:"post", data:{ ...wx.getStorageSync('token'), tel:this.data.tel } }).then(res=>{ wx.navigateBack({ delta:2 }) }) }else{ wx.navigateBack({ delta:2 }) } }) } })
{ "usingComponents": { "mp-form-page": "weui-miniprogram/form-page/form-page", "mp-form": "weui-miniprogram/form/form", "mp-cells": "weui-miniprogram/cells/cells", "mp-cell": "weui-miniprogram/cell/cell" }, "navigationBarTitleText": "手机号绑定" }