下一篇:手把手,从无到有精通小程序开发系列二(分包、自定义组件)
微信面临的问题是如何设计一个比较好的系统,使得所有开发者在微信中都能获得比较好的体验。这个问题是之前的 JS-SDK 所处理不了的,需要一个全新的系统来完成,它需要使得所有的开发者都能做到:
快速的加载
更强大的能力
原生的体验
易用且安全的微信数据开放
高效和简单的开发
这就是小程序的由来
网页开发渲染线程和脚本线程是互斥的,这也是为什么长时间的脚本运行可能会导致页面失去响应,而在小程序中,二者是分开的,分别运行在不同的线程中。网页开发者可以使用到各种浏览器暴露出来的 DOM API,进行 DOM 选中和操作。
而如上文所述,小程序的逻辑层和渲染层是分开的,逻辑层运行在 JSCore 中,并没有一个完整浏览器对象,因而缺少相关的DOM API和BOM API。
这一区别导致了前端开发非常熟悉的一些库,例如 jQuery、 Zepto 等,在小程序中是无法运行的。同时 JSCore 的环境同 NodeJS 环境也是不尽相同,所以一些 NPM 的包在小程序中也是无法运行的。
表1-1 小程序的运行环境
运行环境 | 逻辑层 | 渲染层 |
---|---|---|
iOS | JavaScriptCore | WKWebView |
安卓 | V8 | chromium定制内核 |
小程序开发者工具 | NWJS | Chrome WebView |
小程序目录结构主要包括项目配置文件、主体文件、页面文件和其他文件。
每个小程序新建时自动生成一个项目配置文件project.config.json, 位于根目录下,用于定义小程序项目名称、AppID等内容。
{
"description": "项目配置文件",
"packOptions": {
"ignore": []
},
"setting": {
"urlCheck": true,
"es6": true,
"postcss": true,
"preloadBackgroundData": false,
"minified": true,
"newFeature": true,
"autoAudits": false,
"coverView": true,
"showShadowRootInWxmlPanel": true,
"scopeDataCheck": false
},
"compileType": "miniprogram",
"libVersion": "2.0.4",
"appid": "wx*******db370c43d",
"projectname": "smapp",
"debugOptions": {
"hidedInDevtools": []
},
"isGameTourist": false,
"simulatorType": "wechat",
"simulatorPluginLibVersion": {},
"condition": {
"search": {
"current": -1,
"list": []
},
"conversation": {
"current": -1,
"list": []
},
"game": {
"currentL": -1,
"list": []
},
"miniprogram": {
"current": -1,
"list": []
}
}
}
主体文件也位于根目录下,名称均为app:
在根目录下可以找到 app.json 文件,双击打开,代码如下:
{
"pages":[
"pages/index/index",
"pages/logs/logs"
],
"window":{
"backgroundTextStyle":"light",
"navigationBarBackgroundColor": "#fff",
"navigationBarTitleText": "WeChat",
"navigationBarTextStyle":"black"
}
}
上面代码中,app.json 文件配置了全局等pages和window属性,除此之外,app.json还可以配置tabBar、newworkTimeout及debug属性。
JSON文件注意事项:
1. 数字,包含浮点数和整数
2. 字符串,需要包裹在双引号中
3. Bool值,true 或者 false
4. 数组,需要包裹在方括号中 []
5. 对象,需要包裹在大括号中 {}
6. Null
其他任何格式都会触发报错
app.js是小程序全局逻辑文件
//app.js
App({
onLaunch: function () {
// 展示本地存储能力
var logs = wx.getStorageSync('logs') || []
logs.unshift(Date.now())
wx.setStorageSync('logs', logs)
// 登录
wx.login({
success: res => {
// 发送 res.code 到后台换取 openId, sessionKey, unionId
}
})
// 获取用户信息
wx.getSetting({
success: res => {
if (res.authSetting['scope.userInfo']) {
// 已经授权,可以直接调用 getUserInfo 获取头像昵称,不会弹框
wx.getUserInfo({
success: res => {
// 可以将 res 发送给后台解码出 unionId
this.globalData.userInfo = res.userInfo
// 由于 getUserInfo 是网络请求,可能会在 Page.onLoad 之后才返回
// 所以此处加入 callback 以防止这种情况
if (this.userInfoReadyCallback) {
this.userInfoReadyCallback(res)
}
}
})
}
}
})
},
globalData: {
userInfo: null
}
})
省略掉app.js中的函数内容将得到以下代码框架:
App({
onLaunch: function () {},
globalData: {}
})
可见,所有内容写在App()函数内部,并且彼此之间用逗号隔开,App()用于“注册程序”,在下一节详细介绍。
app.wxss是小程序的全局样式文件,该文件可选,如果没有全局样式可以不写。
在根目录下的pages文件夹内存放所有的页面文件,每个页面文件有一个二级目录
上图中有index和logs两个页面,每个独立页面基本上有四种文件构成:
按照官网的介绍:
微信客户端给小程序所提供的环境为宿主环境。小程序借助宿主环境提供的能力,可以完成许多普通网页无法完成的功能。
小程序的运行环境分成渲染层和逻辑层,其中 WXML 模板和 WXSS 样式工作在渲染层,JS 脚本工作在逻辑层。
小程序的渲染层和逻辑层分别由2个线程管理:渲染层的界面使用了WebView 进行渲染;逻辑层采用JsCore线程运行JS脚本。一个小程序存在多个界面,所以渲染层存在多个WebView线程,这两个线程的通信会经由微信客户端(下文中也会采用Native来代指微信客户端)做中转,逻辑层发送网络请求也经由Native转发,小程序的通信模型下图所示。
逻辑层又称为App service, 由js编写和实现,开发者写的所有代码最后被打包成一份js,并在小程序启动时运行,知道小程序被销毁。
每个小程序都需要在 app.js 中调用 App 方法注册小程序实例,绑定生命周期回调函数、错误监听和页面不存在监听函数等
// app.js
App({
onLaunch (options) {
// 当小程序初始化触发.
},
onShow (options) {
// 当小程序启动或者从后台进入前台时触发.
},
onHide () {
// 当小程序从前台进入后台隐藏时触发.
},
onError (msg) {
console.log(msg)
},
globalData: {
userInfo: null
}
})
备注:
在小程序其他js文件中均可以使用getApp()方法获取小程序实例
var app = getApp()
console.log(app.globalData.userInfo)
属性 | 描述 |
---|---|
onLaunch | 当小程序初始化触发 |
onShow | 当小程序启动或者从后台进入前台时触发 |
onHide | 当小程序从前台进入后台隐藏时触发 |
对于小程序中的每个页面,都需要在页面对应的 js 文件中进行注册,指定页面的初始数据、生命周期回调、事件处理函数等。
使用 Page 构造器注册页面
简单的页面可以使用 Page() 进行构造。
//index.js
Page({
data: {
text: "This is page data."
},
onLoad: function(options) {
// 页面创建时执行
},
onShow: function() {
// 页面出现在前台时执行
},
onReady: function() {
// 页面首次渲染完毕时执行
},
onHide: function() {
// 页面从前台变为后台时执行
},
onUnload: function() {
// 页面销毁时执行
},
onPullDownRefresh: function() {
// 触发下拉刷新时执行
},
onReachBottom: function() {
// 页面触底时执行
},
onShareAppMessage: function () {
// 页面被用户分享时执行
},
onPageScroll: function() {
// 页面滚动时执行
},
onResize: function() {
// 页面尺寸变化时执行
},
onTabItemTap(item) {
// tab 点击时执行
console.log(item.index)
console.log(item.pagePath)
console.log(item.text)
},
// 事件响应函数
viewTap: function() {
this.setData({
text: 'Set some data for updating view.'
}, function() {
// this is setData callback
})
},
// 自由数据
customData: {
hi: 'MINA'
}
})
WXML(WeiXin Markup Language)是框架设计的一套标签语言,结合基础组件、事件系统,可以构建出页面的结构。
{{message}}
// page.js
Page({
data: {
message: 'Hello MINA!'
}
})
{{message}}
WEBVIEW
APP
MINA
// page.js
Page({
data: {
condition: false
view: 'MINA'
}
})
简单的渲染:
{{item}}
// page.js
Page({
data: {
array: [1, 2, 3, 4, 5]
}
})
for列表渲染实战使用:
{{item}}
Click me!
在相应的Page定义中写上相应的事件处理函数,参数是e。
Page({
tapName: function(e) {
var hi = e.currentTarget.dataset.hi // WeChat
}
})
通过dataset获取参数值,是小程序事件传值的方式。
例如在下边这个例子中,点击 inner view 会先后调用handleTap3和handleTap2(因为tap事件会冒泡到 middle view,而 middle view 阻止了 tap 事件冒泡,不再向父节点传递),点击 middle view 会触发handleTap2,点击 outer view 会触发handleTap1。
outer view
middle view
inner view
自基础库版本 1.5.0 起,触摸类事件支持捕获阶段。捕获阶段位于冒泡阶段之前,且在捕获阶段中,事件到达节点的顺序与冒泡阶段恰好相反。需要在捕获阶段监听事件时,可以采用capture-bind、capture-catch关键字,后者将中断捕获阶段和取消冒泡阶段。
在下面的代码中,点击 inner view 会先后调用handleTap2、handleTap4、handleTap3、handleTap1。
outer view
inner view
WXSS 具有 CSS 大部分特性。同时为了更适合开发微信小程序,WXSS 对 CSS 进行了扩充以及修改。
与 CSS 相比,WXSS 扩展的特性有:
尺寸单位
rpx(responsive pixel): 可以根据屏幕宽度进行自适应。规定屏幕宽为750rpx。如在 iPhone6 上,屏幕宽度为375px,共有750个物理像素,则750rpx = 375px = 750物理像素,1rpx = 0.5px = 1物理像素。
WXS(WeiXin Script)是小程序的一套脚本语言,结合 WXML,可以构建出页面的结构。
建议把wxs文件用于对数据的处理,类似vue中的filter
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;
{{m1.getMax(array)}}
下一篇:手把手,从无到有精通小程序开发系列二(分包、自定义组件)