开发小程序中,遇到的wepy的几点坑,记录一下;

更详细的项目总结记录请见我的个人博客:https://fanghongliang.github.io/

1.定时器:

  在页面中有需要用到倒计时或者其他定时器任务时,新建的定时器在卸载页面时一定要清除掉,有时候页面可能不止一个定时器需求,在卸载页面(onUnload钩子函数)的时候一定要清除掉当前不用的定时器

  定时器用来做倒计时效果也不错,初始时间后台获取,前端处理,后台直接在数据库查询拿到的标准时间(数据库原始时间,T分割),前端需要正则处理一下这个时间:

let overTimeStr = data.over_time.split('T')
let time1 = overTimeStr[0].replace(/-/g,",")
let time2 = overTimeStr[1].replace(/:/g,',')
let overTime = time1+ ',' + time2
let overTimeArr = overTime.split(',')
that.countDownCtrl( overTimeArr, 0 );

最终把时间分割为[年,月, 日, 时, 分, 秒]的数组,(如果后端已经把时间处理过了那就更好了),然后把该数组传递给倒计时函数:

   countDownCtrl( time, group ) {
let deadline = new Date()//免费截止时间,月的下从0开始
deadline.setFullYear(time[0], time[1]-1, time[2])
deadline.setHours(time[3], time[4], time[5])
let curTimeJudge = new Date().getTime()
let timeJudge = deadline.getTime()-curTimeJudge
let remainTimeJudge = parseInt(timeJudge/1000)
if( remainTimeJudge < 0) {
log('倒计时已经过期')
return;
}
this.interva1 = setInterval(() => {
let curTime = new Date().getTime() let time = deadline.getTime()-curTime //剩余毫秒数
let remainTime = parseInt(time/1000) //总的剩余时间,以秒计 let day = parseInt( remainTime/(24*3600) )//剩余天
let hour = parseInt( (remainTime-day*24*3600)/3600 )//剩余小时
let minute = parseInt((remainTime-day*24*3600-hour*3600)/60)//剩余分钟
let sec = parseInt(remainTime%60)//剩余秒
hour = hour < 10 ? '0' + hour : hour;
minute = minute < 10 ? '0' + minute : minute
sec = sec < 10 ? '0' + sec : sec
let countDownText = hour+ ":" +minute+ ":" +sec
if( group === 0) { //个人业务逻辑,因为一个页面有两个倒计时需求,代码复用区分
this.countDown = countDownText;
} else if( group === 1 ) {
this.countDownGroup = countDownText
}
this.$apply()
}, 1000 );
}

至此,倒计时效果处理完毕,PS:终止时间一定要大于currentDate,否则显示会出现异常(包括但不限于倒计时闪烁、乱码等)

最后,退出该页面去其他页面时,一定要在页码卸载钩子中清除倒计时!!!

onUnload() {
clearInterval(this.interva1);
}

2.三层组件,阻止点击事件传播:

   三层组件嵌套,第三层的点击事件不能传到第一层去,适用于遮罩层+picker,阻止事件点击向上传播,因为每一层都添加有点击事件,互不干扰、

   解决: 添加函数 catchtap="funcName" 即可,funcName可为空函数,也可以直接不写

3.组件传值:

  组件传值和Vue有点细微区别,Vue强调父组件的数组和对象不要直接传到子组件使用,应为子组件可能会修改这个data,如图:

  但是,wepy中,有时候确实需要把一个对象传递到子组件使用,单个传递对象属性过于繁琐,而且!!!如果单个传递对象的属性到子组件,如果该属性是一个数组,则子组件永远会接收到 undefined 。此时最好用整个对象传值替代单个对象属性逐个传值的方法,

且一定要在传值时加入  .sync 修饰符,双向传值绑定。确保从接口拿到的数据也能传递到子组件,而非 undefined

  

:circleMembersList.sync="circleMembersList"

4.token判断

  在与后台交互的时候,token必不可少。尤其是在小程序分享出去的链接,由其他用户点开分享链接进入小程序内部,此时更是要判断token,token的判断一般选在 onShow()钩子执行而不在 onLoad()钩子内执行。若不存在token,则应该执行登录去拿取token

