微信小程序开发小记
目录结构
根目录生成:项目配置文件project.config.json。setting属性下包含:
配置层
小程序包含一个描述整体程序的 app 和多个描述各自页面的 page。
- app有 app.js / app.json / app.wxss 文件。
- 小程序页面有 js/wxml/json/wxss 文件。
app.json:文件用来对微信小程序进行全局配置,决定页面文件的路径、窗口表现、设置网络超时时间、设置多 tab 等。
(pages, window, tabBar, networkTimeout)
普通json:页面的配置只能设置 app.json 中部分 window 配置项的内容,页面中配置项会覆盖 app.json 的 window 中相同的配置项。
逻辑层
小程序框架的逻辑层并非运行在浏览器中,因此 JavaScript 在 web 中一些能力都无法使用,如 window,document 等。
app.js1
2
3
4
5
6
7
8
9
10
11
12
13
14
15App({
app.js: App({onLaunch(options) {
// Do something initial when launch.
},
onShow(options) {
// Do something when show.
},
onHide() {
// Do something when hide.
},
onError(msg) {
console.log(msg)
},
globalData: 'I am global data'
})
对于小程序,可以在 App 的 onLaunch 和 onShow,或wx.getLaunchOptionsSync 中获取场景值。
wx.getLaunchOptionsSync(path, scene, query, shareTicker, refererInfo) 获取小程序启动时的参数。
普通js1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52// index.js
Page({
data: {
text: 'This is page data.'
},
onLoad(options) {
// Do some initialize when page load.
},
onReady() {
// Do something when page ready.
},
onShow() {
// Do something when page show.
},
onHide() {
// Do something when page hide.
},
onUnload() {
// Do something when page close.
},
onPullDownRefresh() {
// Do something when pull down.
},
onReachBottom() {
// Do something when page reach bottom.
},
onShareAppMessage() {
// return custom share data when user share.
},
onPageScroll() {
// Do something when page scroll
},
onResize() {
// Do something when page resize
},
onTabItemTap(item) {
console.log(item.index)
console.log(item.pagePath)
console.log(item.text)
},
// Event handler.
viewTap() {
this.setData({
text: 'Set some data for updating view.'
}, function () {
// this is setData callback
})
},
customData: {
hi: 'MINA'
}
})
生命周期:
onLoad() 页面加载时触发,只会调用一次,可获取当前页面路径中的参数。
onShow() 页面显示/切入前台时触发,一般用来发送数据请求;
onReady() 页面初次渲染完成时触发, 只会调用一次,代表页面已可和视图层进行交互。
onHide() 页面隐藏/切入后台时触发, 如底部 tab 切换到其他页面或小程序切入后台等。
onUnload() 页面卸载时触发,如redirectTo或navigateBack到其他页面时。
页面路由
Tab 切换:页面全部出栈,只留下新的 Tab 页面
初始化:新页面入栈
打开新页面:新页面入栈
页面重定向:当前页面出栈,新页面入栈
页面返回:页面不断出栈,直到目标返回页
getCurrentPages() 函数用于获取当前页面栈的实例,以数组形式按栈的顺序给出,第一个元素为首页,最后一个元素为当前页面。
navigateTo, redirectTo 只能打开非 tabBar 页面。
switchTab 只能打开 tabBar 页面。
reLaunch 可以打开任意页面。
页面底部的 tabBar 由页面决定,即只要是定义为 tabBar 的页面,底部都有 tabBar。
调用页面路由带的参数可以在目标页面的onLoad中获取
wx.navigateTo 或使用组件 <navigator open-type="navigateTo"/>
url: 类型是String 跳转非 tabBar 的页面的路径 , 路径后可以带参数。参数与路径之间使用?分隔,参数键与参数值用=相连,不同参数用&分隔;如 ‘path?key=value&key2=value2’
success: 类型Function 接口调用成功的回调函数
fail: 类型Function 接口调用失败的回调函数
complete: 类型Function 接口调用结束的回调函数(调用成功、失败都会执行)
1 | wx.navigateTo({ |
模块化
使用 require(path) 将公共代码引入
module.exports 导出
且有模板:1
2
3
4
5
6<template name="head">
<view class='head-container'>
{{ info }}
<image src='../../images/icons/back.png' class='back-icon' wx:if="{{hasBack}}" bindtap='toBack'></image>
</view>
</template>
使用模板:1
2
3<import src="../../components/head.wxml"/>
<template is="head" data="{{info:'灯光设置', hasBack: true}}"/>
C import B,B import A,在C中可以使用B定义的template,在B中可以使用A定义的template,但是C不能使用A定义的template。
include 可以将目标文件除了 <template/>
<wxs/>
外的整个代码引入,相当于是拷贝到 include 位置1
2
3
4<!-- index.wxml -->
<include src="header.wxml" />
<view>body</view>
<include src="footer.wxml" />
wxs:(像computer方法)
是小程序的一套脚本语言,结合 WXML,可以构建出页面的结构。1
2
3
4
5
6
7
8
9
10
11
12
13<wxs module="m1">
var getMax = function(array) {
var max = undefined;
for (var i = 0; i < array.length; ++i) {
max = max === undefined ? array[i] : (max >= array[i] ? max : array[i]);
}
return max;
}
module.exports.getMax = getMax;
</wxs>
<!-- 调用 wxs 里面的 getMax 函数,参数为 page.js 里面的 array -->
<view>{{m1.getMax(array)}}</view>
在.wxs模块中引用其他 wxs 文件模块,可以使用 require 函数。
- 只能引用 .wxs 文件模块,且必须使用相对路径。
- wxs 模块均为单例,wxs 模块在第一次被引用时,会自动初始化为单例对象。多个页面,多个地方,多次引用,使用的都是同一个 wxs 模块对象。
- 如果一个 wxs 模块在定义之后,一直没有被引用,则该模块不会被解析与运行。
存储与请求
1 | wx.setStorageSync('key', 'value') //同步 |
1 | wx.request({ |
如何封装数据请求:
在根目录下创建utils目录及api.js文件和apiConfig.js文件;
在apiConfig.js 封装基础的get, post 和 put, upload等请求方法,设置请求体,带上token和异常处理等;
在api中引入apiConfig.js封装好的请求方法,根据页面数据请求的urls, 设置对应的方法并导出;
在具体的页面中导入。
小程序只可以跟指定的域名与进行网络通信。包括普通 HTTPS 请求(wx.request)、上传文件(wx.uploadFile)、下载文件(wx.downloadFile) 和 WebSocket 通信(wx.connectSocket)
- 域名只支持 https
视图wxss
和css一样,都是用来描述页面的样子;
WXSS 具有 CSS 大部分的特性,也做了一些扩充和修改;
WXSS新增了尺寸单位,WXSS 在底层支持新的尺寸单位 rpx;
WXSS 仅支持部分 CSS 选择器;
WXSS 提供全局样式与局部样式。
节点信息获取
节点信息查询 API 可以用于获取节点属性、样式、在界面上的位置等信息。
最常见的用法是使用这个接口来查询某个节点的当前位置,以及界面的滚动位置。
1 | const query = wx.createSelectorQuery() |
原理
小程序本质就是一个单页面应用,所有的页面渲染和事件处理,都在一个页面内进行,但又可以通过微信客户端调用原生的各种接口;
它的架构,是数据驱动的架构模式,它的UI和数据是分离的,所有的页面更新,都需要通过对数据的更改来实现;
它从技术讲和现有的前端开发差不多,采用JavaScript、WXML、WXSS三种技术进行开发;
功能可分为webview和appService两个部分;
webview用来展现UI,appService有来处理业务逻辑、数据及接口调用;
两个部分在两个进程中运行,通过系统层JSBridge实现通信,实现UI的渲染、事件的处理等。
架构:
微信小程序的框架包含两部分View视图层、App Service逻辑层,View层用来渲染页面结构,AppService层用来逻辑处理、数据请求、接口调用,它们在两个进程(两个Webview)里运行。
小程序启动时会从CDN下载小程序的完整包。
实现:
UI视图和逻辑处理是用多个webview实现的,逻辑处理的JS代码全部加载到一个Webview里面,称之为AppService,整个小程序只有一个,并且整个生命周期常驻内存,而所有的视图(wxml和wxss)都是单独的Webview来承载,称之为AppView。所以一个小程序打开至少就会有2个webview进程,正式因为每个视图都是一个独立的webview进程。
AppService:
可以理解AppService即一个简单的页面,主要功能是负责逻辑处理部分的执行,底层提供一个WAService.js的文件来提供各种api接口,主要是以下几个部分:
消息通信封装为WeixinJSBridge(开发环境为window.postMessage, IOS下为WKWebview的window.webkit.messageHandlers.invokeHandler.postMessage,android下用WeixinJSCore.invokeHandler)
1、日志组件Reporter封装
2、wx对象下面的api方法
3、全局的App,Page,getApp,getCurrentPages等全局方法
4、还有就是对AMD模块规范的实现
然后整个页面就是加载一堆JS文件,包括小程序配置config,上面的WAService.js(调试模式下有asdebug.js),剩下就是我们自己写的全部的js文件,一次性都加载。
上线后是应用部分会打包为2个文件,名称app-config.json和app-service.js,然后微信会打开webview去加载。线上部分应该是微信自身提供了相应的模板文件
AppView:
可以理解为h5的页面,提供UI渲染,底层提供一个WAWebview.js来提供底层的功能:
消息通信封装为WeixinJSBridge(开发环境为window.postMessage, IOS下为WKWebview的window.webkit.messageHandlers.invokeHandler.postMessage,android下用WeixinJSCore.invokeHandler)
2、日志组件Reporter封装
3、wx对象下的api,这里的api跟WAService里的还不太一样,有几个跟那边功能差不多,但是大部分都是处理UI显示相关的方法
4、小程序组件实现和注册
5、VirtualDOM,Diff和Render UI实现
6、页面事件触发
通信:
使用消息publish和subscribe机制实现两个Webview之间的通信,实现方式就是统一封装一个WeixinJSBridge对象,而不同的环境封装的接口不一样。
web-view页面分享
1 | <web-view src="https://mp.weixin.qq.com/" bindmessage"bindGetMsg"></web-view> |