微信小程序学习笔记( 小程序框架 )

必看

这个只是我的学习过程算是日记形式吧,过程是按微信的官方文档的循序来,从 指南中的小程序框架 开始,指南中这一节之前还有页面配置,目录结构,还有很多介绍,没有写但是是非常重要的,一定要看,像指南后面的框架,组件,API更像是字典形式很细,所以 * 指南 * 这里很重要,建议学之前先学一点框架 vue,react 都可以,当然学框架之前也要了解一点 node ( 深入浅出nodejs 这本书挺好的的,至少了解一下前两章 Node简介和模块机制),还是要有一点基础,不然不好理解。

整体比较细,也没想着有人会看,大致和官方文档差不多,但是有自己的一些算是翻译吧(因为有一些不好理解),还有一些补充也不是很多,如果真的想学的话,官方文档就写的很详细了,从指南开始不要跳章节,还有要注重理解
 
 

逻辑层

注册小程序

每个小程序都需要在app.js中调用App方法注册小程序的示例,并绑定声明周期回调函数,错误监听和页面不存在监听函数等。
App中可以调用的详细参数:
1.onlaunch 初始化完成时触发,全局只触发一次,参数可以使用 wx.getLaunchOptionsSync获取(一个wx提供api获取小程序的一些的启动信息参数
2.onshow 小程序启动,或者从后台进入前台显示触发。 或者这个wx.onAppshow事件,也可以实现相同的而功能,监听小程序切前台事件
3.onHide 前台进入后台时触发, 或者wx.onAppHide来绑定监听
4.onError 发生脚本错误时触发,API调用报错的时候触发。或者wx.onError绑定监听
5.onPageNotFound 打开页面不存在时触发,或者wx.onPageNotFound绑定事件.

//App.js
	App({	
		onLaunch (optionc){
			// DO something initial when launch (初始化)
		},
		onShow(options){
			//Do some when show (页面展示触发)
		}onHide(){
			//Do something when hide(切换页面,前台进入后台时触发)
		}onError(msg){
			console.log(msg)
		},
		globalData : 'wang jie hello world'
	})

App.js里面的是全部页面共享的。开发者可以通过 getApp 方法获取到全局数据。

// xxx.js(需要调用全局变量的)
const apppInstance = get App()
console.lod(appInstance.globalData) //wang jie hello world


注册页面

 page构造器注册页面

对于小程序中的每个页面,都需要在页面对应的 js 文件中进行注册,也就是指定页面的初始数据,生命周期的回调,事件处理函数等等。

代码示例
//index.js (每一个页面都有,都可以进行各自页面的配置)
Page({
//初始化数据
 	 data: {
 	   text: "This is page data."
	  },
//生命周期 - 监听页面加载
	  onLoad: function(options) {
	    // Do some initialize when page load.
	  },
//生命周期 — 监听页面初次渲染完成
	  onReady: function() {
	    // Do something when page ready.
	  },
//生命周期 - 监听页面显示
 	 onShow: function() {
  	  // Do something when page show.
 	 },
//生命周期 - 监听页面隐藏
 	 onHide: function() {
 	   // Do something when page hide.
	  },
//生命周期 - 监听页面卸载
 	 onUnload: function() {
 	   // Do something when page close.
	  },
//监听用户下拉动作(刷新那里)
	  onPullDownRefresh: function() {
	    // Do something when pull down.
	  },
//页面上拉触底时间的处理函数
 	 onReachBottom: function() {
  	  // Do something when page reach bottom.
 	 },
//用户分享的的处理函数,支持 button 中的有一个分享组件 open-type = “share”,支持监听这个按钮
//只有定义了此事件处理函数,右上角才会显示“转发”按钮,否则显示当前页面未设置分享
	  onShareAppMessage: function () {
	    // return custom share data when user share.
	  },
//页面滚动触发时间的处理函数
 	 onPageScroll: function() {
  	  // Do something when page scroll
	  },
//页面尺寸改变时触发
 	 onResize: function() {
 	   // Do something when page resize
 	 },
//当前页面是 tab 页时,点击tab时触发
 	 onTabItemTap(item) {
 	   console.log(item.index) 			//当前Tabitem的序号,从0开始
	    console.log(item.pagePath) 		//当前Tab页面的路径
 	   console.log(item.text)			//当前tab上的按钮文字
 	 },
 	 
	  // Event handler.
	  //事件响应函数      或者      组合事件处理函数
	  
	  //.wxml文件中写
	  // click me 
	  //在 page 中自定义这个事件响应函数
	  viewTap: function() {//这是自定义函数
	    this.setData({
 	     text: 'Set some data for updating view.'
 	   }, function() {
 	     // this is setData callback
 	   })
	  },
	  //自由数据
	  customData: {
	    hi: 'MINA'
	  }
	})
ps:

setData 函数用于将数据从逻辑层发送到视图层(异步发送),同时改变对应的 this.data的值(同步)。
  1.支持改变数组的某一项或者对象的某个参数,并且数据可以不在 this.data中预先定义,
  2.但是必须是可支持json化的数据。
  3.如果数据是数祖或者对象的化,键值对的 key 可以是一个地址
     比如   ‘array[0].text’:‘changed data’ (数组) ‘object.text’: ‘changed data’(对象)


使用 Component 构造器构造页面

和 Page 构造器的区别:
    1.Pages 构造器只用于见到那的页面,对于复杂的页面, Page 构造器并不好用
    2.Component 构造器的方法需要放在 methods :{ } 里面

Component({

  behaviors: [],

  // 属性定义(详情参见下文)
  // 放的是组件的对外属性 
  properties: {
    myProperty: { // 属性名
      type: String,
      value: ''
    },
    
    myProperty2: String // 简化的定义方式
  },
  
  data: {}, // 私有数据(组件的内部属性),和 properties 一同用于组件的模板渲染

  lifetimes: {//	组件生命周期声明对象
    // 生命周期函数,可以为函数,或一个在methods段中定义的方法名
    attached: function () { }, //生命周期,在组件实例进入页面节点树时执行
    moved: function () { },    //生命周期,在组件实例被移动到节点树另一个位置执行
    detached: function () { }, //生命周期,在组件实例从节点树移除时执行
  },

  // 生命周期函数,可以为函数,或一个在methods段中定义的方法名
  attached: function () { }, // 此处attached的声明会被lifetimes字段中的声明覆盖
  
  
  ready: function() { }, //组件布局完成后执行


  pageLifetimes: {
    // 组件所在页面的生命周期函数
    show: function () { }, //页面显示
    hide: function () { }, //页面隐藏
    resize: function () { }, //页面尺寸改变
  },


// 里面放构造器的方法
  methods: {
    onMyButtonTap: function(){
      this.setData({
        // 更新属性和数据的方法与更新页面数据的方法类似
      })
    },
    // 内部方法建议以下划线开头
    _myPrivateMethod: function(){
      // 这里将 data.A[0].B 设为 'myPrivateData'
      this.setData({
        'A[0].B': 'myPrivateData'
      })
    },
    _propertyChange: function(newVal, oldVal) {

    }
  }

})
Component({
//有一个hasBehavior方法检测是否具有buhavior
  behaviors: [],//类似于继承,关联的组件可以共用一套生命周期函数
})

页面生命周期

渲染层和逻辑层
在这里插入图片描述

页面路由

小程序中所有页面的路由全部由框架进行管理。

页面栈

框架以栈的心事维护了当前的所有页面,当路由切换的时候,页面栈的表现。

路由方式 页面栈表现
初始化 新页面入栈
打开新页面 新页面入栈
页面重定向 当前页面出栈,新页面入栈
页面返回 页面不断出栈。知道返回到目标页
tab切换(就是页面全局配置的tabbar页) 页面全部出栈,只留下新的Tab页面
重加载 页面全部出栈,只留下新的页面

而 getCurrentPages() 函数获取当前也页面栈。(但是页面栈不能自己修改,因为路由全部由框架管理)

对于路由的触发方式,要么调用API 要么使用组件 navigator (这个之后再写)(组件的方法,路由不能跳转到 Tabbar 页面上)

Tips:
  • navigateTo, redirectTo 只能打开非 tabBar 页面。
  • switchTab 只能打开 tabBar 页面。
  • reLaunch 可以打开任意页面。
  • 页面底部的 tabBar 由页面决定,即只要是定义为 tabBar 的页面,底部都有 tabBar。
  • 调用页面路由带的参数可以在目标页面的onLoad中获取。

模块化

就是将一个公共的代码抽离出来成为一个单独的js文件,作为一个模块。
模块只有通过 module.exports 或者 exports 向外暴露接口才能调用

//common.js
function sayHello(name){
	console.log('Hello ${name}!')
}
function sayGoodbye(name){
	console.log('Goodbye ${name}')
}
//这两种方式暴露对象, 使用 require 引用这个模块的时候就可以获取到定义的方法
module.exports.sayHello = sayHello
exports.sayGoodbye = sayGoodbye
//使用 require 将公共代码引入
var common = require('common.js')
Page({
	helloMINA: function() {
		common.sayHello('MINA')
	},
	goodbyeMINA: function() {
		common.sayGoodbye('MINA')
	}
})

文件作用域

在 javascript 文件中声明的变量和函数旨在改文件中有效;不同的文件中可以生命相同名字的变量和函数,不会相互影响。
通过全局函数 getApp 可以获取全局的应用实例,如果需要全局的数据可以在 App() 中设置,如:

///app.js
App({
	globalData: 1
})
//a.js
var localValue = 'a'  //这个变量只能在 a.js 中引用 
var app = getApp()	  //获取到 app 全局对象
app.globalData++       //对这个 全局变量 更改
//b.js
var localValue = 'b'
console.log(getApp().globalData) // 如果 a.js 这个文件执行在 b.js 之前,则这里会显示2 

说明这种方法是直接调用全局变量,任何修改都会反应到全局变量上。


API

小程序开发框架提供了丰富的 微信原生 API ,可以方便的调起微信提供的能力,比如获取信息,本地存储,支付功能等等。
(具体所有的API,会学习一遍,会在写一个博客,还有组件那块也会再写一个博客)

通常,小程序 APP 有几个基本的类型:

事件监听API

约定以 on 开头的 API 用来监听某个事件是否被触发 ,比如 wx.onSoncketOpen ( 监听WebSocket 链接打开事件 ) ,wx.onCompassChange(监听罗盘数据变化事件,每5秒一次,接口调用后会自动开始监听,可使用 wx.stopCompass)
ps:webSocket 是 H5 开始提供的一种在单个 TCP 链接上进行全双工通讯的协议。
这种类型的API 接受一个回调函数作为参数。当事件触发时会调用这个回调函数并将相关数据以参数形式传入

wx.onCompassChange(function (res) {
	console.log(res.direction)
})

同步API

以 Sync 结尾的API都是同步API ,同步API 的执行结果可以通过函数返回值直接获取,如果执行出错会抛出异常。
ps:
     如 wx.setStorageSync (将数据存储在本地缓存中指定的 key 中,会覆盖掉原来该key对应的内容。除非用户主动删除或因存储空间原因被系统清理,否则数据都一直可用)

wx.setStorage({
	key: "key",
	data: "value"
})
//或者
try{
	wx.setStorageSync('key','value')
}catch (e) {}

     wx.getSyStemlnfoSync 获取系统信息。

wx.getSystemInfo({
  success (res) {
    console.log(res.model)			//设备型号
    console.log(res.pixelRatio)		//设备像素比
    console.log(res.windowWidth)	//可使用窗口宽度
    console.log(res.windowHeight)	//可使用窗口高度
    console.log(res.language)		//微信设置的语言
    console.log(res.version)		//微信版本号
    console.log(res.platform)		//客户端平台
  }
})

try {
  const res = wx.getSystemInfoSync()//上下两个API实现的是同一个功能
  console.log(res.model)
  ...
  ...
} catch (e) {
  // Do something when catch error
}

异步API

大多数 API 都是异步 API,这类API接口通常都接受一个 object 类型的参数,这个参数都支持按需指定以下字段来接收接口调用的结果:


参数 类型 说明
success function 接口调用成功的回调函数
fail function 接口调用失败的回调函数
complete function 接口调用结束的回调函数(失败,成功都会执行)

这三个函数的调用的时候会传入一个 Object 类型参数,里面有 errMsg(错误信息,调用成功返回的${apiName}:ok),erCode (错误代码,但是只有部分API支持),any。

异步 API 的执行结果需要通过 Object 类型的参数中传入的对应回调函数的获取。部分 API 也会有返回值,可以实现更丰富的功能。
比如 wx.request () , wx.login ()

	//发送请求
wx.request({
	url : 'test.php', //这个是必须有的东西
	data : {  //发给后台的参数
		x:'',
		y:''
	},
	haeder: { //请求头(请求的头部信息)
		'content-type' : 'application/json' 
	},
	method: 'POST'.   	//发送请求的方式(可以不需要这个,默认为GET)
	dataType: 'json' ,	//返回的数据格式(默认为json)
	success(res) {   	//接口调用成功的回调的函数
		console.log(res.data)
	},
	fail: function (err){ }, //请求失败执行的函数
	complete: function (){ } //请求完成后执行的函数
	})
    //调用这个接口获取登录凭证。通过凭证换取用户登录态信息,包括用户的唯一标识以及本次登陆的绘画密匙等
wx.login({
	success (res) {
			//res.code 是用户登录凭证(有效期5分钟)。
			//开发者需要在开发案和服务器后台调用 auth.code2Session, 使用 code 换取 openid 和 session_key
		if (res.code) {
			//发起网络请求
			wx.request({
				url: 'https://test.com/onLogin',
				data: {
					code: res.code
				}
			})
		} else {
			console.log('登陆失败!' + res.errMsg)
		}
	}
})



视图层 View

框架的视图层是由 WXML 与 WXSS 两个文件编写,由组件来进行展示。
将逻辑层的数据变成视图,同时将视图层的事件返回逻辑层。
WXML (WeiXin Markup language)用于描述页面的结构。
WXSS (WeiXin Style Sheet)用于描述页面的样式。
组件(Component)是视图的基本组成单元。

WXML

是框架设计的一套标签语言,结合基础组件,时间系统,就可以构建出页面的结构。
(这里很细具体的之后再写)先介绍一点具有哪些功能

数据绑定
	
	<view>{{message}}view>
	// page.js
	Page({
		data: {
			message : 'Hello MINA'
		}
	})
列表渲染
	
 	<view wx:for="{{array}}"> {{item}} view> 
	// page.js
	Page({
		data:{
			array: [1,2,3,4,5 ]
		}
	})
条件渲染
 
 <view wx:if="{{view == 'WEBVIEW'}}"> WEBVIEW view>
 <view WX:elif="{{view == 'APP'}}"> APP view>
 <view wx:elif="{{view == 'MINA'}}"> MINA view>
	//page.js
	Page({
		data: {
			view : 'MINA'
		}
	})
模板
 
	<template name="staffName">
		<view>
			FirstName: {{firstName}} , LastName: {{lastName}}
		view>
	template>		
	
	<template is="staffName" data="{{...staffA}}">template>
	<template is="staffName" data="{{...staffB}}">template>
	<template is="staffName" data="{{...staffC}}">template>
	Page({
		data: {
			staffA : {firstName: 'Hulk',lastName: 'Hu'},
			staffB : {firstName: 'Shang',lastName: 'You'},
			staffC : {firstName: 'Gideon',lastName: 'Lin'}
		}
	})

显示结果:
在这里插入图片描述

wxss

这是一套样式语言,类似于css(但是还有进行扩充和修改),用于描述wxml的组件样式.
扩展的特性有

  • 尺寸单位
  • 样式导入
尺寸单位
  • rpx: 可以根据屏幕宽度进行自适应.规定屏幕宽度为750px.(主要看视觉效果和实际情况)
样式导入
/** common.wxss **/
.small-p{
	padding:5px;
}
/**app.wxss**/
@import "common.wxss"
,middle-p{
	padding:15px;
}
内联样式

框架组件上支持使用 style , class 属性来控制组件的样式.

  • style:静态的样式同意写到 class 中 . style 接受动态的样式,在运行时会进行解析,避免将静态的样式写进style中,以免影响渲染速度.
  • class: 用于指定样式规则,其属性值是样式规则中类选择器名(样式类名)的集合,样式名不用带上 ( . )直接用空格分开.
选择器

选择器 样例 描述
.class .intro 选择所有拥有 class=“intro” 的组件
#id #firstname 选择拥有 id=“firstname” 的组件
element view 选择所有 view 组件
element,element view,checkbox 选择所有文档的 view 组件和所有的 checkbox 组件
::after view::after 在 view 组件后面插入内容
::before view::before 在 view 组件前面插入内容
全局样式与局部样式

定义在 app.wxss 中的样式是全局样式, 作用于每一个页面.在 page 的 wxss 文件中定义的样式为局部样式,只作为在对应的页面,并会覆盖 app.wxss 中 相同的选择器.


wxs部分省略


事件

解释一下事件

  • 事件是视图层到逻辑层的通讯方式.
  • 事件可以将用户的行为反馈到逻辑层进行处理.
  • 事件可以绑定在组件上,当达到触发事,就会执行逻辑层中对应的事件处理函数.
  • 事件对象可以携带额外的信息, 如 id , dataset , touches.
    ps:
         1.dataset 是H5 中的自定义属性,可以通过它来向事件传递你需要的属性。
         2.touches:是当前屏幕上所有触摸点的列表。
事件的使用方式
  • 在组件中绑定一个事件处理函数
    如 bindtap ,当用户点击给组件的时候会在该页面对应的page中找到相应的事件处理函数。
    Click me!
  • 在相应的 Page 定义中写上相应的事件处理函数, 参数是 event
	Page({	
		tapName: function (event){
			console.log(event)
		}
	})

这是 log 出来的信息(这个是事件对象,具体的下面有写)

{
  "type":"tap", //事件的类型
  "timeStamp":895, //事件生成的时间戳
  
  "target": { //触发源事件组件的属性
    "id": "tapTest",
    "dataset":  {		//自定义属性
      "hi":"WeChat"
    }
  },
  //事件绑定的当前组件的属性
  "currentTarget":  {
    "id": "tapTest",
    "dataset": {
      "hi":"WeChat"
    }
  },
  //自定义事件所携带的数据
  "detail": {
    "x":53,		//代表距离文档左上角的距离
    "y":14
  },
  //这是一个数组,里面每一个元素为一个 Touch 对象
  "touches":[{
    "identifier":0,			//触摸点的标识符
    "pageX":53,				//距离文档左上角的距离
    "pageY":14,				
    "clientX":53,			//距离页面可显示区域
    "clientY":14
  }],
  //数据格式同 touches。表示有变化的触摸点
  "changedTouches":[{
    "identifier":0,
    "pageX":53,
    "pageY":14,
    "clientX":53,
    "clientY":14
  }]
}
事件详解
事件分类

   1.冒泡事件:组件上的事件触发以后,该事件该向父节点传递。
   2.非冒泡事件:组件上的事件被触发后,该事件不会向父节点传递。

冒泡事件
类型 触发条件
touchstart 手指触摸动作开始
touchmove 手指触摸后移动
touchcancel 手指触摸动作打断,如来电提醒,弹窗
touchend 手指触摸动作结束
tap 手指触摸后立即离开
longpress 手指触摸超过350ms再离开,指定了事件回调函数,tap事件将不会触发
longtap 手指触摸后,超过350ms再离开(推荐使用longpress事件代替)
transitionend 在 WXSS transition 或者 wx.createAnimation 动画结束后触发
animationstart WXSS animation 动画开始时触发
animationiteration WXSS animation 一次迭代结束时触发
animationend WXSS animation 动画完成时触发(还在理解)

除了上表之外的其他组件自定义事件,没有特殊声明的话都是非冒泡事件,如 from 的 submit 事件,input的 input 事件,scroll-view 的 scroll 事件

事件绑定和冒泡

事件绑定的写法同组件的属性,以 key , value 的形式。

  • key是以 bind 或 catch 开头,然后跟上时间的类型,如bindtap , catchtouchstart。在非原生组件中 bind 和 catch 后面可以紧跟一个冒号,含义不变, 如 bind:tap , catch:touchstart.
  • value是一个字符串,需要在对应的 Page 中定义同名的函数。
  • 不然会报错。
    bind 事件绑定不会阻止事件冒泡事件向上冒泡, catch 事件绑定可以阻止冒泡事件向上冒泡。
事件捕获阶段

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

下面代码,点击 inner view 会先后调用 handleTap2 ,handleTop4,handleTop3 , handleTop1

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

将第一个 capture-bind 修改成 capture-catch, 点击 inner view ,将只会触发handleTap2.

<view id="outer" bind:touchstart="handleTap1" capture-catch:touchstart="handleTap2">
  outer view
  <view id="inner" bind:touchstart="handleTap3" capture-bind:touchstart="handleTap4">
    inner view
  view>
view>
事件对象

当组件出发事件时,逻辑层会绑定该事件的处理函数会收到一个事件对象。

BaseEvent 基础事件对象属性列表
属性 说明
type 事件类型
timeStamp 事件生成时的时间戳
target 触发事件的组件的一些属性值集合
currentTarget 当前组件的一个属性值的集合
mark 事件标记数据
CustomEvent 自定义事件对象属性列表(继承BaseEvent):
属性 说明
detail 额外的信息
TouchEvent触摸事件对象属性列表(继承BaseEvent):
属性 说明
touches 触摸事件,当前停留在屏幕中的触摸点信息的数组
changedTouches 触摸事件,当前变化的触摸点信息的数组
特殊事件: canves中的触摸事件不可冒泡,所以没有currentTarget

type: 代表事件的类型。
timeStamp : 页面打开到触发事件所经过的毫秒数。


target:触发事件的源组件。源组件

属性 说明
id 事件源组件的 id 值
dataset 事件源组件上面由 data- 开头的自定义属性组成的集合.(重要)

currentTarget

事件绑定当前组件。

属性 说明
id 当前组件 id
dataset 当前组件由 data- 开头的自定义属性组合成的集合

说明:target 和 currentTarget 可以参考上例中,点击 inner view 时, handleTap3 收到的事件对象 target 和 currentTarget 都是 inner,而 handleTap2 收到的事件对象 Target 就是 inner,currentTarget 就是 middle。


dataset

组件节点中可以附加一些自定义数据。 这样,在事件中可以获取这些自定义的节点数据,用于事件的逻辑处理。
在 WXML 中,这些自定义数据以 data- 开头

  • data-element-type , 最终会呈现为 event.currentTarget.dataset.elementType
  • data-elementType , 最终会呈现为 event.currentTarget.dataset.elementtype
    DataSet Test
Page({
  bindViewTap:function(event){
    event.currentTarget.dataset.alphaBeta === 1 // - 会转为驼峰写法
    //就是把 - 去掉,然后第一个字母要大写
    event.currentTarget.dataset.alphabeta === 2 // 大写会转为小写
    //没有 - 的话就全部用小写
  }
})
mark

可以使用 mark 来识别具体触发事件的 target0 节点(事件源节点)。此外,mark 还可以用于承载一些自定义数据(类似于 dataset )。
当事件触发时,事件冒泡路径上的所有 mark 会被合并, 并返回给事件回调函数。(即使事件不是冒泡事件,也会 mark)

<view mark:maWark="last" bindtap="binViewTap">
	<button mark:anotherMark="leaf" bindtap="bindButtonTap">按钮button>
view>

在上述 WXML 中,如果按钮被点击,将会触发 bindViewTap 和 bindButtonTap 两个事件,事件携带的 event.mark 将包含 myMark 和 anotherMark 两项

Page({
	bindViewTap: function(e){
		e.mark.myMark === "last" //true
		e.mark.anotherMark === "leaf" //true
	}
})

mark 和 dataset 很相似,主要区别在于: mark 会包含从触发事件的节点到根节点上左右的 Mark: 属性值;而 dataset 仅包含一个节点的 data- 属性值。

  • 如果存在同名的mark ,父节点的 mark 会被子节点覆盖。
  • 在自定义组件中接受事件时,mark 不包含自定义组件外的节点的 mark 。
  • 不同于 datatset ,节点的 mark 不会有 连字符和大小写的转换。
touches

touches是一个数组,每一个元素为一个 Touch 对象(canvas 触摸事件中携带的 touches 是 CanvasTouch数组)。表示当前停留在屏幕上的触摸点。

Touch 对象
属性 说明
identifier 触摸点的标识符
pageX,pageY 距离文档左上角的距离,文档的左上角为原点,横向为X轴,纵向为Y轴
clientX,clientY 距离页面可显示区域(屏幕除去导航条)左上角距离,横向为X轴,纵向为Y轴
CanvasTouch 对象
属性 说明
identifier 触摸点的标识符
changedTouches

changedTouches 数据格式同 touches 。表示有变化的触摸点,如从无变有(touchstart),位置变化(touchmove),从有到无(toucheng,touchcancel)。

detail

自定义事件所携带的数据,如表单组件的提交事件会携带用户的输入,媒体的错误事件会携带错误信息,(具体在各个事件的定义。)
点击事件的 detail 带有的 x,y 同 pageX,pageY 代表距离文档左上角的距离。


基础组件

为开发者提供了一系列基础组件,开发者可以通过组合这些基础组件进行快速开发,(具体的后面再开一个博客)
什么是组件:

  • 组件是视图层的基本组成单元。
  • 组件自带一个功能与微信风格一致的样式。
  • 一个组件通常包括 开始标签 和 结束标签 和 属性 来修饰这个组件,内容在两个标签之内。(和 html 很像可以理解成标签)
<tagname property="value">
Content goes here ...
tagname>

注意:所有组件与属性都是小写,以连字符 - 连接

属性类型
类型 描述 注解
Boolean 布尔值 组件写上该属性,不管什么都会当作 true ;组件没有该属性时,属性值才为 false。属性值为变量的时候,变量值的值会被转化为Boolean类型
Number 数字 1,2.5
String 字符串 “string”
Array 数组 [1,"string]
Object 对象 {key:value}
EventHandler 事件处理函数名 “handlerName” 是 Page 中定义的事件处理函数名
Any 任意属性
公共属性

所有组件都有以上属性:

属性名 描述 注解
id 组件的唯一标识 保持整个页面的唯一(和HTML标签一样)
class 组件的样式类 在对应的 WXSS 中定义的样式类
style 组件的内联样式 动态设置的内联样式
hidden 组件是否显示 所有组件默认显示
data-*** 自定义属性 触发事件 dataset ,会发送给事件处理函数
bind*/catch* 组件的事件 bind*(是可冒泡的事件)catch*(可以阻止冒泡事件)
特殊属性

几乎所有组件都有各种自定义的属性,可以对该组件的功能或样式进行修改(之后详解)

获取界面上的节点信息
WXML节点信息

节点信息查询 API 可以用于获取节点属性,样式,在界面上点的位置等信息。
最常见的用法是使用这个接口来查询某个节点的当前位置,以及界面的滚动位置。
示例代码:

const query = wx.createSelectorQuery()
//底下是一个节点选择器,与css选择器相近但略有区别。
query.select('#the-id').boundingClientRect(function(res){
  res.top // #the-id 节点的上边界坐标(相对于显示区域)
})
query.selectViewport().scrollOffset(function(res){
  res.scrollTop // 显示区域的竖直滚动位置
})
query.exec()

在自定义组件或包含自定义组件的页面中,推荐使用this.createSelectorQuery 来代替 wx.createSelectorQuery
这样就确保再正确的范围内选择节点。

WXML节点布局相交状态可用于监听两个或多个组件节点在布局位置上的相交状态。这组 API 常常用于推断某些节点是否可以被用户看见,有多大比例可以被用户看见。

涉及的主要概念如下。

  • 参照节点:监听的参照节点,取他的布局区域作为参照区域。如果有多个参照节点,则会取他们布局区域的 交际 作为参照区域。页面显示区域页可以作为参照区域之一。
  • 目标节点:监听的目标,默认只能是一个节点(使用 selectAll 选项时,可以同时监听多个节点)。
  • 相交区域:目标节点的布局区域与参照区域的相交区域。
  • 相交比例:相交区域栈参照区间的比例。
  • 阈值:相交比例如果达到阈值,则会触发监听器的回调函数。阈值可以有多个。
示例代码:
Page({
   onload: function(){
   	 wx.createIntersectionObserver().relativeToViewport().observe('.target-class',(res) => {
   		res.id //目标节点的id
   		res.dataset //目标节点 dataset
   		res.intersectionRatio //相交区域占用目标节点的布局区域的比例
   		res.intersectionRect //相交区域
   		res.intersectionRect.left //相交区域的左边界坐标
   		res.intersectionRect.top //相交区域的上边界坐标
   		res.intersectionRect.width //相交区域的宽度
   		res.intersectionRect.height //相交区域的高度
   	})
   }
})

以下实例代码可以在目标节点(用选择器 .target-class 指定)与参照节点(用选择器 .relative-class 指定) 在页面显示区域内相交或相离,且相交或相离成都达到目标节点布局区域的20%和50%时,触发回调函数。
示例代码:

Page({
	onload:function(){
		wx.createIntersectionObserver(this,{
			threshoulds:[0.2,0.5]	
		}).relativeTo('.relative-class').relativeToViewport().observe('.target-class'.(res) => {
			res.intersectionRatio //相交区域占目标节点的布局区域的比例
			res.intersectionRect //相交区域
			res.intersectionRect.left // 相交区域的左边界坐标
      		res.intersectionRect.top // 相交区域的上边界坐标
		    res.intersectionRect.width // 相交区域的宽度
      		res.intersectionRect.height // 相交区域的高度
	})

	}
})

注意:与页面显示区域的相交区域并不准确代表用户可见的区域,因为参与计算的区域是 “布局区域” 布局区域可能会在绘制时被其他节点裁剪隐藏(如遇祖先节点中 overflow 样式为 hidden的节点)或遮盖(如遇 fixed 定位的节点)。
自定义组件或包含自定义组件的页面中,推荐使用 this.createIntersectionObserver 来代替 wx.createIntersectionObserver,这样可以确保在正确的范围内选择节点。

响应显示区域变化
显示区域尺寸

显示区域指小程序界面中可以自由布局展示的区域。在默认情况下,小程序显示区域的尺寸字页面初始化起就不会发生变化。但以下两种方式都可以改变这一默认行为。

在手机上启用屏幕旋转支持

从小程序基础库版本开始,小程序在手机上支持屏幕旋转。使小程序中的页面支持屏幕旋转的方法是:在 app.json 的 window 段中设置 “pageOrientation”:“auto” , 或在页面 json 文件中配置 “pageOrientation”:“auto” 。
“pageOrientation”:“landscape”,表示固定为横屏显示。

在 ipad 上启用屏幕旋转支持

在 app.json 中添加 “resizable”"“true” 。
不能单独配置莫格页面是否支持屏幕旋转

Media Query

又是,对于不同尺寸的显示区域,页面的布局会有所差距,此时可以使用 media query 来解决问题。

.my-class{
	width: 40px;
}

@media (min-width: 480px){
	.my-class{
		width:200px;
	}
}
屏幕旋转事件

有时,仅仅使用 media query 无法控制一些比较精细的布局变化。此时可以使用 js 作为辅助。
在 js 中读取页面的显示区域尺寸,可以使用 selectorQuery.selectViewport 。

动画
界面内动画的常见方式

在小程序中,通常可以使用 css 渐变 和 css 动画类创建简易的界面动画。
同时,还可以使用 wx.createAnimation 接口来动态的创建简易的动画效果。
动画过程中,可以使用 bindtransitionend bindanimationstart bindanimationoteration bindanimationend 来监听动画事件。

事件名 含义
transitionend css渐变结束或 wx.createAnimation 结束一个阶段
animationstart css动画开始
animationiteration css动画结束一个阶段
animationend css动画结束

注意:这几个是啊金都不是冒泡事件,需要绑定在真正发生了动画的节点上才会生效。

高级的动画方式

wxs 响应事件 的方式可以通过使用 WXS 来响应事件的方法来动态的调整节点的 style 属性。通过不断改变 style 属性的值可以做到动画效果。同时,这种方式也可以根据用户的触发事件来动态的生成动画。
连续使用 setData 来改变界面的方法也可以达到动画的效果。这样可以任意的改变界面,但通常会产生较大的延迟或卡顿,甚至导致小程序僵死。此时可以通过将页面的 setData 改为 自定义组件 中的 detData 来提升新能。下面的例子是使用 setData 来提升性能。下面的例子是使用 setData 来实现秒表动画的实例。

小程序的运行环境

微信小程序运行在三端:ios(iPhone/ipad),Android 和 用于调试的开发者工具。
三端的脚本执行环境以及用于渲染非原生组件的环境是各不相同的;

  • 在 ios 上,小程序逻辑层的 javascript 代码运行在 javascriptCore 中,视图层是由 WKWebView 来渲染的,环境还有 ios8,ios9,ios10;
  • 在 Android 上,
    • 旧版本,小程序逻辑层的 javascript 代码运行在 javaScriptCore 中,视图层是由 X5 基于Nobile Chrome 57 内核来渲染的
    • 新版本,小程序逻辑层的 javascript 代码运行在 V8 中,视图层是由自研 XWeb 引擎基于 Monile Chrome 67内核来渲染的
  • 在 开发者工具 上,小程序逻辑层的 javascript 代码是运行在 NW.js 中,视图层是由 Chromium 60 Webview 来渲染的
平台差距

尽管三端的环境是十分相似的,但是还是有一些区别:

  • javascript 语法和 API支持不一致:语法上开发者可以通过开启 ES6 转 ES5 的功能来规避;小程序基础库内置了必要的 Polyfill,来弥补 API 的差异。
  • wxss ,建议开发者在 ios 和 Android 上分别检查小程序的真实表现。
javascript支持情况
运行限制

基于安全开路,小程序中不支持动态执行 JS 代码。及:

  • 不支持使用 eval执行 JS 代码
  • 不自持使用 new Function 创建函数
客户端 ES6 API 支持情况

微信小程序已经支持了绝大部分的 ES6 API,已支持的API 如下(部分 API 依赖系统版本):
String: normalize (ios8,ios9 不支持)
Array: values(ios8,Android不支持),include(ios8不支持)
Other: Proxy(ios8,ios9,Android)

小程序运行机制
前台/后台的状态

小程序启动后,界面被展示给用户,此时小程序出去前台状态。
当用户点击右上角胶囊按钮关闭小程序,或者按了设备 Home 键离开微信是,小程序并没有完全终止运行,而是进入了后台状态,小程序还可以运行一小段时间。
当用户再次进入微信或再次打开小程序,小程序优惠从后台进入前台,但如果用户很久没有再进入小程序,或者系统资源紧张,小程序可能被销毁,即完全终止运行。

小程序启动

小程序启动可以分为两种情况,冷启动和热启动。

  • 冷启动:如果用户首次打开,或小程序销毁后被用户再次打开,此时小程序并未被销毁,只是从后台状态进入前台状态,这个过程就是热启动。
小程序销毁时机
  • 当小程序进入后台,可以维持一小段时间的运行状态,这段时间内都未进入前台,小程序会被销毁。
  • 当小程序占用资源过高,可能会被系统销毁或者被微信客户端主动回收。
    (ios是,目前是5秒连续两次及以上系统内存告警时,会主动进入小程序销毁,并提示用户)(建议小程序必要时使用 wx.onMemoryWarning 监听内存告警事件,进行必要的内存清理)
启动场景分类

A:打开首页

场景值ID 说明
1001 小程序主入口
1019 微信支付入口
1023 安卓系统桌面图标
1038 从另一个小程序返回
1056 音乐播放器菜单
1089 首页下拉小程序栏

B:打开小程序指定的莫格页面
(不同场景类别的启动将具有不同的行为)

热启动逻辑

小程序再热启动时,可能需要立刻跳转到别的页面,点击分享卡片进入小程序时。此时可能会自动产生页面跳转。
按照场景值的类别

上一次的场景 当前场景 效果
A A 保留原来的状态
B A 清空原来的页面栈,打开首页
A或B B 清空页面栈,打开指定页面

A类场景的重新启动策略
小程序被销毁后,下次冷启动如果属于B类场景,将会进入特定的页面。
下次冷启动如果属于A类场景,默认情况下将会进入小程序的首页。在页面对应的json文件中(也可以全局配置在 app.json 的window段中),指定 restartStrategy 配置项可以改变这个默认的行为,使得从某个页面推出后,下次A类场景的冷启动可以回到这个页面。

可选值 含义
homePage 如果从这个页面推出小程序,下次将从首页冷启动。
homePageAndLastestPage 从这个页面推出小程序,下次冷启动后立刻加载这个页面,页面的参数保持不变(不能用于 tab 页)

注意:即使不配置为 homePage ,小程序如果退出过久,下一次冷启动也将不再遵循 restartStrategy 的配置,而是直接从首页冷启动。
无论如何,页面的状态并不会被保留,如输入框中的文本内容,checkbox 的勾选状态等都不会还原。如果需要还原或部分还原,需要利用退出状态。

退出状态

每当小程序可能被销毁之前,页面回调函数 onSaveExitState 会被调用。如果想保留页面中的状态,可以在这个回调函数中保存一些数据,下次启动时可以通过 exitState 获得这些已保存数据。

Page({
	onload:function(){
		var prevExitState = this.exitState //尝试获得上一次退出前 onsaveExitState 保存的数据。
		if(prevExitState !== underfined){
			prevExitState.myDataField === 'myData'
		}
	},
	onSaveExitState:function(){
		var exitState = {myDataField:'myData'} //需要保存的数据
		return{
			data:exitState,
			expireTimeStamp:Date.now() + 24*60*60*1000 //超时时刻
		}
	}
})

onSaveExitState 返回值可以包含两项:

字段名 含义
data 需要保存的数据
expireTimeStamp 超时时刻,在这个时刻后,保存的数据保证一定被丢弃,默认为(当前时刻 +1 天)‘

注意事项:

  • 如果超过 expireTimeStamp ,保存的数据将被丢弃,且冷启动时不遵循 restartStrategy 的配置,而是直接从首页冷启动。
  • expireTimeStamp 有可能被自动提前,如微信客户端需要清理数据的时候。
  • 在小程序存活期间, onSaveExitState 可能会被多次调用,此时以最后一次的调用结果作为最终结果。
  • 在某些特殊情况下(如微信客户端直接被系统杀死),这个方法将不会被调用,下次冷启动也不遵循 restartStrategy 的配置,而是直接从首页冷启动。
小程序更新机制
未启动时更新

开发者在管理后台发布新版本的小程序之后,如果某个用户本地有小程序的历史版本,此时打开的可能还是旧版本。微信客户端会有若干个时机去检查本地缓存的小程序有没有更新版本,如果有则会精默更新版本。总的来说,开发者在后台发布新版本之后,无法立刻影响到所有现网用户,但最差情况下,也在发布之后 24 小时之内下发新版本信息到用户。用户下次打开时回先更新最新版本再打开。

启动时更新

小程序每次冷启动时,都会检查是否有更新版本,如果发现有新版本,将会异步下载新版本的代码包,并同时用客户端本地的包进行启动,即将版本的小程序需要等下一次冷启动才会应用上。

如果需要马上引用到最新版本,可以使用 wx.getUpdateManger API进行处理。

const updateManager = wx.getUpdateManger()
updateManager.onCheckForUpdate(function(res){
	请求完整版本信息的回调
	console.log(res.hasUpdate)
})

updateManger.onUpdateReady(function (){
	wx.showModal({
		title:'更新提示',
		content:'新版本已经准备好,是否重启应用?',
		success(res){
			updateManger.applyUpdate()
		}
	})
})

updateManger.onUpdatedailed(function (){
	//新版本下载失败
})

你可能感兴趣的:(wx小程序学习,wx小程序入门,小程序框架)