running小程序重要技术流程文档
一、项目文件说明:
(注:getMyMoney无用已删除)
二、重要文件介绍
1.reinfo.js:位于utils文件下,该文件封装有统一的请求URL,和请求API同意封装供页面调用;调用时候需要在页面上先引入该文件,如下(index/index.js为例):
//先引入
import API from "../../utils/reinfo.js";
// 后使用的时候如下
wx.request({
url: API.getSysConfig,//这里的API就是上面引入时候的名字,getSysConfig就是我们reinfo.js文件里封装的
method:"get",
success: function (res) {
// 调用接口成功后执行的
}
})
2.app.js:这个是小程序的启动文件,每次小程序启动的话,必定会执行这个文件里的方法。
//onLaunch 小程序生命周期,启动就会执行
onLaunch: function () {
var that=this;
// 展示本地存储能力
var openId = wx.getStorageSync('openId') || null
// 获取用户openid、使用 Promise
// 这里的获取用户openid使用Promise 因为需要让index.js可以调用他来获取openid,因为index作为第一个小程序页面,也具有优先执行权,有时候会在app.js执行之前先执行,有时候会在app.js执行之后执行,所以这里使用Promise做一个异步请求,来供index.js页面调用回调获取用户数据
const getUserOpenId = new Promise((resolve, reject) => {
if(openId){
console.log('缓存openid',openId)
resolve(openId); // resolve Promise
}else{
// 登录code获取openid
wx.login({
success: function (res) {
var code = res.code;//发送给服务器的code
if (code) {
wx.request({
url: API.getSessinOpenid,
method:"post",
data: {
code: code,
},
header: {
'content-tpe': 'application/json'
},
success: function (res) {
console.log('获取到的用户openid为:',res)
//可以把openid保存到本地缓存,方便以后调用
wx.setStorageSync('openId', res.data.data);
// that.getUserInfoFun(res.data.data)
resolve(res.data.data); // resolve Promise
},
fail:function(res){
reject(err); // reject Promise
console.log(res)
}
})
}
else {
console.log("获取用户登录态失败!");
}
},
fail: function (error) {
}
})
}
});
// 将 Promise 对象存储到全局数据对象中
this.globalData.getUserOpenId = getUserOpenId;
// 获取用户信息
//这个获取用户信息同上意思
const getUserInfo = new Promise((resolve, reject) => {
wx.request({
url: API.getUserInfo,
method:"post",
data: {
openId: wx.getStorageSync('openId') || null,
},
success: function (res) {
console.log('openid获取用户信息:',res)
wx.setStorageSync('userInfo', res.data.data);
resolve(res.data.data); // resolve Promise
}
})
})
// 将 Promise 对象存储到全局数据对象中
this.globalData.getUserInfo = getUserInfo;
},
这个页面底部有个changeTabBar方法这个是自定义底部导航组件用来切换页面的公共方法
小程序组件的使用方法如下:
1.封装组件如comment\tabbar\tabbar.wxml这里就是封装了一个底部导航组件:
其他需要使用的页面进行引入(index/index):
wxml:
<import src="../../comment/tabbar/tabbar.wxml" />
<template is="tabbar" data="{{tabbar}}"/>
js:
//获取应用实例
const app = getApp();
Page({
/**
* 页面的初始数据
*/
data: {
//底部导航栏
tabbar: {},
},
//在onshow或者onload调用app下的changeTabBar方法来进行点击切换页面
onload(){
//调用app中的函数
app.changeTabBar();
}
})
3.postOrder:发布订单是一个大麻烦:这里需要使用一个点击切换和滑动切换(同用户订单列表页和跑腿订单列表页)。
wxml:
<view class="navbar">
<text wx:for="{{navbar}}" data-idx="{{index}}" class="item {{currentTab==index ? 'active' : ''}}" wx:key="unique" bindtap="navbarTap">{{item}}</text>
</view>
js:
/**
* 页面的初始数据
*/
data: {
navbar: ['帮我买', '帮我送', '帮我取'],
currentTab: 0,
}
//电机头部切换bar
navbarTap: function (e) {
console.log( e.currentTarget.dataset.idx)
let initPrice = app.globalData.sysConfig.minDeliveryPrice
// 切换的时候需要将数据清空,让用户重新输入
let postData = {
"commodity": "",
"commodityCost": 0,
"commodityWeight": 1,
"deliveryAddress": "",
"deliveryConcat": "",
"deliveryPhone": "",
"deliveryTime": "",
"openId": "",
"orderType": e.currentTarget.dataset.idx*1,
"pickUpAddress": "",
"pickUpContact": "",
"pickUpPhone": "",
"pickUpTime": "",
"remark": "",
"tipCost": 0,
"totalCost": 0
}
// 设置取货时间、配送时间
postData.deliveryTime = this.calculateFutureTime()
if(postData.orderType == 1||postData.orderType == 2){
postData.pickUpTime = this.calculateFutureTime()
}
var userInfo = wx.getStorageSync('userInfo') || {}
postData.deliveryPhone = userInfo.phone
// postData.orderType = e.currentTarget.dataset.idx
this.setData({
currentTab: e.currentTarget.dataset.idx,
postData,
multiIndex1: [0, 0], // 默认选择当天和第一个时间段
multiIndex2: [0, 0], // 默认选择当天和第一个时间段
multiIndex3: [0, 0], // 默认选择当天和第一个时间段
multiIndex4: [0, 0], // 默认选择当天和第一个时间段
price: initPrice
})
//全局变量
app.globalData.currentTab = e.currentTarget.dataset.idx;
},
// 轮播切换,即左右滑动切换
swiperChange: function (e) {
let initPrice = app.globalData.sysConfig.minDeliveryPrice
// 切换类型的话清空
let postData = {
"commodity": "",
"commodityCost": 0,
"commodityWeight": 1,
"deliveryAddress": "",
"deliveryConcat": "",
"deliveryPhone": "",
"deliveryTime": "",
"openId": "",
"orderType": e.detail.current*1,
"pickUpAddress": "",
"pickUpContact": "",
"pickUpPhone": "",
"pickUpTime": "",
"remark": "",
"tipCost": 0,
"totalCost": 0
}
// 设置取货时间、配送时间
postData.deliveryTime = this.calculateFutureTime()
if(postData.orderType == 1||postData.orderType == 2){
postData.pickUpTime = this.calculateFutureTime()
}
var userInfo = wx.getStorageSync('userInfo') || {}
postData.deliveryPhone = userInfo.phone
this.setData({
currentTab: e.detail.current,
postData,
multiIndex1: [0, 0], // 默认选择当天和第一个时间段
multiIndex2: [0, 0], // 默认选择当天和第一个时间段
multiIndex3: [0, 0], // 默认选择当天和第一个时间段
multiIndex4: [0, 0], // 默认选择当天和第一个时间段
price: initPrice
})
//全局变量
app.globalData.postOrderCurrentTab = e.detail.current;
},
来实现顶部以及点击切换:
配送时间的选择,进行一个立即配送和之后的每隔30分钟可供选择,有当天和次日,
wxml:
<view class="v1-item">
<view>预计送达时间</view>
<picker mode="multiSelector" bindcolumnchange="bindMultiPickerColumnChange" range="{{[dateRange, timeRange]}}" value="{{multiIndex1}}" data-id="1" bindchange="bindMultiPickerChange">
<view class="picker">
{{dateRange[multiIndex1[0]]}} {{timeRange[multiIndex1[1]]}}
</view>
</picker>
</view>
js:
data:{
dateRange: ['今天', '明天'],
timeRange: [], // 存储时间段的数组
multiIndex1: [0, 0], // 默认选择当天和第一个时间段 帮我买:预计送达时间
multiIndex2: [0, 0], // 默认选择当天和第一个时间段 帮我送:预计取货时间
multiIndex3: [0, 0], // 默认选择当天和第一个时间段 帮我送:预计送达时间
multiIndex4: [0, 0], // 默认选择当天和第一个时间段 帮我取:预计送达时间
}
// 配送时间选择列表发生改变时候监听
bindMultiPickerColumnChange(e){
console.log('修改的列为', e.detail.column, ',值为', e.detail.value,e);
if(e.detail.column == 0 && e.detail.value == 1){
var startOfDay = new Date();
startOfDay.setHours(0, 0, 0, 0);
dayType = 1
this.generateTimeRange(startOfDay)
}
else if(e.detail.column == 0 && e.detail.value == 0){
dayType = 0
this.generateTimeRange(new Date())
}
},
// 计算时间选择列表
generateTimeRange: function(now) {
// var now = new Date();
var hours = now.getHours();
var minutes = now.getMinutes();
var timeRange = [];
// 生成时间段,每半个小时为一个时间段,共24小时
for (var i = 0; i < 48; i++) {
var hour = Math.floor(i / 2);
var minute = (i % 2) * 30;
// 格式化时间,补零操作
var hourStr = hour < 10 ? '0' + hour : '' + hour;
var minuteStr = minute === 0 ? '00' : '' + minute;
if (hour > hours || (hour == hours && minute >= minutes)) {
timeRange.push(hourStr + ':' + minuteStr);
}
}
if(dayType == 0){
timeRange[0] = '立即配送'
}
this.setData({
timeRange: timeRange
});
},
// 根据当前时间自动计算30分钟后的时间,并在遇到23:40时能正确计算到次日
calculateFutureTime() {
var currentDate = new Date();
var futureDate = new Date(currentDate.getTime() + 30 * 60000); // 加上30分钟的毫秒数
// 如果超过了当天的23:59:59,就设置到次日的00:30
if (futureDate.getDate() > currentDate.getDate()) {
futureDate = new Date(futureDate.getFullYear(), futureDate.getMonth(), futureDate.getDate(), 0, 30, 0);
var originalDate = new Date(futureDate);
var hour = originalDate.getHours()<10?'0'+originalDate.getHours():originalDate.getHours();
// var minute = originalDate.getMinutes();
var minute = originalDate.getMinutes()<10?'0'+originalDate.getMinutes():originalDate.getMinutes();
var formattedTime = hour + ':' + minute;
// var formattedTime = hour<10?0+hour:hour + ':' + minute;
console.log("当前时间0000:" , currentDate);
console.log("30分钟后的时间000:" , futureDate,formattedTime);
return '次日 '+formattedTime;
}
var originalDate = new Date(futureDate);
var hour = originalDate.getHours()<10?'0'+originalDate.getHours():originalDate.getHours();
var minute = originalDate.getMinutes()<10?'0'+originalDate.getMinutes():originalDate.getMinutes();
// var minute = originalDate.getMinutes();
var formattedTime = hour + ':' + minute;
// var formattedTime = hour<10?0+hour:hour + ':' + minute;
console.log("当前时间111:" , currentDate);
console.log("30分钟后的时间1111:" , futureDate,formattedTime);
return '今天 '+formattedTime;
},
// 选择
bindMultiPickerChange: function(e) {
console.log('选择',e)
let postData = this.data.postData
let type = e.currentTarget.dataset.id
console.log('这样可以吗?',this.data['multiIndex'+type])
// 如果是立即配送自动匹配现在的30分钟后
if(this.data.timeRange[e.detail.value[1]] == '立即配送'){
postData.deliveryTime = this.calculateFutureTime()
}
if(type == 1){
postData.deliveryTime = this.data.dateRange[this.data['multiIndex'+type][0]] +' '+ this.data.timeRange[this.data['multiIndex'+type][1]]
}
if(type == 2){
postData.pickUpTime = this.data.dateRange[this.data['multiIndex'+type][0]] +' '+ this.data.timeRange[this.data['multiIndex'+type][1]]
}
if(type == 3){
postData.deliveryTime = this.data.dateRange[this.data['multiIndex'+type][0]] +' '+ this.data.timeRange[this.data['multiIndex'+type][1]]
}
if(type == 4){
postData.deliveryTime = this.data.dateRange[this.data['multiIndex'+type][0]] +' '+ this.data.timeRange[this.data['multiIndex'+type][1]]
}
this.setData({
['multiIndex'+type]: e.detail.value,
postData,
});
console.log('结果》》》?',this.data['multiIndex'+type])
},
图片上传列表
wxml:
<view class="v1">
<!-- 图片列表 -->
<view class="image-list">
<block wx:for="{{images}}" wx:key="index">
<view class="image-item">
<image src="{{item}}" mode="aspectFill" data-src="{{item}}" bindtap="previewImage"></image>
<view class="delete-btn" bindtap="deleteImage" data-index="{{index}}">×</view>
</view>
</block>
<!-- 添加图片按钮 -->
<view class="add-image" bindtap="chooseImage">
<text>+</text>
</view>
</view>
</view>
js:
data:{
images: [], // 存储已选择的图片列表
}
// 选择图片
chooseImage() {
let that = this;
wx.chooseImage({
count: 1,
sizeType: ['original', 'compressed'],
sourceType: ['album', 'camera'],
success: (res) => {
console.log('选择图片',res)
wx.uploadFile({
url: API.uploadImg,
filePath: res.tempFilePaths[0],
name: 'file',
header: {
"Content-Type": "multipart/form-data"
},
formData: {
'type': 4 //1-表示头像,2-表示身份证,4-订单图片
},
success (resFile){
let fileData = JSON.parse(resFile.data)
console.log("文件上传接口",JSON.parse(resFile.data))
if(fileData.code == 0){
// 上传成功时候插入原有的数据中
const newImages = that.data.images.concat(fileData.data);
that.setData({
images: newImages,
});
}else{
wx.showToast({
title: fileData.msg,
icon: 'error'
})
}
}
})
},
});
},
// 预览图片
previewImage(e) {
const current = e.target.dataset.src;
wx.previewImage({
current: current,
urls: this.data.images,
});
},
// 删除图片
deleteImage(e) {
const index = e.target.dataset.index;
const newImages = this.data.images;
// 删除指定位置index的图片
newImages.splice(index, 1);
this.setData({
images: newImages,
});
},
4.index:抢单大厅样式
//<!-- class使用三元运算符,动态设置class名称,用遍历数据,判断奇偶数来实现左右不同样式 -->
<view class="{{index%2 == 0?'v2-body-v1':'v2-body-v2'}}" wx:for="{{orderHallList}}" bindtap="gotoOrderDetail" data-paymentStatus="{{item.paymentStatus}}" data-orderStatus="{{item.orderStatus}}" data-id="{{item.id}}" data-type="orderHall">
<view class="{{index%2 == 0?'v2-body-v1-price':'v2-body-v2-price'}}">¥{{item.totalCost}}</view>
<view class="{{index%2 == 0?'v2-body-v1-text':'v2-body-v2-text'}}">
<image src="{{index%2 == 0?'/images/zuo.png':'/images/you.png'}}"></image>
<text>{{item.orderType == 'BUY'?'帮我买':item.orderType == 'SEND'?'帮我送':item.orderType == 'TAKE'?'帮我取':''}}</text>
</view>
<view class="{{index%2 == 0?'v2-body-v1-img':'v2-body-v2-img'}}">
<view>{{item.deliveryAddress}}</view>
<view>{{item.deliveryTime}}</view>
</view>
</view>
5.订单完成的评价打分:
wxml:
<view class="v1-item">
// <!-- 星星打分实现 -->
<view style="width: 100%;line-height: 60rpx;">
<view style="width: unset;margin-left: unset;" class='starLen' bindtap="myStarChoose">
<block wx:for="{{starMap}}">
<image wx:if="{{star>=index+1}}" class='star' data-star="{{index+1}}" src="../../images/start-2.png" />
<image wx:if="{{star<index+1}}" class='star' data-star="{{index+1}}" src="../../images/start-1.png" />
</block>
</view>
<view class="scoreContent" style="width: unset;margin-left: unset;">{{starMap[star-1]}}</view>
</view>
</view>
js:
/**
* 页面的初始数据
*/
data: {
star: 0, //默认0分
starMap: [
'非常差',
'差',
'一般',
'好',
'非常好',
],
},
// 选星
myStarChoose(e) {
let star = parseInt(e.target.dataset.star) || 0;
// 获取打的分
this.setData({
star: star,
});
},
这里列举这几个比较难的流程,如果后面对哪些模块的流程有不明白的可以再提出来