下一篇:手把手,从无到有精通小程序开发系列二(分包、自定义组件)
小程序入门
- 1 小程序的由来
- 2 小程序与普通网页开发的区别
- 3 开始
- 4 小程序目录结构
-
- 4.1 配置文件
- 4.2 主体文件
-
- 4.2.1 app.json文件
- 4.2.2 app.js 文件
- 4.2.3 app.wxss 文件
- 4.3 页面文件
- 5 小程序框架
-
- 5.1 逻辑层
-
- 5.1.1 App()注册程序
-
- getApp()方法:
- 小程序生命周期
- 5.1.2 Page()注册页面
-
- 页面生命周期
- 5.2 视图层
-
- 5.2.1 WXHL
-
- 数据绑定data
- 控制属性绑定if
- 列表渲染for
- 事件绑定
- 5.2.2 WXSS
- 5.2.3 WXS
1 小程序的由来
微信面临的问题是如何设计一个比较好的系统,使得所有开发者在微信中都能获得比较好的体验。这个问题是之前的 JS-SDK 所处理不了的,需要一个全新的系统来完成,它需要使得所有的开发者都能做到:
-
快速的加载
-
更强大的能力
-
原生的体验
-
易用且安全的微信数据开放
-
高效和简单的开发
这就是小程序的由来
2 小程序与普通网页开发的区别
网页开发渲染线程和脚本线程是互斥的,这也是为什么长时间的脚本运行可能会导致页面失去响应,而在小程序中,二者是分开的,分别运行在不同的线程中。网页开发者可以使用到各种浏览器暴露出来的 DOM API,进行 DOM 选中和操作。
而如上文所述,小程序的逻辑层和渲染层是分开的,逻辑层运行在 JSCore 中,并没有一个完整浏览器对象,因而缺少相关的DOM API和BOM API。
这一区别导致了前端开发非常熟悉的一些库,例如 jQuery、 Zepto 等,在小程序中是无法运行的。同时 JSCore 的环境同 NodeJS 环境也是不尽相同,所以一些 NPM 的包在小程序中也是无法运行的。
表1-1 小程序的运行环境
运行环境 | 逻辑层 | 渲染层 |
---|---|---|
iOS | JavaScriptCore | WKWebView |
安卓 | V8 | chromium定制内核 |
小程序开发者工具 | NWJS | Chrome WebView |
3 开始
- 如果你刚刚接触小程序,申请账号、安装开发者工具请参照官网的步骤进行申请账号
- 如果是公司的项目,直接使用公司已经申请好的appid
- 打开微信开发者工具–新建小程序项目—输入相关信息,就创建了一个完整的小程序项目了
4 小程序目录结构
小程序目录结构主要包括项目配置文件、主体文件、页面文件和其他文件。
4.1 配置文件
每个小程序新建时自动生成一个项目配置文件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": []}}
}
4.2 主体文件
主体文件也位于根目录下,名称均为app:
- app.json: 必填文件,用于描述小程序公共配置
- app,js: 必填文件,用于描述小程序整体逻辑
- app.wxss: 可填文件,公共样式类
4.2.1 app.json文件
在根目录下可以找到 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属性。
- pages:必填。对应的值是数组属性,记录小程序页面路径地址,第一个是默认初始页面
- window: 选填。对应对象属性,可以设置页面窗口表现,如导航栏颜色,标题等
- tabBar:选填。对应对象属性,用于多tab选项的小程序设置tab属性值
- newworkTimeout: 选填。对应对象属性,用于设置各类网络请求的超时时间
- debug:选填。对应布尔属性,用于开启debug模式,方便调试
JSON文件注意事项:
- JSON文件在小程序代码中扮演静态配置的作用,在小程序运行之前就决定了小程序一些表现,需要注意的是小程序是无法在运行过程中去动态更新JSON 配置文件从而发生对应的变化的。
- JSON文件都是被包裹在一个大括号中 {},通过key-value的方式来表达数据
- JSON的Key必须包裹在一个双引号中,在实践中,编写 JSON 的时候,忘了给 Key 值加双引号或者是把双引号写成单引号是常见错误
- JSON的值只能是以下几种数据格式:
1. 数字,包含浮点数和整数2. 字符串,需要包裹在双引号中3. Bool值,true 或者 false4. 数组,需要包裹在方括号中 []5. 对象,需要包裹在大括号中 {}6. Null其他任何格式都会触发报错
- JSON 文件中无法使用注释,试图添加注释将会引发报错
4.2.2 app.js 文件
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 发送给后台解码出 unionIdthis.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()用于“注册程序”,在下一节详细介绍。
4.2.3 app.wxss 文件
app.wxss是小程序的全局样式文件,该文件可选,如果没有全局样式可以不写。
4.3 页面文件
在根目录下的pages文件夹内存放所有的页面文件,每个页面文件有一个二级目录
上图中有index和logs两个页面,每个独立页面基本上有四种文件构成:
- wxml文件: 构建页面结构,类似html文件的作用
- wxss文件:设置页面样式,该文件只影响当前页面,并会覆盖app.wxss文件中冲突的内容
- js文件:设置页面逻辑代码
- json文件:重新设置app.json中window属性的内容,只影响当前页面。
5 小程序框架
按照官网的介绍:
微信客户端给小程序所提供的环境为宿主环境。小程序借助宿主环境提供的能力,可以完成许多普通网页无法完成的功能。
小程序的运行环境分成渲染层和逻辑层,其中 WXML 模板和 WXSS 样式工作在渲染层,JS 脚本工作在逻辑层。
小程序的渲染层和逻辑层分别由2个线程管理:渲染层的界面使用了WebView 进行渲染;逻辑层采用JsCore线程运行JS脚本。一个小程序存在多个界面,所以渲染层存在多个WebView线程,这两个线程的通信会经由微信客户端(下文中也会采用Native来代指微信客户端)做中转,逻辑层发送网络请求也经由Native转发,小程序的通信模型下图所示。
5.1 逻辑层
逻辑层又称为App service, 由js编写和实现,开发者写的所有代码最后被打包成一份js,并在小程序启动时运行,知道小程序被销毁。
- 新增App()和Page()方法,分别用于整个小程序和单个页面的注册
- 新增getApp()和getCurrentPages()方法,分别用于获取整个应用程序和当前页面实例。
- 提供微信原生api,用于获取微信用户信息、本地存储、扫一扫、微信支付、微信运动等功能。
- 每个页面拥有独立的作用域,并提供模块化功能。
5.1.1 App()注册程序
每个小程序都需要在 app.js 中调用 App 方法注册小程序实例,绑定生命周期回调函数、错误监听和页面不存在监听函数等
// app.js
App({onLaunch (options) {// 当小程序初始化触发.},onShow (options) {// 当小程序启动或者从后台进入前台时触发.},onHide () {// 当小程序从前台进入后台隐藏时触发.},onError (msg) {console.log(msg)},globalData: {userInfo: null}
})
备注:
- 小程序后台:单击小程序关闭按钮或者按设备的Home键离开微信时会进入后台运行状态。
- 小程序前台:当用户再次打开处于后台状态的小程序,会重新进入前台运行状态。
getApp()方法:
在小程序其他js文件中均可以使用getApp()方法获取小程序实例
var app = getApp()
console.log(app.globalData.userInfo)
小程序生命周期
属性 | 描述 |
---|---|
onLaunch | 当小程序初始化触发 |
onShow | 当小程序启动或者从后台进入前台时触发 |
onHide | 当小程序从前台进入后台隐藏时触发 |
5.1.2 Page()注册页面
对于小程序中的每个页面,都需要在页面对应的 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'}
})
页面生命周期
5.2 视图层
5.2.1 WXHL
WXML(WeiXin Markup Language)是框架设计的一套标签语言,结合基础组件、事件系统,可以构建出页面的结构。
数据绑定data
<!--wxml-->
<view> {{message}} </view>
// page.js
Page({data: {message: 'Hello MINA!'}
})
控制属性绑定if
<!--wxml-->
<view wx:if='{{condition}}'> {{message}} </view>
<view wx:if="{{view == 'WEBVIEW'}}"> WEBVIEW </view>
<view wx:elif="{{view == 'APP'}}"> APP </view>
<view wx:else="{{view == 'MINA'}}"> MINA </view>
// page.js
Page({data: {condition: falseview: 'MINA'}
})
列表渲染for
简单的渲染:
<!--wxml-->
<view wx:for="{{array}}"> {{item}} </view>
// page.js
Page({data: {array: [1, 2, 3, 4, 5]}
})
for列表渲染实战使用:
<view wx:for="{{array}}" wx:for-index="index"wx:for-item="item"wx:key="index"> {{item}}
</view>
事件绑定
- 微信官方对于事件的定义为:
- 事件是视图层到逻辑层的通讯方式。
- 事件可以将用户的行为反馈到逻辑层进行处理。
- 事件可以绑定在组件上,当达到触发事件,就会执行逻辑层中对应的事件处理函数。
- 事件对象可以携带额外信息,如 id, dataset, touches。
- 我们一起来看一下事件绑定的例子:
<view id="tapTest" data-hi="WeChat" bindtap="tapName"> Click me! </view>
在相应的Page定义中写上相应的事件处理函数,参数是e。
Page({tapName: function(e) {var hi = e.currentTarget.dataset.hi // WeChat}
})
通过dataset获取参数值,是小程序事件传值的方式。
- 事件分类
事件分为冒泡事件和非冒泡事件:
- 冒泡事件:当一个组件上的事件被触发后,该事件会向父节点传递。
- 非冒泡事件:当一个组件上的事件被触发后,该事件不会向父节点传递。
- 绑定事件分类
- bind事件:不会组织冒泡事件向上冒泡
- catch事件:会组织冒泡事件向上冒泡
例如在下边这个例子中,点击 inner view 会先后调用handleTap3和handleTap2(因为tap事件会冒泡到 middle view,而 middle view 阻止了 tap 事件冒泡,不再向父节点传递),点击 middle view 会触发handleTap2,点击 outer view 会触发handleTap1。
<view id="outer" bindtap="handleTap1">outer view<view id="middle" catchtap="handleTap2">middle view<view id="inner" bindtap="handleTap3">inner view</view></view>
</view>
- 事件的捕获阶段
自基础库版本 1.5.0 起,触摸类事件支持捕获阶段。捕获阶段位于冒泡阶段之前,且在捕获阶段中,事件到达节点的顺序与冒泡阶段恰好相反。需要在捕获阶段监听事件时,可以采用capture-bind、capture-catch关键字,后者将中断捕获阶段和取消冒泡阶段。
在下面的代码中,点击 inner view 会先后调用handleTap2、handleTap4、handleTap3、handleTap1。
<view id="outer" bind:touchstart="handleTap1" capture-bind:touchstart="handleTap2">outer view<view id="inner" bind:touchstart="handleTap3" capture-bind:touchstart="handleTap4">inner view</view>
</view>
5.2.2 WXSS
WXSS 具有 CSS 大部分特性。同时为了更适合开发微信小程序,WXSS 对 CSS 进行了扩充以及修改。
与 CSS 相比,WXSS 扩展的特性有:
- 尺寸单位
- 样式导入
尺寸单位
rpx(responsive pixel): 可以根据屏幕宽度进行自适应。规定屏幕宽为750rpx。如在 iPhone6 上,屏幕宽度为375px,共有750个物理像素,则750rpx = 375px = 750物理像素,1rpx = 0.5px = 1物理像素。
5.2.3 WXS
WXS(WeiXin Script)是小程序的一套脚本语言,结合 WXML,可以构建出页面的结构。
- WXS 不依赖于运行时的基础库版本,可以在所有版本的小程序中运行。
- WXS 与 JavaScript 是不同的语言,有自己的语法,并不和 JavaScript 一致。
- WXS 的运行环境和其他 JavaScript 代码是隔离的,WXS 中不能调用其他 JavaScript 文件中定义的函数,也不能调用小程序提供的API。
- WXS 函数不能作为组件的事件回调。
由于运行环境的差异,在 iOS 设备上小程序内的 WXS 会比 JavaScript 代码快 2 ~ 20 倍。在 android 设备上二者运行效率无差异。
建议把wxs文件用于对数据的处理,类似vue中的filter
<!--wxml-->
<!-- 下面的 getMax 函数,接受一个数组,且返回数组中最大的元素的值 -->
<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>
下一篇:手把手,从无到有精通小程序开发系列二(分包、自定义组件)