5.formID

  微信提供了服务通知,即在你支付、快递等行为时,微信会直接给你发一个服务通知来提醒,每次提醒都会消耗该用户存储的formID,formID为消耗品,用一个少一个,只有通过用户的表单提交行为才可以拿到formID,

<form @submit="submitForm" report-submit="true">
<button form-type="submit" class="editCard" @tap = "goModifiPage('editFormTab')">修改</button>
</form>
submitForm(e) {
this.postFormId( e.detail.formId )
}

6.微信支付

  准备: crypto-js.js   md5.js

  微信支付流程为: 前端点击支付按钮  ==》 准备加密数据  ==》 调用后端接口,传入需要的加密数据  ==》 后端验证加密数据,再返回加密数据  ==》 前端拿到后端加密数据(时间戳、内容、签名),对时间戳和内容进行本地签名,再判断本地签名和后端签名是否

一致,若不一致,直接返回,退出支付,支付失败!若一致,对刚刚后台返回的content(内容)进行解析,拿到所需订单数据,前端调起微信支付借口,参数传入刚刚解析数据  ===》 得到支付结果 success  or fail !结束

  Sign函数:

/**
* 签名
*/
function sign(timestamp, content) {
var raw = timestamp + salt + content
var hash = CryptoJS.SHA256(raw).toString()
return CryptoJS.MD5(hash).toString()
}

  前端点击支付按钮:

// 单独支付接口
alonePay(arg) {
const that = this;
if( that.buttonClicked === false ) return;
that.buttonClicked = false;
let mode = 1;
let appId = this.$parent.globalData.appId;
let content;
let sign;
const timeStamp = new Date().Format("yyyy-MM-dd hh:mm:ss").toString();
let code = wepy.getStorageSync('code');
wepy.login().then((res) => {
if(res.code) {
let code = res.code;
log('code', code)
wepy.setStorage({
key: "code",
data: code
})
}
}).then( res => {
content = `mode=${mode}&app_id=${appId}`
sign = Sign.sign(timeStamp,content);
}).then(res => {
that.goCirclePay( that.circle_id, timeStamp, sign, content, mode )
})
},

  支付函数:

    // 支付
goCirclePay( circle_id, timestamp, sign, content, mode) {
const that = this;
circleApi.goCirclePay({
data: {
circle_id,
timestamp,
sign,
content
},
getToken: true
}).then( res => {
log('支付res:', res) let data = res.data
const SignServer = data.sign
const timeStampServer = data.timestamp
let contentServer = data.content
const SignLocal = Sign.sign(timeStampServer,contentServer); if( mode === 0 && data.status === "success") {
that.nav('/pages/circleDetail?circle_id=' + that.circle_id)
return;
} if( SignLocal !== SignServer ) {
log('签名不一致!')
wx.showToast({
title: "您已经支付过了",
duration: 1500,
image: "../images/common/icon_wxchat.png",
})
return
}
let contentArr = contentServer.split('&')
const timeStamp = contentArr[0].split('=')[1];
const nonceStr = contentArr[1].split('=')[1];
let index = contentArr[2].indexOf("=");
const package1 = contentArr[2].slice(index+1)
const signType = contentArr[3].split('=')[1];
const paySign = contentArr[4].split('=')[1];
wepy.requestPayment({
timeStamp,
nonceStr,
package: package1,
signType,
paySign
}).then(res => {
return new Promise(resolve => {
setTimeout(() => {
resolve()
}, 1000)
})
}).then(res => {
that.buttonClicked = true;
let groupFormIdGet;
circleApi.getGroupFormId({ ////获取getGroupFormId
data: {
circle_id: that.circle_id
},
getToken: true
}).then( res => {
let data = res.data
that.group_form_id = data.group_form_id
groupFormIdGet = data.group_form_id if( mode === 1) {
that.nav(`/pages/paySuccess?circle_id=${that.circle_id}&shareLink=${that.shareLink}`)
} else if( mode === 2) {
that.nav(`/pages/paySuccess?circle_id=${that.circle_id}&group_form_id=${groupFormIdGet}`)
}
that.$apply()
})
}).catch(res => {
log('支付失败', res)
that.buttonClicked = true;
})
})
}

  至此,支付就已经完成!

  7.图片上传(采用七牛云)

  图片上传服务器采用七牛云服务,在APP内小程序触发的时候,请求七牛云拿到token存为全局变量。

  图片需要上传的地方,直接放代码:

  页面结构:

