2.1小程序框架
2.1.1基本框架
1)逻辑层
用来处理业务逻辑
JavaScript
2)视图层
用来渲染页面
视图层描述语言WXML
视图样式WXSS
2.1.2目录结构
1)框架全局文件
①app.js
定义全局数据和函数的使用
指定微信小程序的生命周期函数
onLaunch:监听小程序初始化
onShow:监听小程序显示
onHide:监听小程序隐藏
②app.json
③app.wxss
对CSS样式进行了拓展
该文件是对所有页面定义的一个全局样式
当页面重新定义的样式与全局样式冲突,全局样式将被覆盖
④project.config.json
小程序项目个性化配置文件:界面颜色、编译配置等
包含一些版本、appid、项目名称等信息
换机器重新安装开发工具需重新配置
每个项目根目录下均会产生此文件
2)框架页面文件
框架页面文件主要由5个文件组成:
文件类型 | 是否必填 | 作用 |
---|---|---|
js | 是 | 页面逻辑 |
json | 否 | 页面配置 |
wxml | 是 | 页面结构 |
wxs | 否 | 小程序脚本语言 |
wxss | 否 | 页面样式表 |
框架页面文件都放置在pages文件夹下
2.2注册程序应用
2.2.1小程序注册
在App()函数里完成小程序注册,并指定其生命周期函数
属性 | 类型 | 描述 | 触发时机 |
---|---|---|---|
onLaunch | Function | 监听小程序初始化 | 当小程序初始化完成时,会触发onLaunch(全局只触发一次) |
onShow | Function | 监听小程序显示 | 当小程序启动,或从后台进入前台显示,会触发onShow |
onHide | Function | 监听小程序隐藏 | 当小程序从前台进入后台,会触发onHide |
onError | Function | 错误监听函数 | 当小程序发生脚本错误,或者API调用失败时,会触发onError并附带错误信息 |
onPageNotFound | Function | 页面不存在监听函数 | 当小程序出现要打开的页面不存在的情况,会附带页面信息回调该函数 |
其他 | Any | 开发者可以添加任意的函数或数据到Object参数中,用this可以使用 |
2.2.2全局调用
在页面js文件,按如下所示方法,就可以调用app.js里的全局数据globalData
var AppInstance=getApp()
console.log(AppInstance.globalData)
不仅可以调用全局数据,还可以调用自定义的全局函数,但是不能调用生命周期函数
2.2.3注意事项
- App()必须在app.js中注册,且不能注册多个
- 不要在定义于app()内的函数中调用getApp(),使用this就可以获取App实例
- 不要在onLoad的时候调用getCurrentPage(),此时page还没有生成
- 通过getApp()获取实例之后,不要私自调用生命周期函数
2.3注册页面的使用
.js文件中的Page()函数用来注册页面
接受一个object参数,其指定页面的初始数据、生命周期函数、事件处理函数等页面的所有业务逻辑处理都放在这个文件里
1)Object参数说明
属性 | 类型 | 描述 |
---|---|---|
data | Object | 页面的初始数据 |
onLoad | Function | 监听页面加载 |
onReady | Function | 监听页面初次渲染完成 |
onShow | Function | 监听页面显示 |
onHide | Function | 监听页面隐藏 |
onUnload | Function | 监听页面卸载 |
onPullDownRefresh | Function | 监听用户下拉动作 |
onReachBottom | Function | 页面上拉触发事件的处理函数 |
onShareAppMessage | Function | 用户单击右上角分享 |
onPageScroll | Function | 页面滚动触发事件的处理函数 |
onTabItemTap | Function | 当前是tab页时,点击tab时触发 |
其他 | Any | 开发者可以添加任意的函数或数据到object参数中,在页面的函数中用this可以访问 |
2)示例代码
Page({data:{text:'Hello World!'},onLoad:function(options){},onReady:function(options){},onShow:function(options){},onShareAppMessage:function(options){}
})
2.3.1页面初始化数据
- data
- 初始化数据将作为页面的第一次渲染
- data会以json的形式由逻辑层传到渲染层
- 其数据必须是可以转成json的格式(字符串、数字、布尔值、对象或数组)
- 渲染界面可以通过WXML对数据进行绑定
//.js
Page({data:{motto:'我的第一个微信小程序',userInfo:{},}})
<!--.wxml-->
<text class="user-motto">{{motto}}</text>
2.3.2生命周期函数
- onLoad 页面加载:一个页面只调用一次,接受页面参数可以获取wx.navigateTo和wx.redirectTo及< navigator >中的query
- onShow 页面显示:每次打开页面都会调用一次
- onReady 页面初次渲染完成:一个页面只调用一次,可和视图层进行交互,对界面的设置如wx.setNavigationBarTitle应在onReady之后设置
- onHide 页面隐藏:当调用navigateTo或底部tab切换时调用
- onUnload 页面卸载:当调用redirectTo或navigateBack的时候调用
2.3.3页面相关事件处理函数
- onPullDownRefresh 下拉刷新:监听用户下拉刷新事件,需要在config的windows选项中开启enablePullDownRefresh。当处理完数据刷新后,wx.stopPullDownRefresh可以停止当前页面的下拉刷新
- onShareAppMessage 用户分享:只有定义了此事件处理函数,右上角菜单才会显示“分享”按钮,用户点击“分享”按钮的时候会调用此函数。此事件需要返回一个Object参数,用于自定义分享内容。
分享参数及代码
Page({onShareAppMessage:function(){return{title:'自定义分享标题'desc:'自定义分享描述'path:'/page/user?id=123'//必须是以/开头的完整路径}.}
})
2.3.4页面路由管理
- 微信小程序的页面路由都是由微信小程序框架来管理的
- 框架以栈的形式维护了所有页面
- 小程序页面交互也是通过栈来完成√小程序初始化时,新页面入栈
- 打开新页面时,新页面入栈
- 页面重定向时,当前页面出栈
- 页面返回时,页面不断出栈,直到新页面入栈
- tab切换时,页面全部出栈,只留下新的tab页面
- 重新加载时,页面全部出栈,只留下新的页面
1.路由触发方式及页面生命周期函数
页面路由方式 | 触发时机 | 路由后页面 | 路由前页面 |
---|---|---|---|
初始化 | 小程序打开的第一个页面 | onLoad,onShow | |
打开新页面 | 调用API wx.navigateTo或使用组件< navigator open-type=“navigate”/> | onLoad,onShow | onHide |
页面重定向 | 调用API wx.redirectTo或使用组件< navigator open-type=“redirect”/> | onLoad,onShow | onUnload |
页面返回 | 调用API wx.navigateBack或用户按左上角返回按钮 | onShow | onUnload |
tab切换 | Function | 调用API wx.switchTab或使用组件< navigator open-type=“switchTab”/> 或用户切换/tab |
API应用程序调用接口
2.注意事项
- navigateTo,redirectTo只能打开非tabBar页面
- switchTab只能打开任意页面
- reLaunch可以打开任意页面
- 页面底部的tabBar由页面决定,即只要是定义为tabBar的页面,底部都有tabBar
- 调用页面路由带的参数可以在目标页面的onLoad中获取
2.3.5自定义函数
- 除了初始化数据和生命周期函数,Page中还可以定义一些特殊的函数:事件处理函数
- 在渲染层的组件中可以加入事件绑定
- 当达到触发事件时,就会执行Page中定义的事件处理函数
示例代码
<!--wxml-->
<view bindtap="clickMe">点我</view>
//js
Page({clickMe:function(){console.log('view tap')}
})
2.3.6 setDate设值函数
- Page.prototype.setData()设值函数用于将数据从逻辑层发送到视图层
- 同时改变对应的this.data的值
- setData()参数格式:
接受一个对象,以key, value的形式表示将this.data中的key对应的值改变成value - 其中key非常灵活,以数据路径的形式给出,如array[2].message,a.b.c.d
- 并且不需要在this.data中预先定义
示例代码
<!—wxml-->
<view>{{title}}</view>
<button bindtap=“changeText”>改变正常数据</button>
<view>{{array[0].text}}</view>
<button bindtap="changeItemInArray”>改变数据数据</button>
<view>{{object.text}}</view>
<button bindtap="changeItemInObject”>改变对象数据</button>
<view>{{newField.text}}</view>
<button bindtap=“addNewField”>增加新数据</button>
//js
Page({data:{text:'init data',array:[{text:'init data'}],object:{text:'init data'} },changeText:function(){//this.data.text='changed data'//错误,不能工作this.setData({text:'changed data'}) },changeItemInArray:function(){this.setData({'array[0].text':'changed data'}) },changeItemInObject:function(){this.setData({'object.text':'changed data'}) },addNewField:function(){this.setData({'newField.text':'new data'}) }
})
注意事项
- 直接修改this.data无效,无法改变页面的状态,还会造成数据不一致
- 单次设置的数据不能超过1024KB,尽量避免一次性设置过多的数据
2.4数据绑定
2.4.1简介
将js文件Page的data绑定至WXML页面,实现动态数据链接
2.4.2用法
通过双大括号({{ }})将变量包起来,在WXML页面里将数据值显示出来
2.4.3示例代码
//index.wxml
<!--index.wxml-->
<view>{{message}}</view>
//index.js
//index.js
Page({data:{message:'hello XiaoChengXu!'}
})
2.4.4数据绑定分类
1)组件属性绑定
将data里的数据绑定到小程序组件上
示例代码:
<!--wxml-->
<view id="item-{{id}}"></view>
//js
Page({data:{id:0}
})
2)控制属性绑定
用来进行if语句条件判断,如果条件满足则执行,否则不执行
示例代码:
<!--wxml-->
<view wx:if="{{condition}}"></view>
//js
Page({data:{condition:true}
})
3)关键字绑定
常用于组件的一些关键字
像复选框组件一样,checked关键字如果等于true,则代表复选框选中;如果等于false,则代表不选中复选框
示例代码:
<!--wxml-->
<checkbox checked="{{false}}"></checkbox>
注意:如果直接写checked = “false”,则该字符串的计算结果转为boolean类型后代表真值
4)关键字绑定
在{{ }}内可以进行简单的运算
①三元运算
<!--wxml-->
<view hidden="{{flag?true:false}}">Hidden</view>
②数学运算
<!--wxml-->
<view>{{a+b}}+{{c}}+d</view>
//js
Page({data:{a:1,b:2,c:3}
})
view中的内容为3+3+d
③逻辑判断
<!--wxml-->
<view wx:if="{{length>5}}"></view>
④字符串运算
<!--wxml-->
<view>{{“hello”+name}}</view>
//js
Page({data:{name:'微信小程序!'}
})
⑤数据路径运算
<!--wxml-->
<view>{{object.key}}{{array[0]}}</view>
//js
Page({data:{object:{key:'微信小程序!'},array:['hello']}
})
2.5条件渲染
2.5.1 wx:if判断单个组件
在微信小程序框架里,使用wx:if=“{{condition}}”来判断是否需要渲染该代码块
示例代码:
<!--wxml-->
<view wx:if=“{{condition}}” >True </view>
使用wx:elif和wx:else来添加一个else块:
<!--wxml-->
<view wx:if="{{ 1ength > 5}}">1</view>
<view wx:elif="{{ length > 2 }}">2</view>
<view wx:else>3</view>
2.5.2 block wx:if判断多个组件
wx:if是一个控制属性,需要将它添加到一个标签上
如果想一次性判断多个组件标签,可以使用一个< block/>标签将多个组件包装起来,并在上面使用wx:if控制属性
示例代码:
<!--wxml-->
<block wx:if="{{true}}"><view>view1</view><view>view2</view>
</block>
< block/>不是一个组件,它仅是一个包装元素,不会在页面做任何渲染,只接受控制属性
block wx:if示例
<!--index.wxml-->
<button bindtap="change_color">横条背景变色</button>
<!--wx:if-->
<block wx:if="{{b==true}}"><view class="bg_green"></view>
</block>
<block wx:elif="{{b==false}}"><view class="bg_blue"></view>
</block>
// index.js
Page({data:{b:false},change_color:function(){var ab = this.data.b;this.setData({b:!ab})}
})
/**index.wxss**/
.bg_green {height:100rpx;background:green;
}
.bg_blue {height:100rpx;background:blue;
}
< block>这个元素在条件渲染上是很好用的,不过要注意不要在这个标签上绑定其他属性,比如data-或者绑定事件bindtap。< block>元素不会在页面中做任何渲染,它不是个组件,所以在其上面绑定的事件或者属性也不会有效。
2.6列表渲染
2.6.1 wx:for列表渲染单个组件
- 在组件上使用wx:for控制属性绑定一个数组,即可使用数组中各项的数据重复渲染该组件
- 数组当前项的下标变量名默认为index
- 数组当前项的变量名默认为item
示例代码:
<view wx:for=“{{array}}” >{{index}}:{{ item.message}}
</view>
Page({data:{array:[{message:'第0个元素',},{message:'第1个元素'}]}
}]
使用wx:for-item可以指定数组当前元素的变量名
使用wx:for-index可以指定数组当前下标的变量名
示例代码:
<view wx:for=“{{array}}” wx:for-index="idx" wx:for-item="itemName">{{index}}:{{ itemName.message}}
</view>
2.6.2 block wx:for列表渲染多个组件
wx:for应用在某一个组件上,如果想渲染一个包含多节点的结构块,这时wx:for需要应用在< block/>标签上
示例代码:
<block wx:for=“{{[1,2,3]}}”><view> {{index}}:</view><view> {{item}} </view>
</block>
2.6.3 wx:key指定唯一标识符
如果列表中项目的位置会动态改变或有新的项目添加到列表中,并且希望列表中的项目保持自己的特征和状态,如
< input/>中的输入内容
< switch/>的选中状态
需要使用wx:key来指定列表中项目的唯一标识符
wx:key的值以以下两种形式提供
- 字符串:代表在for循环的array中item的某个property,该property的值需要是列表中唯一的字符串或数字,且不能动态改变
- 保留关键字:
*this代表在for循环中的item本身,这种表示需要item本身是一个唯一的字符串或者数字
当数据改变触发渲染层重新渲染的时候,会校正带有key的组件
框架会确保它们被重新排列,而不是重新创建,以确保组件保持自身的状态,并且提高列表渲染时的效率
示例代码
<switch wx:for=“{{objectArray}}” wx:key=“unique” > {{item.id}}</switch>
Page([data:{objectArray:[{id:5, unique: 'unique_5'},{id:4, unique: 'unique_4'},{id:3, unique: 'unique_3'},{id:2, unique: 'unique_2'},{id:1, unique: 'unique_1'},{id:0, unique: 'unique_0'}]}
})
注意:如不提供wx:key,会报一个warning,如果明确知道该列表是静态的,或者不必关注其顺序,可以选择忽略。
2.7定义模板
2.7.1定义模板
WXML提供模板(template)功能
可以把一些共用的、复用的代码,在模板中定义代码片段
在不同的地方调用,以达到一次编写,多次直接使用的效果
在< template/>内定义代码片段,使用name属性,作为模板的名字
示例代码如下:
<template name=“msgItem”><view><text> {{ index }} : {{ msg }} </text><text> Time: {{time}}</text></view>
</template>
2.7.2使用模板
在WXML文件里,使用is属性,声明需要使用的模板然后将模板所需要的data传入
示例代码如下:
<template is=“msgltem” data=“{{ item }}”/>
Page([data:{item: {index:O,msg:'这是一个模板',time:'2019-06-16'}}
])
is属性可以使用三元运算语法,来动态决定具体
需要渲染哪个模板:
<template name="odd" ><view>奇数</view>
</template>
<template name="even"><view>偶数</view>
</template>
<block wx:for=“{{[1,2,3,4,5]}}” ><template is="{{ item%2 == 0 ?'even':'odd' }}"/>
</block>
2.8引用功能
2.8.1 import引用——引用模板文件
import可以在该文件中使用目标文件定义的template假如在item.wxml中定义了一个叫item的template示例代码如下:
<!-- item.wxml -->
<template name="item"><text>{{ text }} </text>
</template>
在index.wxml中引用了item.wxml,就可以使用item模板
示例代码如下:
<import src="item.wxml"/>
<template is="item" data="{{ text: 'import引用'}}"/>
2.8.2 include引用——引用整个除了< template/>的文件
include可以将目标文件除了< template/>的整个代码引入
相当于是复制到include位置
示例代码如下:
<!-- index.wxml -->
<include src="header.wxml"/>
<view>页面主体</view>
<include src="footer.wxml"/><!-- header.wxml -->
<view>头文件</view><!-- footer.wxml -->
<view>尾文件</view>
2.9 WXS小程序脚本语言
暂时不学