手把手,从无到有精通小程序开发系列一(基本框架、生命周期)

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

小程序入门

  • 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
  • 打开微信开发者工具–新建小程序项目—输入相关信息,就创建了一个完整的小程序项目了
    手把手,从无到有精通小程序开发系列一(基本框架、生命周期)_第1张图片

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 或者 false
	4. 数组,需要包裹在方括号中 []
	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 发送给后台解码出 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()用于“注册程序”,在下一节详细介绍。

4.2.3 app.wxss 文件

app.wxss是小程序的全局样式文件,该文件可选,如果没有全局样式可以不写。

4.3 页面文件

在根目录下的pages文件夹内存放所有的页面文件,每个页面文件有一个二级目录
手把手,从无到有精通小程序开发系列一(基本框架、生命周期)_第2张图片
上图中有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'
  }
})

页面生命周期

手把手,从无到有精通小程序开发系列一(基本框架、生命周期)_第3张图片

5.2 视图层

5.2.1 WXHL

WXML(WeiXin Markup Language)是框架设计的一套标签语言,结合基础组件、事件系统,可以构建出页面的结构。

数据绑定data


 {{message}} 
// page.js
Page({
  data: {
    message: 'Hello MINA!'
  }
})

控制属性绑定if


 {{message}} 
 WEBVIEW 
 APP 
 MINA 
// page.js
Page({
  data: {
    condition: false
    view: 'MINA'
  }
})

列表渲染for

简单的渲染:


 {{item}} 
// page.js
Page({
  data: {
    array: [1, 2, 3, 4, 5]
  }
})

for列表渲染实战使用:

 
	{{item}}

事件绑定

  1. 微信官方对于事件的定义为:
  • 事件是视图层到逻辑层的通讯方式。
  • 事件可以将用户的行为反馈到逻辑层进行处理。
  • 事件可以绑定在组件上,当达到触发事件,就会执行逻辑层中对应的事件处理函数。
  • 事件对象可以携带额外信息,如 id, dataset, touches。
  1. 我们一起来看一下事件绑定的例子:
 Click me! 

在相应的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。


  outer view
  
    middle view
    
      inner view
    
  

  1. 事件的捕获阶段

自基础库版本 1.5.0 起,触摸类事件支持捕获阶段。捕获阶段位于冒泡阶段之前,且在捕获阶段中,事件到达节点的顺序与冒泡阶段恰好相反。需要在捕获阶段监听事件时,可以采用capture-bind、capture-catch关键字,后者将中断捕获阶段和取消冒泡阶段。

在下面的代码中,点击 inner view 会先后调用handleTap2、handleTap4、handleTap3、handleTap1。


  outer view
  
    inner 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




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)}} 

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

你可能感兴趣的:(小程序,前端架构)