<!-- 上传生活照 -->
<view class="baseInfoTip" style="border: 0">上传生活照
<view class="imgUploadText">(最多9张)</view>
<view class="leftOriginLine"></view>
</view>
<view class="uploadImgBox">
<repeat for="{{images}}" index="index" item="item" key="index">
<view class="itemBox">
<image class="imgItem" src="{{item}}" mode="aspectFill"></image>
<image class="imgItemCancel" id="{{index}}" src="../images/common/icon_cardImg_cancel.png" @tap.stop="cancelUploadImg"></image>
</view>
</repeat>
<view class="itemBox" @tap="addImg" wx:if="{{!addImgCtrl}}">
<image class="imgItem" src="../images/common/icon_addImg.png"></image>
</view>
</view>

  base.oploadImg()函数:

// 上传图片
const uploadImg = (imageURL, uptokenURL) => {
return new Promise((resolve, reject) => {
qiniuyun.upload(imageURL, (res) => {
resolve(res);
}, (error) => {
reject(error);
}, {
region: 'ECN',
domain: '填入域名',
uptoken: uptokenURL
});
});
}

 

  上传图片函数:

 // 从相册选择照片上传
addImg(){
const that = this;
if( that.buttonClicked === false ) return;
that.buttonClicked = false;
wepy.chooseImage({
count:9 - that.images.length,
sizeType: 'compressed',
}).then(async(res1) => {
that.buttonClicked = true;
that.toast('上传图片中...','loading');
let filePath = res1.tempFilePaths;
for(let i = 0;i < filePath.length;i++){
let imgSrc= res1.tempFilePaths[i];
let imgType = imgSrc.substring(imgSrc.length-3);
let imgSize = res1.tempFiles[i].size;
if(imgSize > 2000000 || imgType === 'gif'){
that.toast('该图片格式错误!请重新选择一张', 'none', 3000);
continue
}
let res = await base.uploadImg(filePath[i], that.$parent.globalData.qiniuToken);
that.images.push(res.imageURL);
log('image长度:', that.images.length)
log('image:', that.images)
if( that.images.length >= 9) {
that.addImgCtrl = true
}
if(that.images.length > 9){
that.images = that.images.slice(0,9)
}
if(that.images.length >0 && that.config.fImages){
that.config.progress = that.config.progress + parseFloat(that.config.getConfigs.lifepicweight*100);
that.config.fImages = false
}
that.$apply();
// 上传用户头像列表
that.userInfo.photos = that.images
if(i === filePath.length -1){
wepy.hideToast();
}
}
}).catch((res) => {
if(res.errMsg === "chooseImage:fail:system permission denied"){
that.toast('请打开微信调用摄像头的权限', 'none', 3500)
}
})
},
// 取消图片上传
cancelUploadImg(e) {
if( this.images.length < 10 ) {
this.addImgCtrl = false
}
let index = e.target.id
this.images.splice(index, 1)
},

至此,图片上传解决

  

