之前一直是在有道云笔记上记录自己的学习笔记,最近一直有想法想有一个自己的技术博客,一方面可以和大家分享讨论,另一方面也是想通过公开的技术博客为自己的简历加分。
正好最近在自学uniapp,就把知识点记录在这份笔记中,作为自己的第一篇博客。也希望能帮助到想要学习uniapp的同学,一起查漏补缺。这篇笔记后面会一直更新。
uniapp的优势
- 一套代码可以打包到不同的应用平台(如微信小程序,手机端APP,H5),是目前跨端开发使用最多的方案;
- 门槛低,直接使用vue的语法即可完成开发,对于熟悉vue的开发者非常友好;
- 生态环境丰富,拥有大量的官方及第三方插件。
开发环境搭建以及调试
- 下载并安装HbuilderX作为开发工具;
- 下载安装微信开发者工具作为微信小程序的调试工具;
- 在微信开发者工具中的”安全设置”中,打开服务端口,就可以在HbuilderX中连接微信小程序进行调试了;
- 真机调试,需要用USB连接手机和电脑,打开开发者模式的USB调试选项,在HbuilderX中安装真机插件,然后选择运行到Android APP设备基座,它会在手机上下载一个Hbuilder,然后就可以调试APP了。
项目结构
- pages.json 微信小程序的配置文件,用于配置导航部分、tabbar、路由部分;
- manifest.json 配置appid、logo、地图sdk等等;
- main.js vue项目的入口文件;
- App.vue 全局的公共css样式,事件监听(比如上来就要登录);
- static 静态资源文件夹,放图片、字体图标
- pages 页面文件夹,放的都是路由页面
- components 组件文件夹,放的是在各个页面都可以公用的组件
- common 全局的css文件样式,比如主题色,间距
底部导航tabbar
uniapp开发的小程序和app的底部导航部分不是自己写模板代码绘制出来的,而是在pages.json中配置出来的,包括页面路径,图标和选中图标,字体颜色,文字和图标的间距等等,具体可以在官方文档查看具体的配置项,下面给出一段实例:
"tabBar": {
"color": "#636263",
"selectedColor": "#636263",
"spacing": "4px",
"list": [{
"pagePath": "pages/index/index",
"iconPath": "static/tabbar/home.png",
"selectedIconPath": "static/tabbar/home-fill.png",
"text": "首页"
},
{
"pagePath": "pages/list/list",
"iconPath": "static/tabbar/category.png",
"selectedIconPath": "static/tabbar/category-fill.png",
"text": "列表"
}
]}
顶部标题栏
顶部标题栏是在pages.json中的navigationBar相关样式进行设置,包含了标题文字,字体颜色,标题背景色。APP端支持配置左侧和右侧的图标按钮,在style下面的app-plus中进行配置即可:
"app-plus": {
"titleNView": {
"buttons": [
{
"float": "left",
"fontSrc": "static/iconfont.ttf",
"text": "\ue617"
},
{
"float": "right",
"fontSrc": "static/iconfont.ttf",
"text": "\ue665"
}
]
}
}
需要注意微信小程序不支持app-plus中的配置,在微信小程序中还是只显示标题文字,并不会显示左右的按钮。如果设计稿要求微信小程序的显示效果和APP一样,可以参考下面的做法:
首先要在pages.json中,把navigationStyle设置为custom,然后在index.vue中自己写一套顶部导航栏,并且需要加上if模板判断,只有在微信小程序中生效:
<!-- #ifdef MP-WEIXIN -->
<view class="wx-nav">
<uni-icons custom-prefix="iconfont" type="icon-fangdajing" size="20"></uni-icons>
<text>百年奥莱</text>
<uni-icons custom-prefix="iconfont" type="icon-xiaoxizhongxin" size="20"></uni-icons>
</view>
<!-- #endif -->
轮播组件
在HbuilderX中输入swiper会自动补齐相关代码模板,非常方便,代码示例如下:
<swiper :indicator-dots="true" :autoplay="true" :interval="3000" :duration="1000">
<swiper-item>
<view class="swiper-item">
<image src="../../static/image/swiper1.jpg" mode=""></image>
</view>
</swiper-item>
<swiper-item>
<view class="swiper-item">
<image src="../../static/image/swiper2.jpg" mode=""></image>
</view>
</swiper-item>
</swiper>
如果出现了图片内容显示不全,以及图片没有占满宽度的问题,可以尝试给image和swiper标签设置宽高,让他们的宽度为100%,高度为图片的完整高度(因为swiper组件有默认的150px高度,可能不满足图片尺寸,所以需要自己写样式):
swiper,
image {
width: 100%;
height: 400rpx;
}
如果轮播的不是一张张有着固定尺寸的图片,而是一个个页面(也就是希望左右滑动时能切换navbar页面),这个时候高度就有点麻烦,一种解决方案是使用uniapp的api去计算各个页面的高度,赋值给swiper组件,代码示例如下:
const view = uni.createSelectorQuery().select('#home') // 计算id为home的元素高度
view.boundingClientRect((data) => {
this.clientHeight = data.height
}).exec()
但是这种解决方案的问题是需要一直维护这片区域的高度,如果遇到懒加载,或者上拉刷新更多数据的情况,那么这个高度会变化。一个更加合适的方案是,用一个scroll-view去包裹这片区域,这个scroll-view的高度是固定的(比如屏幕高度-topbar高度),scroll-view里面放我们需要滚动的区域,里面的高度可能很高,但是这都不要紧,只要scroll-view的高度固定就可以了:
uni.getSystemInfo({
success: (res) => {
const windowHeight = res.windowHeight
const contentHeight = windowHeight - uni.upx2px(80)
this.contentHeight = contentHeight
}
})
// 这里的contentHeight就是swiper和scroll-view的高度
easycom组件
在传统的vue2项目中,想在页面中引入组件时,需要在script标签中,先import,然后在components里面定义,才可以在页面中使用组件。uniapp做了优化,只要满足一定的规范,就可以无需引入,直接在页面里调用组件标签就可以渲染组件了。
需要满足的规范也很简单,在项目目录下面新建components目录,在这个目录下面放入自己开发的组件,满足组件文件夹名字和组件名字同名即可,如图所示:
这里写一个小坑,在uniapp中,渲染组件必须是成对标签,不能使用单标签,否则在微信小程序中许多样式不会生效。
常用生命周期函数
这里只列举一些常用的,完整的生命周期参考官方文档
- onLoad 页面加载时触发,用onLoad可以接受路由传参;
- onReady 页面组件渲染完毕时触发,类似于vue2中的mounted生命周期函数;
- onShow 页面出现在屏幕上时触发,由于在h5或者小程序中,页面初始化后不会销毁,而是会挂载在后台,因此onLoad和onReady只会触发一次,而onShow可以实现每次进入页面时都能触发到,非常好用。
- mounted 组件渲染完成后触发,uniapp区分页面和组件的生命周期,onLoad或者onShow是页面生命周期,在组件中是不会触发的,必须写组件的生命周期;
- onBackPress 用户点击左上角的返回按钮时触发,常见的场景是比如在蒙层中,按返回按钮时希望能关闭蒙层而不是返回上一页,这时就需要这个生命周期函数去自定义返回按钮的行为;
数据缓存
类似于pc端的localStorage,把数据缓存到客户端本地。可以看官网提供的数据缓存API。推荐使用sync结尾的同步数据缓存API,同步的接口写起来更加自然。异步的接口需要在success中传递回调函数,写法上麻烦一些。
let keywords = uni.getStorageSync('keywords') || []
uni.setStorageSync('keywords', keywords)
页面通讯
指的是不同页面之间分发和订阅事件,在vue项目中我会引入miqq组件进行通讯,而uniapp内部已经封装好了,详情可见页面通讯官方文档,这里给出最简单的示例代码:
uni.$emit('selectAddress', 1) // 在地址管理页面中选中地址
uni.$on('selectAddress', (index)=> console.log(index)) // 在结算页面得到选中的地址
路由跳转及传参
uniapp中的路由跳转非常方便,不需要去单独写一个路由文件,全部在pages.json中自动配置好了。路由函数中的url直接写文件路径即可,不过需要注意url不能写项目路径(比如@/pages/index),只能写相对路径(比如../search/search)。传参也只要直接在路径后面用=的方式连接参数即可。更多详见官方文档
- uni.navigateTo({url: ‘../search/search?id=1’}),最常用的路由跳转函数
- uni.redirectTo({url: ‘../search/search?id=1’}),这个方法会关闭当前页面,然后再跳转到目标页面,用这种方式不会出现后退的按钮
- uni.switchTab({url: ‘../shopcart/shopcart’}),这个函数可以切换tab,上面两个都不可以。
转发分享到第三方
使用官方提供的uni.share方法可以分享到其他平台,需要传provider,imageUrl,title等参数,详见官方文档,这里给出简单的代码示例:
uni.share({
provider: "qq",
type: 0,
title: "这是我分享的商品标题",
href: "http://192.168.31.95:8080/pages/detail/detail?id=8",
imageUrl:
"https://upload-images.jianshu.io/upload_images/5472529-3bd133bd4451e048.png?imageMogr2/auto-orient/strip|imageView2/2/w/1200/format/webp",
success: () => {
uni.showTabBar({
title: "分享成功",
});
},
});
使用第三方账号登录
比如使用qq或者微信账号登录,使用官方提供的uni.login方法即可,另外需要配合uni.getUserInfo()方法,获取到用户在该平台的信息(比如昵称,头像等),详见官方文档,这里给出简单的代码示例:
uni.login({
provider: 'qq',
success: (res) => {
// 最重要的就是这个openid,需要传递给后端
const openId = res.authResult.openId;
uni.getUserInfo({
provider: mode,
success: (userInfo) => {
console.log(userInfo);
},
});
console.log(res);
},
});