下一篇:手把手,从无到有精通小程序开发系列二(分包、自定义组件)

小程序入门

  • 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()注册程序
      • 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,并在小程序启动时运行,知道小程序被销毁。

  1. 新增App()和Page()方法,分别用于整个小程序和单个页面的注册
  2. 新增getApp()和getCurrentPages()方法,分别用于获取整个应用程序和当前页面实例。
  3. 提供微信原生api,用于获取微信用户信息、本地存储、扫一扫、微信支付、微信运动等功能。
  4. 每个页面拥有独立的作用域,并提供模块化功能。

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>

事件绑定

  1. 微信官方对于事件的定义为:
  • 事件是视图层到逻辑层的通讯方式。
  • 事件可以将用户的行为反馈到逻辑层进行处理。
  • 事件可以绑定在组件上,当达到触发事件,就会执行逻辑层中对应的事件处理函数。
  • 事件对象可以携带额外信息,如 id, dataset, touches。
  1. 我们一起来看一下事件绑定的例子:
<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获取参数值,是小程序事件传值的方式。

  1. 事件分类
    事件分为冒泡事件和非冒泡事件:
  • 冒泡事件:当一个组件上的事件被触发后,该事件会向父节点传递。
  • 非冒泡事件:当一个组件上的事件被触发后,该事件不会向父节点传递。
  1. 绑定事件分类
  • 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. 事件的捕获阶段

自基础库版本 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>

下一篇:手把手,从无到有精通小程序开发系列二(分包、自定义组件)