wepy-开发总结(功能点)的更多相关文章

  1. python_way day18 html-day4, Django路由,(正则匹配页码,包含自开发分页功能), 模板, Model(jDango-ORM) : SQLite,数据库时间字段插入的方法

    python_way day18 html-day4 1.Django-路由系统   - 自开发分页功能 2.模板语言:之母板的使用 3.SQLite:model(jDango-ORM) 数据库时间字 ...

  2. iOS项目开发常用功能静态库

    YHDeveloperTools iOS项目开发常用功能静态库 查看源码 功能方法: 1.字符检查 [NSString checkStringWithType:Email andTargetStrin ...

  3. 微信小程序wepy开发循环wx:for需要注意

    微信小程序wepy开发循环wx:for需要注意 item index值必须在wx:for之后使用 <view wx:for="{{tablist}}" class=" ...

  4. wepy开发小程序eslint报错error 'getApp' is not defined no-undef

    wepy开发小程序使用getApp().globalData保存全局数据很方便,但是会在控制台看到很多报错:“error 'getApp' is not defined no-undef”,这是esl ...

  5. Django框架之cookie和session及开发登录功能

    1.cookie是什么? Web应用程序是使用HTTP协议传输数据的.HTTP协议是无状态的协议.一旦数据交换完毕,客户端与服务器端的连接就会关闭,再次交换数据需要建立新的连接.这就意味着服务器无法从 ...

  6. NFC模组,开发NFC功能 仅仅要几条指令的事情

    特点:实现NFC透明传输.内置NFC协议栈,支持UART串口直接读写,用于门禁能够同一时候兼容手机和卡片开门,还能实现动态密钥,读到的NFC数据自己主动串口输出,会串口就能开发NFC,不须要研究LLC ...

  7. 阿里云短信服务发送短信验证码(JAVA开发此功能)

    开发此功能需注册阿里云账号,并开通短信服务(免费开通) 充值后,不会影响业务的正常使用!(因为发送验证类短信:1-10万范围的短信是0.045元/条).开发测试使用,充2块钱测试足够了 可参考阿里云官 ...

  8. 使用wepy开发微信小程序商城第三篇:购物车(布局篇)

    使用wepy开发微信小程序商城 第三篇:购物车(布局篇) 前两篇如下: 使用wepy开发微信小程序商城第一篇:项目初始化 使用wepy开发微信小程序商城第二篇:路由配置和页面结构 基于上两篇内容,开始 ...

  9. 使用wepy开发微信小程序商城第二篇:路由配置和页面结构

    使用wepy开发微信小程序商城 第二篇:路由配置和页面结构 前言: 最近公司在做一个微信小程序的项目,用的是类似于vue的wepy框架.我也借此机会学习和实践一下. 小程序官方文档:https://d ...

  10. 使用wepy开发微信小程序商城第一篇:项目初始化

    使用wepy开发微信小程序商城 第一篇:项目初始化 前言: wepy小程序项目初始化的操作,官方文档看了好几遍,感觉写得不是很清楚. 这篇写得挺好的:小程序开发之wepy 1.初始化项目 (1)全局安 ...

随机推荐

  1. IE浏览器中图片路径正确< img ... />标签不显示图片

    如下图所示,下面的html要去加载上面的jpg图片: 代码如下: <img src="luzhanshi1.jpg" alt="图片加载失败"> 使 ...

  2. Quartz安装包中的15个example

    Welcome======= Welcome to the Quartz Examples directory. This directory contains 15 examples that sh ...

  3. Windows操作路由表

    route print route add 172.17.0.0 mask 255.255.0.0 192.168.99.100 route delete 172.17.0.0 mask 255.25 ...

  4. 阶段3 1.Mybatis_06.使用Mybatis完成DAO层的开发_9 typeAliases标签和package标签

    配置别名 上面制定了好了别名后,映射文件就可以简写了.不区分大小写 皆可以小写也可以大写 大小写混着也可以 测试 package 直接把com.itheima.domain下面所有的类都注册了 可以使 ...

  5. HTTP学习记录:二、请求方法

    学习资源主要为:@小坦克HTTP相关博客 最基础的是4种,GET.POST.PUT.DELETE对应着对资源的查.改.增.删.最常用的是GET和POST. GET一般用于获取/查询资源信息: POST ...

  6. Linux监控命令之==>vmstat

    一.使用说明 vmstat 可以对操作系统的内存信息.进程状态.CPU 活动.磁盘等信息进行监控,不足之处是无法对某个进程进行深入分析. 二.用法及参数说明 -a:显示活跃和非活跃内存 -f:显示从系 ...

  7. 中国MOOC_零基础学Java语言_第5周 数组

    第5周 数组 5.1 数组 5.2 数组计算 public class Main { public static void main(String[] args) { for (int i = 1; ...

  8. sql语句经验

    1:拼接字段模糊查询 where  aaa(字段) not like CONCAT(DATE_FORMAT(new(),"%Y-%m-%d"),'%完成%'): 2:备份表中数据导 ...

  9. ionic3构建过程中遇到的找不到AndroidManifest.xml的问题

    问题如下: Failed to install 'ionic-plugin-keyboard': Error: ENOENT: no such file or directory, open '/Us ...

  10. Git 的使用及其一些基本用法

    打开你的git-bash 绑定用户和邮箱作为标识 $ git config --global user.name "your name" $ git config --global ...