小程序中的js对象实例,按作用域大小划分,大致可以归为三类:App, Page, Component。
Component 也即本文要重点要讲的自定义组件,或称模板。
一、App?
App() 必须在 app.js 中调用且只能调用一次,用于注册成为一个小程序应用。
1、app.js
App({
// 小程序初始化完成时触发,全局只触发一次。
onLaunch (options) {
// 通过options.scene获取场景值可以得到小程序进入的渠道来源
// 参数也可以使用 wx.getLaunchOptionsSync 获取。
},
// 小程序启动,或从后台进入前台显示时触发。
onShow (options) {
// 小程序启动,或从后台进入前台显示时触发。
},
// 小程序从前台进入后台时触发。
onHide () {
// 也可以使用 wx.onAppHide 绑定监听。
},
onError (msg) {
console.log(msg)
},
// 小程序要打开的页面不存在时触发。也可以使用 wx.onPageNotFound 绑定监听。
onPageNotFound(res) {
// 如果是 tabbar 页面,需使用 wx.switchTab
// 若需保留历史页面路径,需用wx.navigateTo,而非wx.redirectTo (会销毁当前页面)
// 若存在循环操作,则需要计算页面层级(wx.navigateTo最多跳转10层页面,超过会报页面栈溢出)
let pageNum = getCurrentPages().length
if(pages >= 10){
// 超过页面路由层深,返回重载应用首页
wx.reLaunch({
url: '/pages/index/index'
})
}else{
wx.navigateTo({
url: '/pages/...'
})
}
// 控制后退页面数 wx.navigateBack(); wx.navigateBack({delta: n}); // 后退n页
wx.navigateBack({
// 回退所有循环操作页面,只保留前3页
delta: pageNum - 3,
// iOS会先重定向后回退页面,需要控制先回退完成后再重定向到指定页面
complete: function(){
wx.redirectTo({
url: '/pages/...'
})
}
})
},
// 全局数据,可以保存用户登录信息等
globalData: {
}
})
2、app.json
app.json 全局配置(所有页面需要在此文件中注册配置pages。该文件不能写注释。)
{
"pages": [
"pages/index/index"
],
"window": {
"backgroundTextStyle": "light",
"navigationBarBackgroundColor": "#fff",
"navigationBarTitleText": "我的小程序",
"navigationBarTextStyle": "black"
},
"permission": {
"scope.userLocation": {
"desc": "你的位置信息将用于定位效果展示"
}
},
"style": "v2",
"sitemapLocation": "sitemap.json",
"tabBar": {
"color": "#333333",
"selectedColor": "#333333",
"selectedFontweight": "600",
"backgroundColor": "#fff",
"list": [
{
"pagePath": "pages/index/index",
"iconPath": "/img/icon_index0.png",
"selectedIconPath": "/img/icon_index1.png",
"text": "首页"
},
{
"pagePath": "pages/mine/mine",
"iconPath": "/img/icon_mine0.png",
"selectedIconPath": "/img/icon_mine1.png",
"text": "我的"
}
]
}
}
二、Page
1、/pages/chat-list/chat-list.js
import Api from '../../api.js';
Page({
/**
* 页面的初始数据
*/
data: {
userId: 0,
pageNum: 1,
chats: [],
noMoreChatData: false,
noMoreUserData: false
},
// 扫码
scanCode(){
// 这一步重命名赋值变量,是为了在回调函数内部能够获取当前页面对象
let that = this
wx.scanCode({
onlyFromCamera: true,
success (res) {
// {"charSet":"utf-8","result":"32","codeVersion":1,"errMsg":"scanCode:ok","rawData":"MzI=","scanType":"QR_CODE"}
if(res.result == that.data.userId){
wx.showToast({
title: '扫码成功'
})
}else{
wx.showToast({
title: '二维码无效',
icon: 'none'
})
}
},
fail (res) {
wx.showToast({
title: res,
icon: 'none'
})
}
})
},
// 弹框下拉选菜单
chooseMenu() {
let that = this
wx.showActionSheet({
itemList: ['离职-随时到岗', '在职-月内到岗', '在职-考虑机会', '在职-暂不考虑'], // 不能超过6个
success (res) {
// todo something
}
})
},
// 订阅服务消息通知(后台服务器按模板ID推送通知,小程序订阅接收)
subscribeNotice(){
wx.requestSubscribeMessage({
tmplIds: ['o-ztPlfmck2B6yWFey_pLloT3CxUqLrbXnX-FvfiWlo'],
success: (res) => {}
})
},
// 页面锚点
pageScrollTo(){
wx.pageScrollTo({
selector:'#footer', // 滚动至指定节点元素id
duration: 0 // 滚动过渡时间
})
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
// 可以通过options获取上级页面路由路径传参
let userId = options.userId
this.setData({
userId: userId
})
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
// 一般会在页面显示时,请求服务加载数据,动态渲染页面展示
this.getChatsByPage()
// 禁止页面分享菜单(shareAppMessage分享给朋友;shareTimeline分享到朋友圈)
wx.hideShareMenu({
menus: ['shareAppMessage', 'shareTimeline']
})
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
// wx.redirectTo 会触发当前页面销毁
// 一般也会在页面销毁时(包括onHide时),关闭当前页面的定时器
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
// 该事件默认关闭,需要在页面对应的json配置文件中开启 "enablePullDownRefresh": true
// 比如聊天页面,后台服务按时间倒序返回聊天记录,前端第一页拉取最新的聊天记录,下拉刷新拉取历史聊天记录
// 下拉刷新,获取下一页历史聊天数据列表
this.getChatsByPage()
},
// 获取聊天数据列表
getChatsByPage(){
if(!this.data.noMoreChatData){
this.setData({
pageNum: this.data.pageNum + 1
})
// 前端拉取的每一页记录,逆序处理后,追加到当前数据列表的头部
let chats = Api.getChatsByPage() // 分页查询,从后台服务器拉取聊天记录数据
if(chats != null && chats.length > 0){
chats.sort(function(a, b){return a['id'] - b['id']}) // 逆序处理:数组属性获取方法,重写排序规则要return
that.setData({
chats: chats.concat(that.data.chats) // 头部插入数组
})
}else{
that.setData({
noMoreChatData: true
})
}
}
},
// 分页查询数据列表(触底onReachBottom后若有更多数据再请求)
noMoreUserData(e) {
// 参数值由子组件user-list触发trigger传递过来
this.setData({
noMoreUserData: e.detail
})
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
// 分页查询处理
if (!this.data.noMoreUserData) {
// 获取子组件 user-list
this.userList = this.selectComponent("#userList")
// 调用子组件的方法
this.userList.getDataList()
}
},
/**
* 用户点击右上角分享(移除该函数,则整个页面禁止分享)
*/
onShareAppMessage: function () {
}
})
2、/pages/chat-list/chat-list.json
页面对应的json配置文件:引用组件;开启下拉刷新监听;设置标题栏
{
"usingComponents": {
"user-list": "/components/user-list/user-list"
},
"enablePullDownRefresh": true,
"navigationBarTitleText": "聊天列表"
}
3、/pages/chat-list/chat-list.wxml
<view class="chat-list">
<!--
引用子组件模板,user-list标签需与chat-list.json中引入并设定的组件名保持一致;
设定的id,用于chat-list.js中获取子组件对象:
this.userList = this.selectComponent("#userList")?
userId 为父传子交互属性, 对应子组件user-list.js的properties中定义的属性userId
bind:noMoreUserData 用于子组件user-list.js中trigger触发父组件方法noMoreUserData
-->
<user-list id="userList"? userId="{{userId}}" bind:noMoreUserData="noMoreUserData" />
</view>
三、Component
如果诸多Page间存在一些反复重复部分,可以选择新建Component,抽取出公共部分作为模板引用,也即自定义组件,从而达到复用的目的。
组件json配置,声明为组件(当然,组件内部还可以再嵌套引用其他组件):
1、/components/user-list/user-list.json
{
"component": true,
"usingComponents": {
"no-more": "/components/no-more/no-more"
}
}
2、/components/user-list/user-list.js
import Api from '../../api.js'
// 子组件 user-list
Component({
/**
* 组件的属性列表 (父传子交互属性)
*/
properties: {
userId: Number
},
/**
* 组件的初始数据 (子组件私有数据,data中可以获取到properties中的传参值)
*/
data: {
userId: 0,
dataList: [],
pageNum: 1,
noMoreData: false
},
/**
* 组件的方法列表
*/
methods: {
// 子组件中定义的方法,父组件中获取到子组件对象后,可以调用子组件方法
getDataList() {
// 获取数据列表
let dataList = Api.getDataList()
if(dataList.length > 0){
this.setData({
dataList: this.data.dataList.concat(dataList),
pageNum: pageNum + 1
})
}else{
this.setData({
noMoreData: true
})
// 子组件user-list, 触发父组件对象绑定的监听方法
this.triggerEvent('noMoreUserData', true)
}
}
}
})
|