前言
最近要教会公司后端写微信小程序,所以萌生了写一篇入门手册教给后端宝宝们食用的想法,接下来我们来从几个方面入手。
什么是微信小程序
微信小程序是运行在微信中的web程序,代码是部署在微信云服务器上的。
优势
- 无需下载安装,无需注册,用完即走,不会过多地占用手机内存
- 小程序可以跨平台(苹果或安卓系统)运行,其开发门槛和成本比APP开发要低
- 打开速度比H5(HTML5)要快,接近于原生App的体验
- 安卓手机可以直接添加小程序至手机桌面,打开方式和App一样方便
- 可以借用微信的用户群体,方便营销推广。
劣势
- 小程序目前无法直接分享至朋友圈,只能分享给微信好友或微信群
- 小程序的二维码不支持长按识别,只能通过微信扫一扫才能打开
- 小程序没有push功能,不能给用户推送消息和个人相关的通知消息
- 小程序没有用户体系,用户不需要注册,因此用户用完即走,很难形成用户体系
怎么开发一款小程序
我的理解是开发小程序要分为4大步骤:注册、信息完善、开发小程序、审核和发布小程序
- 注册:在微信公众平台注册小程序,完成注册后可以同步进行信息完善和开发,注意APPID,这个要配置在小程序开发工具中,记得保存下来。
- 信息完善:在注册完小程序后填写小程序基本信息,包括名称、头像、介绍及服务范围等。
- 开发小程序:工欲善其事必先利其器,先配置开发者工具,在进行小程序开发。
- 审核和发布小程序:完成小程序开发后,提交代码至微信团队审核,审核通过后即可发布
开发小程序工具配置
注册成功后,可登录,然后获取 APPID
小程序开发必须要在专门的开发者工具进行开发,开发者工具下载地址 下载完成之后新建小程序,输入项目名称、目录、AppID等,还可以选择微信提供的一些模板,快速生成一个功能相对齐全的小程序。
这里有两种开发模式,一种是云服务,我的理解是调用远程代码库的函数和存储实现一个小程序,另外一种不使用云服务,则是本地编写代码实现自己的小程序。
如下是现有项目进行改造,则在右上角的详情中修改成申请下来的APPID
配置完成后,即可进行开发,整个工具的分布如下
小程序调试工具介绍
小程序的调试工具类似浏览器的调试工具,分为以下几个功能模块:
Wxml:页面结构和结构对应的 wxss 属性Console:控制台,输出提示信息Sources:当前项目的脚本文件Network:观察和显示request和socket的请求情况Perfomance:性能分析Memory:内存AppData:当前小程序的具体数据Storage:显示当前项目使用wx.setStorage或者wx.setStorageSync存储的数据Security: 安全性Sensor:模拟地理位置和模拟移动设备表现,用于调试重力感应 APIMock:模拟接口Audits:体验评分检测Vulnerability:发现并修复小程序内的接口安全漏洞,提升小程序安全性
小程序框架介绍
微信团队为小程序提供的框架命名为 MINA 应用框架 ,通过封装微信客户端提供的文件系统、网络通信、任务管理、数据安全等基础功能,对上层提供一整套Javascript API,让开发者能够方便的使用微信提供的各种功能与能力。
小程序的运行环境分成渲染层和逻辑层,其中 WXML 模板和 WXSS 样式工作在渲染层,JS 脚本工作在逻辑层。
由2个线程管理:渲染层的界面使用了WebView 进行渲染;逻辑层采用JsCore线程运行JS 脚本。一个小程序存在多个界面,所以渲染层存在多个WebView线程,这两个线程的通信会经由微信客户端做中转,逻辑层发送网络请求也经由Native进行转发。
MINA框架支持mvvm模式,vue、React、Angular也是mvvm模式的支持者。
MVVM的核心是ViewModel层,负责转换Model层中的数据对象来让数据更容易管理和使用,向上与View视图层进行双向数据绑定,向下与Model层通过接口请求进行数据交互,起承上启下的作用
小程序文件介绍
小程序框架提供了自己的视图层描述语言 WXML 和 WXSS,以及 JavaScript,并在视图层与逻辑层间提供了数据传输和事件系统,让开发者能够专注于数据与逻辑。
注意
pages页面(小程序的每一个页面)由4个文件组成:
js: 页面逻辑,相当于控制层,也包括部分数据wxml:页面结构展示,相当于视图层(view)json:页面配置,配置一些页面展示的数据,充当部分的模型wxss:页面样式表
小程序页面生命周期
onLoad:页面创建时执行onShow:页面出现在前台时执行onReady:页面首次渲染完毕时执行onHide: 页面从前台变为后台时执行onUnload: 页面销毁时执行onPullDownRefresh: 触发下拉刷新时执行onReachBottom: 页面触底时执行onShareAppMessage: 页面被用户分享时执行onPageScroll: 页面滚动时执行onResize: 页面尺寸变化时执行onTabItemTap:tab 点击时执行
Page({
data: {
name:'木子呀'
},
onLoad() {
console.log('页面创建时执行');
},
onShow() {
console.log('页面出现在前台时执行');
},
onReady() {
console.log('页面首次渲染完毕时执行');
},
onHide() {
console.log('页面从前台变为后台时执行,也就是隐藏时执行');
},
onUnload() {
console.log('页面销毁时执行');
},
onPullDownRefresh() {
console.log('触发下拉刷新时执行');
},
onReachBottom() {
console.log('页面触底时执行');
},
onShareAppMessage() {
console.log('页面被用户分享时执行');
},
onPageScroll() {
console.log('页面滚动时执行');
},
onResize() {
console.log('页面尺寸变化时执行');
},
onTabItemTap() {
console.log('tab 点击时执行');
},
//这样定义的不会是mvvm响应的参数
no_mvvm_params:{
id:'00001'
},
getList(){
console.log('自定义事件,比如获取后台数据');
},
//...可以根据需求实现很多自定义事件。
})
小程序应用生命周期
onLaunch:监听小程序初始化onShow:监听小程序启动或切前台onHide:监听小程序切后台onError: 错误监听函数onPageNotFound: 页面不存在监听函数
App({
data: {
name:'木子呀'
},
onLaunch() {
console.log('监听小程序初始化');
},
onShow() {
console.log('监听小程序启动或切前台');
},
onHide() {
console.log('监听小程序切后台');
},
onError() {
console.log('错误监听函数');
},
onPageNotFound() {
console.log('页面不存在监听函数');
},
})
全局配置 app.json
app.json 是当前小程序的全局配置,包括了小程序的所有页面路径、界面表现、网络超时时间、底部 tab 等。普通快速启动项目里边的 app.json 配置
{
//路由
"pages": [
"pages/home/index",
],
//授权
"permission": {
"scope.userLocation": {
"desc": "需要获取您的地理位置,请确认授权"
},
},
//导航栏配置
"window": {
"navigationBarBackgroundColor": "#ffffff",
"navigationBarTextStyle": "black",
"navigationBarTitleText": "小程序"
"backgroundTextStyle":"light"
},
//超时时间
"networkTimeout": {
"request": 75000
},
//底部tabBar
"tabBar": {
"list": [
{ "pagePath": "pages/index/index", //跳转的路径
"text": "首页", //名称
"iconPath": "./tabs/tab_home_nor@3x.png", // 图标
"selectedIconPath": "./tabs/tab_home_fill@3x.png" //选中的图标
},
{
"pagePath": "pages/user/index",
"text": "我的",
"iconPath": "./tabs/tab_my_nor@3x.png",
"selectedIconPath": "./tabs/tab_my_fill@3x.png"
}
]
}
}
window导航栏配置
tabBar配置
小程序语法
- set参数
Page({
data: {
name:'木子呀'
},
setparams(){
this.setData({
name:'木子'
//names是在data中声明的参数
})
}
})
2.数据绑定
Page({
data: {
name:'木子呀'
},
})
index.wxml
<view> {{ name }} </view>
3.组件属性
Page({
data: {
name:'木子呀',
key:'001'
},
})
index.wxml
<view key={{key}}> {{ name }} </view>
4.bool 类型
<!--不要直接写 checked="false",其计算结果是一个字符串-->
<checkbox checked="{{false}}"> </checkbox>
5.运算
Page({
data: {
name:'木子呀'
age:10,
age_two:8
},
})
index.wxml
<!--三元运算-->
<view hidden="{{name === '木子呀' ? true : false}}"> Hidden </view>
<!--算数运算-->
<view> {{age + age_two}} </view>
<!--逻辑判断-->
<view wx:if="{{age > 5}}"> </view>
<!--字符串运算-->
<view> {{'hello' + name}} </view>
6.循环和if判断
Page({
data: {
array:[{message:'aaa'}]
},
})
index.wxml
<!--key可以提高渲染性能,但必须是唯一的,如果可变的列表涉及增删不能用index-->
<!--循环体内会默认抛出index和item-->
<view wx:for="{{array}}" wx:key="{{item.message}}"> {{index}}: {{item.message}} </view>
7.标签和事件以及参数传递
框架设计的一套标签语言,结合基础组件、事件系统,可以构建出页面的结构。
<!--视图容器-->
<view>这里是试图内容</view>
<!--文本-->
<text>这里面是文本</text>
<!--image图片-->
<image src="../../img.jpg"></image>
<!--输入框-->
<input value="{{name}}"></input>
<!--button按钮-->
<button></button>
<!--textarea长文本输入框-->
<textarea></textarea>
<!--picker下拉框-->
<picker></picker>
<!--通过bind指令实现事件绑定-->
<!--点击事件-->
<view bindtap='click'>这里是试图内容</view>
<!--输入事件-->
<view bindinput='click'>这里是试图内容</view>
<!--手指触摸动作开始-->
<view bindtouchstart='click'>这里是试图内容</view>
<!--手指触摸后移动-->
<view bindtouchmove='click'>这里是试图内容</view>
<!--绑定事件时不能带参数 不能带括号 ------以下为错误写法 -->
<view bindtap='click(100)'>这里是试图内容</view>
<!--绑定事件时传递参数 ------以下为正确写法 -->
<view bindtap='click' data-name='{{name}}'>这里是试图内容</view>
js
click(e){
//拿到的参数
console.log(e.target.dataset.name);
},
样式文件wxss
样式语言,具有css大部分的特性,wxss在css基础上做了一些扩充和修改。
新增尺寸单位rpx,可以根据屏幕宽度进行自适应。规定屏幕宽为750rpx。如在 iPhone6 上,屏幕宽度为375px,共有750个物理像素,则750rpx = 375px = 750物理像素,1rpx = 0.5px = 1物理像素。
子组件配置,以及触发父子组件事件
payPage.wxml
<view>
<payAccount id="childPayAccount" bindpayAccount="payAccount" ></payAccount>
<view bindtap="handerClickChild">点我调用子组件<view>
<view>
payPage.json
{
"usingComponents": {
"payAccount":"/components/payAccount/payAccount",
}
}
payPage.js
//父组件声明的方法
payAccount(e){
console.log( e.detail);
}
//父组件调用子组件
handerClickChild(e){
//通过id获取子组件
const child = this.selectComponent("#childPayAccount")
//父组件调用子组件
child.childMethod()
}
<!--子组件-->
payAccount.wxml
<view bindtap="handerClick">payAccount子组件<view>
payAccount.js
//子组件调用父组件
handerClick(){
this.triggerEvent("payAccount",'点击了执行emit');
}
//子组件的方法
childMethod(){
console.log('调用子组件的方法');
}
小程序路由跳转的几种方式以及传参
//保留当前页面,跳转到应用内的某个页面
wx.navigateTo({ url: '/pages/detail/detail?id=1' })
//关闭当前页面,跳转到应用内的某个页面。但是不允许跳转到 tabbar 页面
wx.redirectTo({ url: `/pages/detail/detail`, })
//跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面(不可以携带参数)
wx.switchTab({ url: `/pages/detail/detail`, })
//关闭当前页面, delta值为1 ,表示跳转上一页,2表示跳两级 ,可通过 getCurrentPages() 获取当前的页面栈,决定需要返回几层.
wx.navigateBack({ delta:1 })
//关闭所有页面,打开到应用内的某个页面
wx.reLaunch({ url: '/pages/detail/detail' })
//跳转路由传参
let name = '木子'
wx.navigateTo({
url: '/pages/demo/demo?name='+name
})
demo.js
onLoad(data) {
console.log(data.name);
},
小程序获取授权
通过微信官方提供的api可以获取用户的信息,在获取之前需要用户授权。
// 获取用户信息授权
wx.getUserProfile({
desc: '用于完善会员资料', // 必填,声明获取用户个人信息后的用途
success: (res) => {
console.log(res.userInfo);
// 处理用户信息
},
fail: (err) => {
console.log('用户信息授权失败', err);
}
});
// 获取手机号码授权
wx.getPhoneNumber({
success: (res) => {
// 获取解密后的手机号
const decryptedData = wx.decryptData(res.encryptedData, res.iv);
console.log(decryptedData.phoneNumber);
// 处理手机号
},
fail: (err) => {
console.log('手机号码授权失败', err);
}
});
小程序登录
参考小程序登录方案官方答案,登录流程如下
小程序发布
开发过程中,我们可以通过微信开发者工具的『预览』和『真机调试』功能进行调试。 没问题后通过微信开发者工具的『上传』按钮进行代码上传。
上传成功后会出现上传成功的提示,还会出现如下的代码质量提示
有时还会出现如下上传失败的提示
这时就需要进行分包优化,参考这里,分包优化后重新进行上传。
上传成功后,登录『微信公众平台』查看『版本管理』,就可以看到我们刚才上传的版本代码