一个 java 程序员最不务正业的一次分享了.
小程序的火热相信不用我多说了, 年初的时候老婆去浦东某达面试, 甚至都被问有没有小程序测试经验. 俨然小程序成为了互联网公司自 PC,WAP, 安卓, iOS 之后又一不可或缺的入口. 正好这段时间公司也在做一款小程序, 于是顺便也学习了一把. 当然因为我是一个 javaer, 自然是以后端的视角来谈谈, 和前端的同学肯定还是比不上的.
学习小程序, 我认为对于后端同学还是比较有优势的, 因为后端同学对于 html,CSS 以及 JS 这些前端基本知识还是有所涉猎的, 而前端的同学对于后端可能就没那么了解了. 接下来, 以我的实践经历来简单聊一聊小程序, 算是总结也算是个分享.
小程序用来做什么?
"触手可及","用完即走". 感觉这两个词把小程序的特点描述的真的是淋漓尽致. 以微信的用户量, 小程序免去了用户还需安装 App 的繁琐. 而且用完之后, 无需刻意退出, 直接离开即可, 当下次某个时间点在想起来, 重新翻出来就行了. 这对很多行业来说可能是颠覆性的. 以我个人的观点来看, 小程序适合做一些业务简单, 性能要求不高, 使用频率相对较低的应用. 比如像垂直电商行业就是典型的受益者, 自媒体电商, 生鲜电商, 如果让用户去下载一个这样的 App 成本是很大的, 而使用小程序确悄然的避免了拉新客的难题. 又比如我自己, 如果我把自己的博客做成了一个 App, 相信几乎不会有同学去下载, 而使用小程序却偶尔还会有些同学会点进来看看的, 哈哈.
入门小程序
首先开发小程序, 需要一个专门的工具[微信开发者工具] , 这个大家可以直接到微信公众平台下载.
接下来我们首先新建个快速启动模板看一下, 如果你有注册账号有 appid 的可以填入, 没有的话也没关系. 点击图中小程序即可使用测试账号.
如上图, 进入后即可看到这些文件.
可以说一个简单的小程序只有这些了.
App.JS 主要是全局公共的 JS 方法声明及调用所在的文件
App.JSON 是小程序全局的配置文件, 所以有的页面都在要此注册, 不然不允许访问
App.wxss 是小程序全局的 CSS 文件
pages 下是对应着所有页面, 每个页面, 可以添加四种类型的文件,.JSON,.wxss,.wxml,.JS
另外在说下这四种类型的文件, 小程序 pages 下面基本上每个文件夹相当于一个页面, 每个文件夹下面有四种命名相同但类型不同的文件, 这四种构成了页面的全部.
.JSON 后缀的 JSON 配置文件
.wxml 后缀的 WXML 模板文件, 类似 web 开发的 HTML
.wxss 后缀的 WXSS 样式文件, 类似 Web 开发的 CSS
.JS 后缀的 JS 脚本逻辑文件, 它就是一个 JS 啊, 不过小程序的 JS 不能操作 dom, 是基于数据绑定的哦
然后我们在看下 JS 文件的构成, 注释很清晰:
- Page({
- /**
- * 页面的初始数据
- */
- data: {
- },
- /**
- * 生命周期函数 -- 监听页面加载
- */
- onLoad: function (options) {
- },
- /**
- * 生命周期函数 -- 监听页面初次渲染完成
- */
- onReady: function () {
- },
- /**
- * 生命周期函数 -- 监听页面显示
- */
- onShow: function () {
- },
- /**
- * 生命周期函数 -- 监听页面隐藏
- */
- onHide: function () {
- },
- /**
- * 生命周期函数 -- 监听页面卸载
- */
- onUnload: function () {
- },
- /**
- * 页面相关事件处理函数 -- 监听用户下拉动作
- */
- onPullDownRefresh: function () {
- },
- /**
- * 页面上拉触底事件的处理函数
- */
- onReachBottom: function () {
- },
- /**
- * 用户点击右上角分享
- */
- onShareAppMessage: function () {
- }
})
了解了这些基本上小程序开发就没问题了, 其他就剩翻文档了. 这里我建议把文档当成字典来读, 读完简易教程和框架后, 其他需要什么来查什么就行了, 没必要像教科书一样一字不落的全看完.
因为微信开发者工具还比较初始, 之前每建一个页面, 我都是先建一个文件夹, 然后在分别把四个文件建好. 这里我介绍个小技巧, 大家可以首先将要新建的页面注册进 App.JSON, 这时候工具会自动把文件夹和四种文件给你建好. 说实话很奇怪, 这种方法在官方文档上我并没有看到, 不知道是我眼花还是官方真的没有写.
- {
- "pages":[
- "pages/index/index",
- "pages/logs/logs"
- ],
- "window":{
- "backgroundTextStyle":"light",
- "navigationBarBackgroundColor": "#fff",
- "navigationBarTitleText": "WeChat",
- "navigationBarTextStyle":"black"
- }
}
再说下页面的注册, 当我们在 App.JSON 文件中注册的时候,[pages/index/index] 会将该页面下 index.xx 的四种文件加载进来, 而不必一个个写了. 还有就是文件夹名字和文件名是可以不同的, 比如[pages/index/launch] 会将 index 文件夹下所有的 launch 文件加载. 但是建议还是一样把, 不然看着挺别扭的.
最后在多说句, 小程序的域名白名单问题, 我发现很多同学不知道, 包括身边的同事, 一直还在用内网穿透来开发.
首先小程序对应用请求的域名是有限制的.
请求的域名必须在后台配置, 非配置域名无法请求成功.
域名协议必须是 https 的, 如果是 http 请求也是会失败的
当然, 这是对线上版本来说. 如果是我们本地开发, 小程序提供了一个很人性化的功能. 可以忽略这个限制, 甚至你可以直接请求本地的 IP 地址 + 端口号, 而不必使用繁琐的内网穿透的方式了.
具体操作方式就是在微信开发者工具中, 点击[设置] -[项目设置] -[勾选] 不校验合法域名, Web-view(业务域名),TLS 版本以及 HTTPS 证书 即可, 如下图
下面就结合我的实践小程序来简单聊一聊, 更多的资料大家可以查阅文档
开源实践
恰巧前段时间做了个练手的 yyblog 的开源项目, 这次就拿这个项目做个简单的小程序客户端了. 还是惯例, 大家先看下效果图吧.
单纯的 HTML,CSS,JS 实现, 没有应用任何前端框架, 还是比较适合参考学习的. ppps: 反正我是不会说因为我不会才不用的 呜呜~~~ 流下了没有技术的泪水﹏.
微信小程序总的来说虽然已经上线那么久, 但和传统意义上的开发语言上比, 还不是那么稳定的, 官方也在不断的调整中.
相信很多同学有遇到过这样的场景, 当你第一次进入一个小程序的时候, 会弹出来一个用户信息授权的弹窗. 刚开始我写的时候也是这样处理的, 但是后来在上传代码的时候看到, 微信在 9 月 12 号的时候发了一个公告.
主要是取消了分享监听接口的回调, 将获取用户信息的 getUserInfo 接口改为只有用户点击了相关授权组件才能触发, 还有就是 openSetting 接口也改为了点击才能触发. 所以做微信小程序开发还是要做关注下官方的动态, 以免做好的功能确不能正常使用的尴尬.
全局配置
前面有说 App.xx 的相关文件, 是小程序的全局配置文件, 这里在单独说下 App.JS 这个文件. 当我们某些参数是全局需要的时候, 我们就可以将相关的参数写在这个文件里面, 比如我们请求的基础 url, 亦或是用户信息, 用户 ID 这种请求必须携带的参数. 同时我们可以将版本校验的代码写在这里, 这里在多说一句, 微信是支持版本校验的, 当有新的版本代码的时候, 可以做用户更新提示, 这里不再需要我们后台校验, 还是比较方便的. 相关的代码如下:
- App({
- onLaunch() {
- this.checkUpdate();
- },
- globalData: {
- userInfo: {},
- apiBase: "https://www.laoyeye.net",
- userId: ""
- },
- checkUpdate() {
- const updateManager = wx.getUpdateManager();
- updateManager.onCheckForUpdate(function (res) {
- // 请求完新版本信息的回调
- console.log(res.hasUpdate)
- })
- updateManager.onUpdateReady(function () {
- wx.showModal({
- title: '更新提示',
- content: '新版本已经准备好, 是否重启应用?',
- success: function (res) {
- if (res.confirm) {
- // 新的版本已经下载好, 调用 applyUpdate 应用新版本并重启
- updateManager.applyUpdate()
- }
- }
- })
- })
- updateManager.onUpdateFailed(function () {
- // 新版本下载失败
- console.log('更新失败!')
- })
- }
})
启动页
用户在刚开始进入小程序的时候, 首先会展现一个启动页. 起初我也不是这样设计的, 基本上是用户进入后直接进入主页, 弹出用户授权就行了, 但是因为 9.12 的调整, 也不得不作出了修改. 让用户首先进入启动页授权, 授权后跳转到主页. 已授权的用户就把授权按钮隐藏, 然后在等待 1.5s 后跳转到主页. 这个过程中我除了做了获取用户授权的操作之外, 还请求后台服务器在后台创建了用户数据, 最终将 userId 返回到小程序. 以后用户做评论, 点赞, 收藏等操作, 均会携带 userId, 方便区分具体的用户.
这个页面其实有两个比较重要的知识要点, 这里特别强调下.
首先, 我们需要获取每个用户对于当前应用的 openId, 以便下次用户访问时, 避免再次授权的重复操作.
调用 wx.login()接口获取登录凭证 (code) 进而换取用户登录态信息, 包括用户的唯一标识 (openid) 及本次登录的 会话密钥(session_key) 等. 但是需要注意的是, 用 code 去换取 openid 的操作, 需要在服务端后台来做, 如果在小程序 JS 上交换, 在开发版本你会看到也是可以正常获取登录, 但是到生产上就不行了, 因为小程序的安全限制, 官方的域名是无法设置到白名单里.
代码如下:
- login(auth) {
- let that = this;
- // 调用微信登录接口
- wx.login({
- success: function(res) {
- wx.request({
- url: App.globalData.apiBase + '/api/wx/login?code=' + res.code + '&nickname=' + App.globalData.userInfo.nickName +
- '&avatar=' + App.globalData.userInfo.avatarUrl,
- header: {
- 'content-type': 'application/json'
- },
- success: function(res) {
- //userId
- if (res.data.code == 200) {
- App.globalData.userId = res.data.data;
- console.log('获取用户信息 =' + res.data.data);
- if (auth == 'auth') {
- that.direct();
- } else {
- let timer = setTimeout(() => {
- clearTimeout(timer)
- that.direct()
- }, 1500)
- }
- }
- }
- })
- }
- })
},
第二, 就是 getUserInfo 这个接口了, 因为新规定的限制, 以往如果用户没有授权, 是会弹出授权的弹窗的. 但是新规定之后如果你调用这个接口是在用户没有授权的情况下, 那么会直接进入 fail 失败的回调的. 所以你必须通过组件获取用户的授权, 然后在用户点击的回调里在调用这个方法.
代码如下:
- <button class="show-btn" wx:if="{{userInfo.length == 0}}" type="primary" open-type="getUserInfo" bindgetuserinfo="onGetUserInfo"> 授权登录 </button >
- onGetUserInfo() {
- var that = this;
- wx.getSetting({
- success: function(res) {
- if (res.authSetting['scope.userInfo']) {
- wx.getUserInfo({
- success: function(res) {
- App.globalData.userInfo = res.userInfo;
- that.login('auth');
- },
- fail: function() {
- console.log('系统错误')
- }
- })
- } else {
- wx.showToast({
- title: "授权失败",
- duration: 1000,
- icon: "none"
- })
- }
- },
- fail: function() {
- console.log('获取用户信息失败');
- }
- })
},
最后, 这里在讲个小问题, 我不知道是不是我个人的问题, 我在做页面数据赋值的时候, 会使用
this.data.requestUrl = requestUrl;
或者
- this.setData({
- postList: totalData
- });
的方法. 如果是异步情况下, 必须使用方法二, 页面上才能取到数据. 但是有些情况下非异步方法里使用方法一数据竟然取不出来, 可是我在断点中明明看到数据是赋值成功的啊. 而这个时候换成方法二却又成功了. 真的是不明所以, 大家尽量使用方法二吧.
主页, 技术页
把这两个页面一起讲, 原因就是两个页面虽然展现形式上不同, 但是技术特点上还是想同的. 唯一的区别, 可能就是后期我会把两个页面的数据接口做个调整, 请求不同的数据了.
这个页面主要是两个知识点, 上拉加载更多和下拉刷新了.
首先是上滑加载更多数据, 这个其实是小程序官方提供的一个 onReachBottom 的方法, 只要用户上滑到一定距离就会触发, 这里我做了分页的处理. 首次进入展示五条数据, 当触发事件后请求第二页的数据. 当然请求到第二页的数据并不能覆盖之前的数据哦, 不然当用户在下滑时, 刚才的数据没了, 是不符合用户习惯的.
上滑事件触发的距离也是可以通过 onReachBottomDistance 实现的, 默认 50px
具体实现的代码如下:
- // 上滑加载更多数据
- onReachBottom: function (event) {
- var nextUrl = this.data.requestUrl +
- "?page=" + this.data.page + "&limit=5";
- util.Ajax(nextUrl, "get", null, this.processData)
- wx.showNavigationBarLoading()
},
- processData: function (indexData) {
- var totalData = {};
- // 如果要绑定新加载的数据, 那么需要同旧有的数据合并在一起
- if (!this.data.isEmpty) {
- totalData = this.data.postList.concat(indexData);
- }
- else {
- totalData = indexData;
- this.data.isEmpty = false;
- }
- this.setData({
- postList: totalData
- });
- this.data.page += 1;
- wx.hideNavigationBarLoading();
- wx.stopPullDownRefresh();
},
然后是下拉刷新, 下拉刷新默认是不开启的, 需要我们在 *.JSON 配置中通过 enablePullDownRefresh 属性开启, 默认为 false.
如果在 App.JSON 中设置为全局开启下拉刷新, 在具体页面中即为当前页面开启.
相关代码如下:
- {
- "navigationBarTitleText":"小卖铺的老爷爷",
- "enablePullDownRefresh": true
}
- onPullDownRefresh: function (event) {
- var refreshUrl = this.data.requestUrl +
- "?page=0&limit=5";
- this.data.techList = {};
- this.data.isEmpty = true;
- this.data.page = 1;
- util.Ajax(refreshUrl, "get", null, this.processData);
- wx.showNavigationBarLoading();
},
其实这两种方法, 在大家看官方文档全局配置的时候就会看到的. 上面我也有说过学习小程序, 官方文档的简易教程和框架还是必看的, 其他的就没那么重要了.
详情页
详情页其实就一个要讲, 富文本的解析.
因为微信小程序并不支持 HTML 语言, 所以需要转换为微信支持的 wxml.
总的来说微信对富文本的支持并不好, 官方也没什么好用的富文本解析组件. 这次我使用的是 GitHub 上关注度最高的小程序富文本组件 https://github.com/icindy/wxParse , 虽说相对比较完善了, BUG 还是不少的, 而且作者好像也不维护了. 但是目前实在没有找到其他什么好的替代方案, 只能用这个了. 如果大家还有其他组件, 可以告诉我一下哈.
https://github.com/icindy/wxParse 的使用, 项目上已经讲的很清楚了, 大家方便可以移步: https://github.com/icindy/wxParse 查看.
我这边对 wxParse 做了一些小改动, 主要解决部分手机报错无法解析的问题. 原因是微信小程序不支持 console.dir()的写法, 这个小程序官方也有在社区说明.
分享
当你在页面的 JS 文件中, 定义了 onShareAppMessage 函数, 这时候页面便拥有了分享功能, 可以转发给微信好友.
- /**
- * 用户点击右上角分享
- */
- onShareAppMessage: function () {
- return {
- title: this.data.postData.title,
- path: '/pages/post-detail/post-detail?id=' + this.data.id + "&title=" + '小卖铺的老爷爷' + "&share=1"
- }
},
如上, 是我的分享代码, 设置了分享的标题, 以及跳转的路径等. 这里我对路径做了参数处理, 以便我能区分出用户的来源. 为什么要区分用户来源呢, 因为小程序的分享页面进入后有个很奇怪的问题, 没有返回主页的按钮. 所以我这边单独做了区分, 当用户来自分享时, 显示一个悬浮的返回首页的图标.
相关代码如下:
- <!-- 回到首页(分享的时候显示) -->
- <image wx:if="{{share}}" bindtap='onBackHome' class='back-home' src='/images/icon/home-page.png' lazy-load></image >
- /**
- * 回到首页(分享的时候)
- */
- onBackHome: function () {
- wx.reLaunch({
- url: '/pages/launch/launch?share=1"'
- })
}
我的
最后在说说我的这个页面, 其实这个页面没啥重要的东西. 只是静态页面的跳转.
个人信息后期我会做成可绑定 PC 端账户的形式.
我的收藏是已经实现过的, 只是可能详情页还没有具体收藏的入口, 后期我会加上. 具体的效果图如下.
还有一个就是打赏赞助这个页面, 刚开始是准备做成小程序间关联, 使用给赞 API 的接入方式. 但是最近小程序官方对多个小程序间的跳转也要增加限制, 就懒得弄了.
直接做了个详情页的跳转, 详情页面贴了张赞赏码完事. 需要注意的是小程序页面并不支持直接长按扫描哦, 需要点击下图片, 在弹出的图片上在长按识别图中的二维码.
ppps: 写完文章后才想起来这个页面忘记说一个东西. 小程序是可以使用阿里 icon 库的, 具体使用方法大家网上看看吧. 不说了, 有兴趣的也可以看下我源码中的实现.
来源: https://juejin.im/post/5bcda068518825780d09b25b