本文最后更新于:9 个月前
前言
正文 小程序开发 开发准备 HBuilderX+uni-app+uinCloud
微信开发者工具连接失败
微信开发者工具
最近在开发 PicMemories壁纸分享小程序,浅浅记录遇到的一些问题
请求域名不合法
全局封装request
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 App ({ request (options ) { const { url, method, data, success, fail } = options; wx.request ({ url, method, data, success (res ) { success && success (res.data ); }, fail (error ) { fail && fail (error); } }); }, onLaunch : function ( ) { console .log ("App launched" ); }, onShow : function ( ) { console .log ("App showed" ); }, onHide : function ( ) { console .log ("App hided" ); }, globalData : { userInfo : null , themeColor : '#F44336' , }, });
1 2 3 4 5 6 7 8 9 10 app.request ({ url : 'http://localhost:8084/api/user/current' , method : 'GET' , success : function (data ) { console .log (data); }, fail : function (error ) { console .log (error); } })
1 Invalid character found in method name [0x160x030x010x020x000x010x000x010xfc0x030x031E0xe3 ]0x8eQ0xd60x0e0xf7mJ0x950x920x810xe00x0c0x820xb5 )0xc70xdf0xefY0xe30xb8 |0x9d0xd430xe50x8f5 ]. HTTP method names must be tokens
经排查,是因为把 http 写成 https 了:
数据双向绑定 1 2 3 4 5 <van-cell-group > <van-field required model:value ="{{username}}" label ="昵称" placeholder ="请输入昵称" /> <van-field required model:value ="{{phone}}" label ="密码" placeholder ="请设置密码" /> <van-field required model:value ="{{password}}" label ="手机号" placeholder ="请输入手机号" /> </van-cell-group >
1 2 3 4 5 data : { username : '' , password : '' , phone : '' },
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 goToRegister ( ) { app.request ({ url : 'http://localhost:8084/api/user/register' , method : 'POST' , data : { username : this .data .username , password : this .data .password , phone : this .data .phone }, success : function (data ) { console .log (data); }, fail : function (error ) { console .log (error); } }) },
即可实现简单的双向数据绑定(2023/08/04早)
生命周期函数 1 2 3 4 5 6 onLoad (options ) { },
1 2 3 4 5 6 onShow ( ) { Toast ("分类~" ) },
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 onPullDownRefresh ( ) { },onReachBottom ( ) { },onShareAppMessage ( ) { }
路由跳转
1 wx.switchTab 跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面
1 wx.reLaunch 关闭所有页面,打开到应用内的某个页面
1 wx.redirectTo 关闭当前页面,跳转到应用内的某个页面。但是不允许跳转到 tabbar 页面
1 wx.navigateTo 保留当前页面,跳转到应用内的某个页面。但是不能跳到 tabbar 页面
1 wx.navigateBack 关闭当前页面,返回上一页面或多级页面
我们可以分析出在不同的业务场景下,使用怎样的路由跳转更合适:
wx.switchTab:支持跳转至tabbar页面
跳转至tabbar页,关闭其他所有非 tabBar 页面
wx.redirectTo、wx.navigateTo:支持跳转至非tabbar页面
前者关闭当前页面,后者保留当前页面
wx.navigateBack:与wx.navigateTo配合,返回上一级页面
wx.reLaunch:支持跳转至任何页面
那么从登录页跳转至个人页,就应该用wx.switchTab / wx.reLaunch(2023/08/05早)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 goToLogin ( ) { app.request ({ url : 'http://localhost:8084/api/user/login' , method : 'POST' , data : { username : this .data .username , password : this .data .password , }, success : function (res ) { console .log (res) const data = res.data ; if (data.code == 0 ) { wx.setStorageSync ('sessionID' , res.header ["Set-Cookie" ]); Notify ({ type : 'success' , message : data.description }); wx.reLaunch ({ url : '/pages/user/index' }) } else { Notify ({ type : 'warning' , message : data.description }); } }, fail : function (error ) { console .log (error); } }) },
data已初始化,未触发数据绑定 1 2 3 4 5 Page ({ data : { imgs : [], urlList : [] },
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 onShow ( ) { Toast ("惊喜多多~" ) var _this = this app.request ({ url : 'http://localhost:8084/api/wallpaper/listPage' , method : 'GET' , success : function (res ) { const data = res.data ; _this.setData ({ 'imgs' : data.data .records }); _this.data .imgs .forEach ((item ) => { _this.data .urlList .push (item.wallpaperUrl ); }); }, fail : function (error ) { console .log (error); } }) },
1 2 3 <block class ="image-list" wx:for ="{{urlList}}" wx:key ="index" > <image class ="img" src ="{{item}}" alt ="刚刚" mode ="widthFix" /> </block >
这里的 image 标签,仍旧无法正常绑定到urlList
当show()生命周期函数未执行完毕,即urlList仍为空数组时,data在页面展示时已经初始化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 onShow ( ) { Toast ("惊喜多多~" ) this .getData (); },getData ( ) { var _this = this ; app.request ({ url : 'http://localhost:8084/api/wallpaper/listPage' , method : 'GET' , success : function (res ) { const data = res.data ; _this.setData ({ 'imgs' : data.data .records }); _this.setUrlList (); } }); },setUrlList ( ) { var urlList = []; this .data .imgs .forEach ((item ) => { urlList.push (item.wallpaperUrl ); }); this .setData ({ 'urlList' : urlList }); },
成功解决urlList数据双向绑定问题(2023/08/05早)
无法获取Session
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 goToLogin ( ) { app.request ({ url : 'http://localhost:8084/api/user/login' , method : 'POST' , data : { username : this .data .username , password : this .data .password , }, success : function (res ) { console .log (res) const data = res.data ; if (data.code == 0 ) { wx.setStorageSync ('sessionID' , res.header ["Set-Cookie" ]); Notify ({ type : 'success' , message : data.description }); wx.reLaunch ({ url : '/pages/user/index' }) } else { Notify ({ type : 'warning' , message : data.description }); } }, fail : function (error ) { console .log (error); } }) },
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 app.request ({ url : 'http://localhost:8084/api/user/current' , method : 'GET' , header : { 'Content-Type' : 'application/json' , 'sessionID' : wx.getStorageSync ('sessionID' ) }, success : function (data ) { console .log (data); }, fail : function (error ) { console .log (error); } }) },
小程序登录 - 用户身份标识
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 goToLogin ( ) { var _this = this ; wx.login ({ success (res ) { if (res.code ) { console .log ("code = " + res.code ) wx.request ({ url : 'http://localhost:8084/api/user/login' , method : 'POST' , data : { code : res.code , username : _this.data .username , password : _this.data .password , }, success : function (res ) { console .log (res) const data = res.data ; if (data.code == 0 ) { Notify ({ type : 'success' , message : data.description }); wx.reLaunch ({ url : '/pages/user/index' }) } else { Notify ({ type : 'warning' , message : data.description }); } }, fail : function (error ) { console .log (error); } }) } else { console .log ('登录失败!' + res.errMsg ) } } }) },
1 2 private final String appId = "wxd12f7c79bd639a9b" ; private final String secret = "8a99ccc1802486c1387c1cda45288dd5" ;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public String getCode2Session (String appId, String secret, String code) { String url = String.format("https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code" , appId, secret, code); HttpRequest request = HttpRequest.get(url); log.info("result = " + request.execute()); return "request" ; } String url = "https://api.weixin.qq.com/sns/jscode2session" ; HashMap<String, Object> paramMap = new HashMap <>(); paramMap.put("appid" , appId); paramMap.put("secret" , secret); paramMap.put("js_code" , code); paramMap.put("grant_type" , "authorization_code" ); String result = HttpUtil.get(url, paramMap); log.info("result = " + result); return result;
1 2 Response Body : {"session_key":"oZ0ju27QocpPhHF2Z1MrtQ==" ,"openid" :"otcWC6_yPHlB2Q6e0vIrB_J2iYHs" }
1 { "errcode" : 40029 , "errmsg" : "invalid code, rid: 64cf07f9-36a4c687-09c960f0" }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 onShow () { Toast('个人中心~' ); console .log ("seeesion_key = " + wx.getStorageSync('session_key' )) app.request({ url : 'http://localhost:8084/api/user/current' , method : 'GET' , header : { 'Authorization' : 'Bearer ' + wx.getStorageSync('session_key' ) }, success : function (data ) { console .log (data); }, fail : function (error ) { console .log (error); } }) },
路由跳转、携带参数
1 2 3 4 5 6 7 8 9 10 11 onClickShow (e ) { const imageUrl = e.currentTarget .dataset .url ; const parameter = { url : imageUrl }; const url = '/pages/imageInfo/index?parameter=' + encodeURIComponent (JSON .stringify (parameter)); wx.navigateTo ({ url : url }); },
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 onLoad (options ) { const {url} = JSON .parse (decodeURIComponent (options.parameter )); console .log (url) this .getData (url) },getData (url ){ this .setData ({ 'url' : url }) console .log (this .data .url ) },
要注意这里的 options 拿到的数据是封装好的对象,要使用如上方式接收参数:(2023/08/09晚)
1 const {url} = JSON .parse (decodeURIComponent (options.parameter ));
点击image标签携带URL
要给每个 <image>
标签添加 click 函数,以便点击不同的图片跳转到不同的页面,可以通过以下方法实现:
1 <image class ="img" src ="{{item}}" alt ="刚刚" mode ="widthFix" bindtap ="handleImageTap" data-url ="{{item}}" />
在当前页面的 JS 文件中定义 handleImageTap
方法来处理点击事件
可以使用 wx.navigateTo
方法跳转到不同的页面并传递参数
1 2 3 4 5 6 7 8 9 Page ({ handleImageTap (e ) { const imageUrl = e.currentTarget .dataset .url ; wx.navigateTo ({ url : `/pages/detail?imageUrl=\${imageUrl}` , }); }, });
在 handleImageTap
方法中,使用 e.currentTarget.dataset.url
获取到点击的图片链接,然后根据需要的逻辑进行不同的跳转。
请注意,上述代码是使用小程序原生的 wx.navigateTo
进行页面跳转,如果你使用的是框架或组件库,可能有不同的方法来实现页面跳转。(2023/08/09晚)
实现点赞图片 1 2 3 4 <view class ="like" > <van-icon name ="{{isLiked ? 'like' : 'like-o'}}" color ="red" bindtap ="handleIconClick" /> </view >
1 2 3 4 5 6 7 8 9 10 11 handleIconClick ( ) { this .setData ({ isLiked : !this .data .isLiked , }); if (this .data .isLiked ){ Toast ("已收藏~" ) }else { Toast ('取消收藏~' ) } },
效果呈现
2024年4月22日
半年前尝试开发过第一个微信小程序,花费了二十天时间认真做功能实现.。当时为了开发这个小程序,还借鉴了不少相关小程序的页面排版,多方参照才最终定型了这版页面。那么最终的效果如下 :
踩坑记录
首先,能够正确获取到小程序的appID、appSecret:
开发者工具的appID必须设置正确,否则会不可避免地出现 invalid code 错误:(2023/08/06早)
1 { "errcode" : 40029 , "errmsg" : "invalid code, rid: 64cf07f9-36a4c687-09c960f0" }
公众号开通
2024年4月22日
今下午,我突然想要开通一个微信公众号,借此来激励我每天读书写作。那是因为最近开始慢慢回忆起小时候的乡村生活 ,写的东西渐渐多了起来。但总归是没时间没精力,写东西断断续续的,我对这样的写作现状很不满意。
于是下午看了很多相关公众号文章,计划近段时间就开启公众号文章写作计划:
我快速回顾了前段时间里了解到的有关微信公众平台的信息,包括小程序开发、智能机器人对话(动手做个 AI 机器人,帮我回消息!_牛客网 (nowcoder.com) )这些,把这些快遗忘的知识捡起来。
微信公众平台访问入口:微信公众平台 (qq.com)
注册一个微信公众号,选择订阅号 即可。
但接下来的一步就让我止步于此了,我必须要提供一个未被微信公众平台注册过 的邮箱
详细要求可以看这里:公众号注册提示“邮箱已被占用” (qq.com)
除了现在正在使用的 qq 邮箱外,去年写小程序时还用手机号申请了网易邮箱。但现在由于这个网易邮箱绑定了一个小程序,要想顺利开通微信公众号,目前只有两种解决办法:修改小程序登录邮箱 和注销小程序
虽然这个小程序是废稿,但毕竟是我开发的第一个微信小程序,未来可能还要继续优化呢。就这么注销了的话,本地的开发可能受到影响,怪可惜的。那最终的解决办法就是:今天晚上回去找我兄弟,让他注册一个网易邮箱,完事了我把小程序邮箱账号更换成他的,我开通的微信公众号就绑定我的网易邮箱吧。
那么现在就开始研究研究今年年初搞过的微信智能 AI 机器人了,不知道当时怎么想的,竟然没有记录下代码是如何起来的。相关的开发文档也没有多少记录,只有运行效果,只好是我再继续摸索摸索。
2024年4月23日
很好,昨天下午总结了一番微信智能 AI 机器人的开发流程,晚上又让我的好兄弟注册了新的网易邮箱。
这下我就成功开通了微信公众号了。
总结