写在前面
因微信小程序宣称解决了前端程序员头痛的兼容问题,只需要按照腾讯官方那一套规则进行编码就可以满足不同的终端需求。所以去年下半年我就用微信小程序实现了我们公司内部使用的一个项目(目前使用人数700+),下面是我在摸索过程中的一些总结经验,给后面的同学铺铺路,让大家早点下班回家陪老婆孩子。
你将学习到:
- 如何使用自定义tabbar及权限控制
- 如何使用echarts图表插件
- 程序大小超过限制如何分包
- 如何使用vantUI组件,解决弹出层滑动穿透页面滚动
- 自定义头部及滚动页面浮现到顶部
- 如何实现自动更新,以及手动更新方案
- 内部使用软件需要登录,如何通过审核
其它一些坑 - 使用wepy设置data后为何不更新视图
- wepy methods中怎么访问自己的methods方法
- 小程序命名可能违反规定
- iOS上时间Date初始化的坑
1 如何使用自定义tabbar及权限控制
使用过原生tabbar的同学都知道,原生tabbar太丑了,而且想自定义一些样式完全没法,大多数app最终都会有自定义tabbar的需求。
按规矩先丢官方链接
使用步骤:
拷贝官方demo中的custom-tab-bar文件到根目录
我用的wepy框架,则复制到src目录下如图,没错自定义tabbar部分需使用原生的写法,其他自己的业务页面使用wepy框架。
入口文件app.json启用自定义tabbar
wepy框架在app.wpy config对象中
list中的pagePath是自己页面的目录是必须的,其他属性都可以删除,因为具体的tabbar样式(如图片和颜色)还是得在自定义custom-tab-bar中设置。
"tabBar": {
"custom": true,
//"color": "#7A7E83", //这里写了不起作用可注释
//"selectedColor": "#3cc51f",//这里写了不起作用可注释
//"borderStyle": "black",//这里写了不起作用可注释
//"backgroundColor": "#ffffff",//这里写了不起作用可注释
"list": [
{
"pagePath": "index/index",
"iconPath": "image/icon_component.png",//这里写了不起作用可注释
"selectedIconPath": "image/icon_component_HL.png",//这里写了不起作用可注释
"text": "组件"//这里写了不起作用可注释
},
{
"pagePath": "index/index2",
"iconPath": "image/icon_API.png",//这里写了不起作用可注释
"selectedIconPath": "image/icon_API_HL.png",//这里写了不起作可注释
"text": "接口"//这里写了不起作用可注释
}
]
},
回到自定义custom-tab-bar/index.js
有如下代码:
Component({
data: {
selected: 0,//默认选中项下标
color: "#7A7E83",//默认项字体颜色
selectedColor: "#3cc51f",//选中项字体颜色
list: [{
pagePath: "/index/index",
iconPath: "/image/icon_component.png",
selectedIconPath: "/image/icon_component_HL.png",
text: "组件"
}, {
pagePath: "/index/index2",
iconPath: "/image/icon_API.png",
selectedIconPath: "/image/icon_API_HL.png",
text: "接口"
}]
},
attached() {
},
methods: {
switchTab(e) {
const data = e.currentTarget.dataset
const url = data.path
wx.switchTab({url})
//this.setData({ 注释掉这三行
// selected: data.index
//})
}
}
})
注释掉this.setData()方法是因为跳转的tab页面也会setData一次,避免重复设置data导致闪烁,继续往下看。
为每个tab页面生命周期show添加代码
在wepy框架中是onShow方法。
获取当前页面对象this.$wxpage
onShow() {
if (typeof this.$wxpage.getTabBar === 'function' &&
this.$wxpage.getTabBar()) {
this.$wxpage.getTabBar().setData({
selected: 0//每个tab页在配置的list数组中下标不同,需要相应修改
})
}
}
不难发现,在每次进入tab页的时候都会获取当前页面的bar对象(tabbar对象在每个tab页面中不是同一个,都是一个新的对象),然后设置selected。所以在上面的switchTab方法中注释掉setData方法,因为重复了。
菜单右上角数字info实现及更新
- list数组中添加属性infoNum(需要的菜单项才添加)。
- wxml代码中按条件渲染infoNum(有值且大于0才显示)。
- 每个tab页show生命周期中获取info数字后setData。
this.$wxpage.getTabBar().setData({
['list[1].infoNum']: infoNum //更新info数字
})
['list[1].infoNum']
更新多层对象的方式,是不是有点想吐槽了
根据登陆的角色控制菜单项
我相信有很多同学也有这个需求,根据登陆的用户不同,看到的底部菜单也不同,例如:管理员。
实现的方式和info非常相似
- list数组中添加属性show
- wxml代码中 wx:for循环中中按条件添加show和hide的className
- 登陆后获取用户权限列表,判断要显示或隐藏的项
调用方法更新bar实例的data
为了方便,可以在custom-tab-bar/index.js
methods中创建方法,然后在每个tab页面调用:this.$wxpage.getTabBar().yourFuncName(balabala)
,注意是每个bar页,因为上面说到每个tab页bar实例是独立的。原生页面获取TabBar实例直接
this.getTabBar()
即可。
因篇幅有限有些细节并没有说完,有需求可留下评论或直接联系我。
如何使用echats图表插件
在小程序中使用图表是非常常见的需求,好在已经有了比较成熟的echarts组件。使用方法很简单,按规矩先甩官方链接
按照官方文档配置即可,但需要注意的点:
- 原版echarts.js比较大,小程序打包有大小限制,推荐到echarts官网按需打包
- 需要在style中写上:
ec-canvas {
width: 100%;
height: 100%;
}
3.在微信开发工具中预览echarts图表显示有问题,但是在真机上没出现
程序大小超过限制如何分包
小程序为了用户保证快速打开程序、有一个良好的用户体验。所以限制了小程序的大小(总共不超过20M,每个包不超过2M),但是我们随着程序越来越复杂、页面越来越多,少不了会超过限制,还好官方给了一个分包的方案。按规矩官方链接
- 简单说就是主要的页面(tabbar关联的那几个页面)优先下载到客户端并展示-主包
- 其它次要页面(详情页)可以在需要的时候下载展示。-分包
其中分包可以有任意多个,这样就能有效的控制每个包的大小。
核心配置代码:
app.js/app.wepy
pages: [ //主包tab页
'pages/index',
'pages/bill',
'pages/mgMenu',
'pages/my',
],
subPackages: [{//分包配置,是数组代表可以添加多个
root: 'subPackage1',//subPackage1是分包目录名可取自己想要的名称
pages: [
"pages/login", //登录
"pages/billDetail", //账单详情
"pages/shopDetail", //商品申请
]
}],
注意:每次新增一个页面都要在相应包的pages中添加页面路径
说到小程序的大小问题,项目中的静态文件例如(开源js、字体、图片、视频)等可以丢到CDN上面去,一方面减少打包大小,一方面增加读取速度。CDN可以使用收费的如阿里,也可以使用免费的CDN,如BootCDN、jsdelivr(最近国内很慢慎用)、unpkg国内版等。如果大家感兴趣我将单独写一篇白嫖CDN的文章。
如何使用vantUI组件
在现在快速迭代的趋势下,UI库显得就很重要了,个人比较喜欢有赞开源的vantUI,当然其他UI库也有非常不错的,看个人喜好。按规矩甩出官方链接
下面分享下我用vant组件的一些心得:
我选择的是下载编译后的组件代码,项目需要哪个组件就拷贝到自己的components中,点这里
使用这个方法有个弊端,就是使用的组件如果依赖其他组件,需要一并拷贝。依赖的组件可以看组件/index.json
例如<van-button>
组件的index.json
如下:{ "component": true, "usingComponents": { "van-icon": "../icon/index", "van-loading": "../loading/index" } }
可以看到
<van-button>
组件还依赖于<van-iconn>
和<van-loading>
组件,这时候我们把<van-iconn>
和<van-loading>
组件也拷贝到自己的components目录中即可。
2.在页面中使用前需在usingComponents
中配置,且配置时的路径是相对位置,不能像import
中用@
的形式,必须用..
来寻找路径。
usingComponents: {
"van-action-sheet": "../components/lib/action-sheet/index",
"van-toast": "../components/lib/toast/index",
"van-picker": "../components/lib/picker/index",
"van-popup": "../components/lib/popup/index",
"van-search": "../components/lib/search/index"
},
Popup弹窗阻止页面滚动方法
当我们用Popup弹出层弹出时间选择器,或者picker等。此时滚动弹出层内容时,底部的主页面内容也会滑动,影响用户操作,我们可以用<scroll-view>
包裹住主内容默认scroll-y="true"
,当我们现实弹出层的时候设置属性scroll-y="{{false}}"
。
通过变量控制即可:
<scroll-view scroll-y="{{!noScroll}}" bindscroll="scrol">
在弹出层显示或隐藏时设置noScroll
为true
或者''(空字符串)
。注意"false"
这个字符串布尔值其实是true
另外如果页面本身只有一屏内容,没有滚动需求的时候,可以通过页面config设置disableScroll:false
内部使用软件如何通过审核
企业内部的软件大多数都是进入程序必须登录才能继续使用,但不符合小程序官方的设计规范。之前我们公司就是进入页面就跳转到登录页,结果审核不通过。
如果你的页面保密性没那么强,可以默认显示主页及菜单,但是数据都是留白。在关键地方提示登录后可见,
我们公司小程序访客模式如下:
如果你的软件保密性较强,必须授权用户登录才行,可以在发起审核时提供一个体验账号给审核人员,并且注明软件只是企业内容使用。
自定义头部及滑动浮现在顶部
自定义头部也是比较常见的需求,下面说明我是如何实现的
- 页面config设置
navigationStyle:'custom'
- wxml中加入代码
<view class="cus-head" hidden="{{!showCusHead}}" style="height:{{cusHead}}"></view>
<view class="head-title" style="top:{{titleTop}}">我是页面标题</view>
cus-head
:自定义头部块 fixed
布局 。
head-title
:标题 fixed
布局,保证 z-index
在cus-head
之上,top
值要保证同胶囊相同,line-height
保证同胶囊高度一致。以下是获取胶囊的api:
const res = wx.getMenuButtonBoundingClientRect()
console.log(res.height)//获取胶囊高度
console.log(res.top)//获取胶囊top值
cusHead
:自定义头部,高度要保证大于胶囊高度,可更据自己需要调整。
showCusHead
:控制显示隐藏,在滚动到一定程度时显示,滚回顶部时隐藏
- 添加滚动监听函数
scroll(e) { //滚动时触发 wepy框架 原生使用setData方法
const top = e.detail.scrollTop;
if (top >= 10) {
this.showCusHead = true;
} else {
this.showCusHead = false;
}
this.$apply();
},
如何实现自动更新,以及自动更新时的手动更新备用方案
在app.wpy或app.js生命周期show/onLaunch中加入以下代码。自己可以写成一个函数直接调用。
完整代码参考:
// 获取小程序更新机制兼容
if (wx.canIUse('getUpdateManager')) {
const updateManager = wx.getUpdateManager()
//1. 检查小程序是否有新版本发布
updateManager.onCheckForUpdate(function (res) {
// 请求完新版本信息的回调
if (res.hasUpdate) {
//2. 小程序有新版本,则静默下载新版本,做好更新准备
updateManager.onUpdateReady(function () {
wx.showModal({
title: '更新提示',
content: '新版本已经准备好,是否重启应用?',
success: function (res) {
if (res.confirm) {
//3. 新的版本已经下载好,调用 applyUpdate 应用新版本并重启
updateManager.applyUpdate()
} else if (res.cancel) {
//如果需要强制更新,则给出二次弹窗,如果不需要,则这里的代码都可以删掉了
wx.showModal({
title: '温馨提示',
content: '本次版本更新涉及到新的功能添加,旧版本无法正常访问的哦~',
success: function (
res) {
self.autoUpdate()
return;
//第二次提示后,强制更新
if (res
.confirm
) {
// 新的版本已经下载好,调用 applyUpdate 应用新版本并重启
updateManager
.applyUpdate()
} else if (
res
.cancel
) {
//重新回到版本更新提示
self.autoUpdate()
}
}
})
}
}
})
})
updateManager.onUpdateFailed(function () {
// 新的版本下载失败
wx.showModal({
title: '更新提示',
content: '新版本已经上线啦~,请您删除当前小程序,重新搜索打开',
})
})
}
})
# } else {
// 如果希望用户在最新版本的客户端上体验您的小程序,可以这样子提示
wx.showModal({
title: '提示',
content: '当前微信版本过低,无法使用该功能,请升级到最新微信版本后重试。'
})
}
备用更新方案
在小程序页面中例如个人中心,加入版本号,给版本号添加点击事件,点击后再次调用上面的方法,进行手动更新。
其它一些坑
wepy框架设置data后要手动调用this.$applay()视图才会更新
对于使用vue的同学很不友好,经常会忘了写导致视图没有更新,以为是出什么bug了
wepy methods
中无法通过this.funname
访问自己
- 要用this.funname直接访问的话需要写在最外层(同生命周期同层级)
- 如果硬要直接调用可使用 this.methods.funcName.call(this)
iOS系统上new Date报错问题
iOS系统上通过new Date('2021-1-1 12:00:00')
这种通过-
连接的字符串无法识别,可通过 .replace(/\-/g, '/')
方法替换成'/'
解决。
小程序命名可能违反规定
小程序上线时的名字是非常关键的,名字在某种程度上是引流的工具,但是小程序官方对名称有非常严格的规定,如果不按照规定取名,上线后会强行下架。我们公司就取了“电费”这个词语,然后要求整改改名,因为这个词语是政府性质的,私有企业不能使用。官方连接
感谢
由于是第一次写这类技术文章,有诸多不足之处,感谢你看到最后,如果这篇文章对你有帮助请不要忘了给我点赞、评论。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。