这个只是我的学习过程算是日记形式吧,过程是按微信的官方文档的循序来,从 指南中的小程序框架 开始,指南中这一节之前还有页面配置,目录结构,还有很多介绍,没有写但是是非常重要的,一定要看,像指南后面的框架,组件,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
对于小程序中的每个页面,都需要在页面对应的 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'
}
})
setData 函数用于将数据从逻辑层发送到视图层(异步发送),同时改变对应的 this.data的值(同步)。
1.支持改变数组的某一项或者对象的某个参数,并且数据可以不在 this.data中预先定义,
2.但是必须是可支持json化的数据。
3.如果数据是数祖或者对象的化,键值对的 key 可以是一个地址
比如 ‘array[0].text’:‘changed data’ (数组) ‘object.text’: ‘changed data’(对象)
和 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 页面上)
就是将一个公共的代码抽离出来成为一个单独的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,会学习一遍,会在写一个博客,还有组件那块也会再写一个博客)
通常,小程序 APP 有几个基本的类型:
约定以 on 开头的 API 用来监听某个事件是否被触发 ,比如 wx.onSoncketOpen ( 监听WebSocket 链接打开事件 ) ,wx.onCompassChange(监听罗盘数据变化事件,每5秒一次,接口调用后会自动开始监听,可使用 wx.stopCompass)
ps:webSocket 是 H5 开始提供的一种在单个 TCP 链接上进行全双工通讯的协议。
这种类型的API 接受一个回调函数作为参数。当事件触发时会调用这个回调函数并将相关数据以参数形式传入
wx.onCompassChange(function (res) {
console.log(res.direction)
})
以 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接口通常都接受一个 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)
}
}
})
框架的视图层是由 WXML 与 WXSS 两个文件编写,由组件来进行展示。
将逻辑层的数据变成视图,同时将视图层的事件返回逻辑层。
WXML (WeiXin Markup language)用于描述页面的结构。
WXSS (WeiXin Style Sheet)用于描述页面的样式。
组件(Component)是视图的基本组成单元。
是框架设计的一套标签语言,结合基础组件,时间系统,就可以构建出页面的结构。
(这里很细具体的之后再写)先介绍一点具有哪些功能
<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'}
}
})
这是一套样式语言,类似于css(但是还有进行扩充和修改),用于描述wxml的组件样式.
扩展的特性有
/** common.wxss **/
.small-p{
padding:5px;
}
/**app.wxss**/
@import "common.wxss"
,middle-p{
padding:15px;
}
框架组件上支持使用 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 中 相同的选择器.
解释一下事件
Click me!
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 的形式。
,触摸类事件支持捕获阶段。捕获阶段位于冒泡之前,而且在捕获阶段中,事件到达节点的顺序与冒泡阶段恰好相反。需要在捕获阶段监听事件时。可以采用 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>
当组件出发事件时,逻辑层会绑定该事件的处理函数会收到一个事件对象。
属性 | 说明 |
---|---|
type | 事件类型 |
timeStamp | 事件生成时的时间戳 |
target | 触发事件的组件的一些属性值集合 |
currentTarget | 当前组件的一个属性值的集合 |
mark | 事件标记数据 |
属性 | 说明 |
---|---|
detail | 额外的信息 |
属性 | 说明 |
---|---|
touches | 触摸事件,当前停留在屏幕中的触摸点信息的数组 |
changedTouches | 触摸事件,当前变化的触摸点信息的数组 |
type: 代表事件的类型。
timeStamp : 页面打开到触发事件所经过的毫秒数。
target:触发事件的源组件。(源组件)
属性 | 说明 |
---|---|
id | 事件源组件的 id 值 |
dataset | 事件源组件上面由 data- 开头的自定义属性组成的集合.(重要) |
事件绑定当前组件。
属性 | 说明 |
---|---|
id | 当前组件 id |
dataset | 当前组件由 data- 开头的自定义属性组合成的集合 |
说明:target 和 currentTarget 可以参考上例中,点击 inner view 时, handleTap3 收到的事件对象 target 和 currentTarget 都是 inner,而 handleTap2 收到的事件对象 Target 就是 inner,currentTarget 就是 middle。
组件节点中可以附加一些自定义数据。 这样,在事件中可以获取这些自定义的节点数据,用于事件的逻辑处理。
在 WXML 中,这些自定义数据以 data- 开头
DataSet Test
Page({
bindViewTap:function(event){
event.currentTarget.dataset.alphaBeta === 1 // - 会转为驼峰写法
//就是把 - 去掉,然后第一个字母要大写
event.currentTarget.dataset.alphabeta === 2 // 大写会转为小写
//没有 - 的话就全部用小写
}
})
可以使用 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- 属性值。
touches是一个数组,每一个元素为一个 Touch 对象(canvas 触摸事件中携带的 touches 是 CanvasTouch数组)。表示当前停留在屏幕上的触摸点。
属性 | 说明 |
---|---|
identifier | 触摸点的标识符 |
pageX,pageY | 距离文档左上角的距离,文档的左上角为原点,横向为X轴,纵向为Y轴 |
clientX,clientY | 距离页面可显示区域(屏幕除去导航条)左上角距离,横向为X轴,纵向为Y轴 |
属性 | 说明 |
---|---|
identifier | 触摸点的标识符 |
changedTouches 数据格式同 touches 。表示有变化的触摸点,如从无变有(touchstart),位置变化(touchmove),从有到无(toucheng,touchcancel)。
自定义事件所携带的数据,如表单组件的提交事件会携带用户的输入,媒体的错误事件会携带错误信息,(具体在各个事件的定义。)
点击事件的 detail 带有的 x,y 同 pageX,pageY 代表距离文档左上角的距离。
为开发者提供了一系列基础组件,开发者可以通过组合这些基础组件进行快速开发,(具体的后面再开一个博客)
什么是组件:
<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*(可以阻止冒泡事件) |
几乎所有组件都有各种自定义的属性,可以对该组件的功能或样式进行修改(之后详解)
节点信息查询 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
这样就确保再正确的范围内选择节点。
涉及的主要概念如下。
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”,表示固定为横屏显示。
在 app.json 中添加 “resizable”"“true” 。
不能单独配置莫格页面是否支持屏幕旋转
又是,对于不同尺寸的显示区域,页面的布局会有所差距,此时可以使用 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 和 用于调试的开发者工具。
三端的脚本执行环境以及用于渲染非原生组件的环境是各不相同的;
尽管三端的环境是十分相似的,但是还是有一些区别:
基于安全开路,小程序中不支持动态执行 JS 代码。及:
微信小程序已经支持了绝大部分的 ES6 API,已支持的API 如下(部分 API 依赖系统版本):
String: normalize (ios8,ios9 不支持)
Array: values(ios8,Android不支持),include(ios8不支持)
Other: Proxy(ios8,ios9,Android)
小程序启动后,界面被展示给用户,此时小程序出去前台状态。
当用户点击右上角胶囊按钮关闭小程序,或者按了设备 Home 键离开微信是,小程序并没有完全终止运行,而是进入了后台状态,小程序还可以运行一小段时间。
当用户再次进入微信或再次打开小程序,小程序优惠从后台进入前台,但如果用户很久没有再进入小程序,或者系统资源紧张,小程序可能被销毁,即完全终止运行。
小程序启动可以分为两种情况,冷启动和热启动。
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 天)‘ |
注意事项:
开发者在管理后台发布新版本的小程序之后,如果某个用户本地有小程序的历史版本,此时打开的可能还是旧版本。微信客户端会有若干个时机去检查本地缓存的小程序有没有更新版本,如果有则会精默更新版本。总的来说,开发者在后台发布新版本之后,无法立刻影响到所有现网用户,但最差情况下,也在发布之后 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 (){
//新版本下载失败
})