小程序开发现在主要分为原生和框架开发。
在对比了相关的优劣势之后个人还是比较倾向于使用框架,主要是开发效率真的比原生高出挺多的,而且在实战下来也没有想象中的那么多的大坑,基本上小程序能够实现的东西uni-app也都能够很好地适配了。下面就来讲一下我开发遇到的一些问题,当做一份uni-app开发小程序的经验总结吧。
全局问题
小程序分包
微信小程序每个分包的大小是2M,总体积一共不能超过16M。
小程序的分包应该是最首先应该考虑的问题,毕竟谁也不知道项目的功能会不会越加越多,而且uni-app打包到小程序的大小会比原生开发更大,会更容易达到2M的上限。到最后因为一开始没有考虑到分包,而重新更改目录结构再去进行分包的话,工作量会比较大。
跨平台问题
- 首先在项目方案刚开始的时候就明确最终是要需要打包到哪几个端的时候,得先去官方文档看看vue语法特性支持表,确认一下自己会会用的语法是在相应端支不支持的,有没有替代方案,以免到时候出bug定位不到问题。
- 其次,很多人可能会在开发的时候引用到一些组件库,比如WeUI、vant等,如果只需要考虑到一个端的话,可以放心引入。如果项目未来有需要实现跨端的可能性的话,建议还是全部自己重新写所需要的的组件。如果不知道如何实现,需要参考的代码的话,可以去uni-app的插件市场看看有没有适合的,把核心代码拿下来再进行修改。
项目创建
uni-app的官方文档也写清楚用cli创建和可视化界面创界的区别了。实际开发下来两种方法其实都差不多。官方自带的可视化界面很多快捷语法都是挺方便的,特别最喜欢的是image标签能够直接识别出本地的图片路径。但是那个编辑器的部分操作实在是不那么友好,最终还是用vscode比较香。
最最离谱的一个问题是,官方文档虽然写着说用cli创建的是可以直接更新的,说的是升级编译器执行npm update就可以了,后来隔了好几个月之后尝试更新了一下,想要用一个小程序官方新出的特性。更新之后项目直接就报错不能执行了,报错信息较多且难以解决。这是用uni-app的一个风险点。
项目打包
小程序打包发到生产版本的时候,记得要将运行build命令的包进行上传,打包后的体积会小很多。
npm run build:mp-weixin
图标问题
小程序的图标和图片尽量都使用网络地址,在真机上出现过偶现无法加载的情况,是小程序官方写出的bug,在近期才进行修复了。并且用网络地址不占用小程序打包的空间。
开发经验汇总
以下开发经验有些是小程序本来就有的,只是这里顺带说一下uni-app的实现。总的来说所有在小程序以wx.开头的API,在uni-app的小程序端都是可以直接用wx.进行使用,前提是当前uni-app的框架是支持当前小程序的特性。
小程序自定义标题栏
如果想要实现类似于下面这种样式的标题栏的话,只要在pages.json设置
{
"path": "test",
"style": {
"navigationStyle": "custom"
}
}
然后页面中自带的标题栏就会被隐藏掉,然后你就可以把自己的标题栏组件放进页面中,值得一提的是,以下方法可以获取到胶囊的高度和当前距离顶端的位置,就可以解决标题栏的适配问题。
onReady () {
let menuButtonInfo = uni.getMenuButtonBoundingClientRect()
let menuHeight = menuButtonInfo.height
let menuTop = menuButtonInfo.top
}
textArea层级问题
问题地址
textArea由于小程序的bug问题,textarea的文字会永远在最上层无法被遮挡,如果有其他弹出层的会出现在textarea上方时候(比如弹窗),需要把textArea先清空掉,或者直接用v-if来隐藏掉整个textarea,之后再进行恢复。
图片查看控件
小程序中如果想要点击图片将图片进行预览,实现类似于在微信聊天中的图片查看器效果,需要用到以下的方法:
wx.previewImage({
current: this.baseImgUrl + this.userData.qrCode, //当前图片地址
urls: [this.baseImgUrl + this.userData.qrCode], //所有要预览的图片的地址集合 数组形式
success: function(res) {},
fail: function(res) {},
complete: function(res) {}
});
获取授权
获取微信登录授权是可以用 wx.authorize直接调用获取微信的登录授权的。但是获取用户信息的wx.authorize({scope: "scope.userInfo"}),不会弹出授权窗口。必须使用以下的方法进行调用,静默授权在开发者平台和真机测试的时候,不方便区分没有授权和授权的情况。并且微信官方也说明了这个方法之后会被废弃掉,有较高的使用风险。
<button open-type="getUserInfo" ref="authorize" @getuserinfo="getuserinfo">授权登录</button>
一般建议页面中不用重复刷新,只在首次加载的时候会显示的数据放在onload中进行获取,会方便之后授权登录之后,再重新调用一遍页面的onload事件,即可重新执行一遍页面初次加载时会执行的方法
let page = getCurrentPages().pop()
let option = page.options
page.onLoad(option)
webview
小程序的webview是会占满整个宽高的,自动铺满整个页面。支持部分小程序的方法。最重要的是网页内 iframe 的域名也需要配置到域名白名单。
developers.weixin.qq.com/miniprogram…
v-html
如果需要富文本在uni-app直接使用v-html即可,小程序端也是支持的,会自动转换为小程序中的标签。如果需要对返回的html字符串添加样式的话,建议使用正则进行匹配。
接口的封装方法
如果需要实现axios的拦截器功能,需要手动对接口的请求方法进行封装,具体也可以操作uni-app的插件市场的封装,以下是实现代码
export default {
_this: this,
config: {
//主URL
baseUrl: "https://api.vc.bilibili.com/link_setting/", //只是举个例子
header: {
'Content-Type': 'application/json;charset=UTF-8'
},
data: {},
method: "GET",
dataType: "json",
/* responseType如设为json,会对返回的数据做一次 JSON.parse */
responseType: "text",
success() {},
fail() {},
complete() {}
},
interceptor: {
request: (config) => {
let token = ''
if (token) {
config.header.token = token
}
return config
},
response: (response) => {
//在调试的时候此处可以将所有返回都打印一下,方便小程序在真机中查看接口返回
// console.log(response)
}
},
request(options = {}, iterceptor = {
request: undefined,
response: undefined
}) {
options.baseUrl = options.baseUrl || this.config.baseUrl
options.dataType = options.dataType || this.config.dataType
options.url = options.baseUrl + options.url
options.data = options.data || {}
options.method = options.method || this.config.method
options.header = options.header || this.config.header
let interceptorRequest = iterceptor.request || this.interceptor.request
let interceptorResponse = iterceptor.response || this.interceptor.response
return new Promise((resolve, reject) => {
let _config = null
options.complete = (response) => {
let statusCode = response.statusCode
response.config = _config
if (interceptorResponse) {
interceptorResponse(response)
}
if (statusCode === 200) { //成功
resolve(response);
} else {
reject(response)
}
}
_config = Object.assign({}, this.config, options)
if (interceptorRequest) {
interceptorRequest(_config)
}
uni.request(_config);
});
}
}
下面是对上面封装好的js文件的引用方法
import http from './interface'
export const test = (data) => {
return http.request({
url: 'ajax/echo/text?name=uni-app',
dataType: 'json',
data,
})
}
地图的注意事项
地图的相关界面预览必须要在真机进行,千万不要只在微信开发者工具进行预览然后就以为功能制作完成了。尤其是要在ios和安卓的两个平台都分别预览一下。
如果需要监听regionchange的事件然后对地图渲染进行操作的话,记得不要将会改变地图位置的方法放在监听的事件里面。不然会造成死循环。而且很多
regionchange(e) {
if(e.causedBy==='drag'){
this.updatedMapCenter()
}
if (this.firstLoadMap||e.causedBy==='update'||e.causedBy==='drag') {
return false
}
this.getInstanceMapData()
},
分享的页面
小程序的页面默认是不带分享按钮的,如果点击右上角的分享会变成灰色。如果页面需要开启分享的功能的话,加上这个事件即可
onShareAppMessage(ops){
console.log(this.selectedApartDetail);
return {
title: '点击查看营业部',
path: /pagesHome/home, //点击分享消息是打开的页面
imageUrl: '../logo.png'
}
}
如果需要全局设置的话,可以在App.vue中对所有的页面,通过onAppRoute时间动态给每个页面绑定上onShareAppMessage事件。
wx.onAppRoute(function (res) {
let pages = getCurrentPages(),
//获取当前页面的对象
view = pages[pages.length - 1]
if (view) {
let rewriteState = true
for(let item of notRewirte){
if(view.route.indexOf(item)!==-1){
rewriteState = false
break
}
}
if (rewriteState) {
view.onShareAppMessage = (a,b,c)=>{
let returnPath = ''
return {
title: 'test',
path: returnPath,
imageUrl: '../../../static/login/log.png'
};
}
}
}
})
将页面保存成图片
很经常会遇到的一个需求是将页面整个页面保存成图片,然后方便用户分享图片至朋友圈对小程序进行引流。主要实现思路是将页面保存为
canvas
<canvas canvas-id="myCanvas" class="canvasIs"/>
//省略部分代码
const ctx = wx.createCanvasContext('myCanvas');
const grd = ctx.createLinearGradient(0, 0, 0, 0);
grd.addColorStop(0, '#fff');
grd.addColorStop(0, '#fff');
ctx.setFillStyle(grd); //为创建的canvans上下文添充颜色 如果没有设置 fillStyle,默认颜色为 black。
ctx.fillRect(0, 0, 300, 556);
ctx.drawImage(this.data.img, 0, 0, 300, 556);
ctx.setFontSize(50); //字大小
ctx.setTextAlign('center'); //是否居中显示,参考点画布中线
ctx.setFillStyle("#333333");
ctx.fillText("需要的文字", 210, 285);
ctx.draw();
导出图片之前需要先获取小程序的保存图片权限
wx.openSetting({//进入小程序授权设置页面
success(settingdata) {
console.log(settingdata)
if (settingdata.authSetting['scope.writePhotosAlbum']) {//用户打开了保存图片授权开关
wx.saveImageToPhotosAlbum({
filePath: benUrl,
success: function (data) {
//然后操作下面的代码
},
})
}
}
})
然后使用canvasToTempFilePath将canvas导出成图片
wx.canvasToTempFilePath({
x: 0,
y: 0,
width: 300, //画布宽高
height: 556,
destWidth: 600,
destHeight: 1112,
canvasId: 'myCanvas',
success: function(res) {
wx.saveImageToPhotosAlbum({
filePath: res.tempFilePath,
success: function(res) {
//console.log(res);
wx.hideLoading()
wx.showToast({
title: '保存成功',
})
},
fail: function(err) {
}
})
}
})
先写这么多啦,有想起来的话我再继续补充。如果有哪里写得不清楚的地方欢迎向我询问哦。喜欢的话可以点个赞,谢啦。