那么,承接上一篇的内容,我们继续来学习微信小程序。需要一提的是,在微信小程序的开发和学习过程,不断地查阅文档是非常重要的,小程序的官方文档写的非常详细,所以我在很多地方没有过多介绍,而是附上了文档链接,希望读者能养成自行查阅文档的习惯。话不多说,今天的学习之旅就要开始了,各位看官准备好了吗?
六、自定义组件
微信提供了自定义组件的功能
参考https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/
1. 定义组件
自定义组件:
-
类似于页面,一个自定义组件由四个文件组成:
.js
.json
.wxml
.wxss
-
在
.js
文件中,通过调用Component(Object)
方法注册组件,并提供组件的属性定义、内部数据和自定义方法。 -
在
.json
文件中,通过"component":true
配置项来描述该构成为组件注意:
-
自定义组件时,在
.wxss
文件中不要使用ID选择器、属性选择器和标签名选择器,请使用类选择器 -
组件名称建议使用连字符方式,如
nav-bar
,不建议使用一个单词构成步骤:
- 创建一个与pages同级的文件夹components用于存放组件,注意不要在pages目录下建该文件夹
- 在companies文件夹下新建一个以组件名为名的文件夹
- 右击该文件夹,选择新建Component,文件名同样是组件名,此时会发现该文件夹下就建好了以组件名为名的四个文件
2. 使用组件
引用组件:
-
局部引用
在某个页面或组件的
.json
文件中引用声明,只能在该页面和组件中使用// 需要指定自定义组件的标签名和对应的文件路径 "usingComponents": { "component-tag-name": "path/to/the/custom/component" }
-
全局引用
在全局的
app.json
文件中引用声明,可以在所有页面和组件中直接调用
调用组件:
-
在其它组件或页面中,直接使用指定的标签名进行组件调用
<component-tag-name></component-tag-name>
3. 组件生命周期
组件的生命周期,指的是组件自身的一些函数,这些函数在特殊的时间点或遇到一些特殊的框架事件时被自动触发。
其中,最重要的生命周期是created
attached
detached
,包含一个组件实例生命流程的最主要时间点。
- 组件实例刚刚被创建好时,
created
生命周期被触发。此时,组件数据this.data
就是在Component
构造器中定义的数据data
。 此时还不能调用setData
。 通常情况下,这个生命周期只应该用于给组件this
添加一些自定义属性字段。 - 在组件完全初始化完毕、进入页面节点树后,
attached
生命周期被触发。此时,this.data
已被初始化为组件的当前值。这个生命周期很有用,绝大多数初始化工作可以在这个时机进行。 - 在组件离开页面节点树后,
detached
生命周期被触发。退出一个页面时,如果组件还在页面节点树中,则detached
会被触发。
3.1 定义生命周期方法
生命周期方法可以直接定义在 Component
构造器的第一级参数中。自小程序基础库版本 2.2.3 起,组件的的生命周期也可以在 lifetimes
字段内进行声明(这是推荐的方式,其优先级最高)。
Component({
lifetimes: {
attached: function() {
// 在组件实例进入页面节点树时执行
},
detached: function() {
// 在组件实例被从页面节点树移除时执行
},
},
// 以下是旧式的定义方式,可以保持对 <2.2.3 版本基础库的兼容
attached: function() {
// 在组件实例进入页面节点树时执行
},
detached: function() {
// 在组件实例被从页面节点树移除时执行
},
// ...
})
注:在详情——>本地设置——>调试基础库可以更改小程序的基础版本库
3.2 组件所在页面的生命周期
还有一些特殊的生命周期,它们并非与组件有很强的关联,但有时组件需要获知,以便组件内部处理。这样的生命周期称为“组件所在页面的生命周期”,在 pageLifetimes
定义段中定义。
Component({
pageLifetimes: {
show: function() {
// 页面被展示
},
hide: function() {
// 页面被隐藏
},
resize: function(size) {
// 页面尺寸变化
}
}
})
4. 组件间数据传递
分为两种情况:
- 父向子传递数据
- 子向父传递数据
注:小程序的页面Page也可以视为自定义组件
参考:https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/events.html
4.1 父向子传递数据
步骤:
- 父组件在调用子组件时,以属性绑定的方式将要传递的数据绑定在子组件标签上
- 在子组件
js
文件中,使用properties
选项声明获取的数据,进行绑定属性的拦截,即接收来自父组件的数据
4.2 子向父传递数据
步骤:
- 父组件在调用子组件时,使用
bind:自定义事件
监听子组件触发的自定义事件,并在父组件中定义回调方法,用来接收数据 - 在子组件中使用
this.triggerEvent(事件名,数据,事件选项)
触发自定义事件
七、API
API:Application Programming Interface
微信提供了一些功能接口,可以在js文件中直接调用,实现特定的功能
1. 路由
常用:wx.navigateTo
- 保留当前页面,跳转到应用内的某个页面。但是不能跳到 tabbar 页面。
- 使用 wx.navigateBack 可以返回到原页面。小程序中页面栈最多十层。
- url后面可以以查询字符串的形式带参数,在跳转的对应页面的js文件中写onload生命周期,可以通过其回调函数中的参数获取打开当前页面路径中的参数
类似的还有:
- wx.switchTab :跳转到tabBar页面,并关闭其他所有非tabBar页面,url中不允许带参数
- wx.navigateBack :关闭当前页面,返回上一页面或多级页面。可通过 getCurrentPages 获取当前的页面栈,决定需要返回几层
- wx.redirectTo:关闭当前页面,跳转到应用内的某个页面。但是不允许跳转到 tabbar 页面
<!--.wxml文件-->
<!-- wx.navigateTo 跳转非tabBar页面的两种方式: 1.使用navigator组件 2.使用wx.navigateTo -->
<view class="title">wx.navigateTo</view>
<navigator url="/pages/logs/logs?id=1001&name=Jack">跳转到logs</navigator>
<button type="primary" bindtap="goLogs">跳转到logs</button>
<!-- 跳转到tabBar页面的两种方式 1.使用navigator组件,设定属性open-type='switchTab' 2.使用wx.switchTab -->
<navigator url='/pages/index/index' open-type="switchTab">跳转到index</navigator>
<button type="primary" bindtap="goIndex">跳转到index</button>
Page({
goLogs(){
wx.navigateTo({
url: '/pages/logs/logs?id=1002&name=alice'
})
},
goIndex(){
wx.switchTab({
url: '/pages/index/index'
})
}
})
Page({
onLoad: function (options) { //参数options中包含了跳转到当前页面时所携带的参数信息
console.log(options);
}
})
2. 网络
常用:wx.request
-
发起 HTTPS 网络请求,就是ajax请求
小程序为保证请求安全,要求所有的请求地址都必须是定义在合法域名列表中的域名地址
具体的要求可参考 https://developers.weixin.qq.com/miniprogram/dev/framework/ability/network.html -
请求地址必须是 合法域名地址,可以由开发者自行配置,微信会进行审核(服务器域名请在 「小程序后台-开发-开发设置-服务器域名」 中进行配置)
-
请求地址必须是 HTTPS 协议,加密,安全
在开发环境下,可以关闭合法校验(可以先用来测试再配置合法域名)
- 详情——>本地设置——>不校验合法域名…
- 该方式只有微信开发工具下有效,在生产环境下或在微信中预览时无效
<!--.wxml文件-->
<!-- wx.request -->
<view class="title">wx.request</view>
<button type="primary" bindtap="sendAjax">发送Ajax请求</button>
Page({
sendAjax(){
wx.request({
url: 'https://m.douban.com/rexxar/api/v2/subject_collection/movie_showing/items',
data:{
start:0,
count:6
},
method:'GET', //请求方式必须为大写字母
success: res => {
console.log(res.data);
},
fail: err => {
console.log(err);
}
})
}
})
3. 界面
常用:
- wx.showToast 显示消息提示框
类似的还有:
- wx.showModal 显示模态对话框
- wx.showLoading
- wx.hideToast
Page({
goLogs(){
wx.navigateTo({
url: '/pages/logs/logs?id=1002&name=alice'
})
},
goIndex(){
wx.switchTab({
url: '/pages/index/index'
})
},
sendAjax(){
wx.request({
url: 'https://m.douban.com/rexxar/api/v2/subject_collection/movie_showing/items',
data:{
start:0,
count:6
},
method:'GET', //请求方式必须为大写字母
success: res => {
console.log(res.data);
wx.showToast({
title: '请求成功', //最多显示7个汉字
icon:'success', //取值只有: success、loading、none
duration:3000
})
},
fail: err => {
console.log(err);
}
})
}
})
4. 数据缓存
每个微信小程序都可以有自己的本地缓存
- wx.setStorage / wx.setStorageSync
- wx.getStorage / wx.getStorageSync
- wx.removeStorage / wx.removeStorageSync
- wx.clearStorage / wx.clearStorageSync
<!--.wxml文件-->
<!-- 数据缓存 -->
<view class="title">数据缓存</view>
<button type="primary" bindtap="doStorage">操作缓存</button>
//.js文件
Page({
doStorage(){
wx.setStorage({
data: {
name:'tom',
age:18,
height:180.5
},
key: 'user',
})
// wx.setStorageSync('user', {
// name:'tom',
// age:18,
// height:180.5
// })
//var user = wx.getStorageSync('user');
//console.log(user); //key不存在时,返回空字符串
}
})
注:添加到缓存中的数据可在调试器的Storage选项卡中查看
5. 开放接口
如果想要获取小程序用户的相关信息,必须通过显示提示的方式获得用户的主动授权才行
常用:wx.getUserInfo
- 获取用户信息,该接口必须是在用户已经授权的情况下调用
- 使用
<button open-type="getUserInfo" bindgetuserinfo=""></button>
进行授权操作 - 其他的授权使用wx.authorize接口向用户发起授权请求获得
- 只需要一次授权,授权后可以直接获取用户信息,无需再授权
类似的还有:
- wx.getSetting 获取用户的当前设置,可以查看用户授权的信息
- wx.authorize 向用户发起授权请求
- wx.login 调用接口获取登录凭证(code)。通过凭证进而换取用户登录态信息,包括用户的唯一标识(openid)及本次登录的会话密钥(session_key)等
//app.js文件
App({
onLaunch:function(options){
//直接获取时可能未授权,此时会失败,所以一般会先判断是否授权
// wx.getUserInfo({
// success: res => {
// console.log(res);
// },
// fail: () => {
// console.log('获取用户信息失败');
// }
// })
//获取用户的当前设置,判断是否授权
wx.getSetting({
success: res => {
//判断是否授权用户信息
if(res.authSetting["scope.useInfo"]){
//已授权时再调用wxwx.getUserInfo接口
wx.getUserInfo({
success: res => {
this.userInfo = res.userInfo;
//由于getUserInfo是异步请求,可能会在page.onload之后才返回数据
if(this.userInfoReadyCallback){
this.userInfoReadyCallback(res);
}
}
})
}
}
})
},
userInfo:null,
})
//api.wxml文件
<!--
开放接口
-->
<view class="title">开放接口</view>
<button wx:if='{{ !userInfo }}' type="primary" open-type="getUserInfo" bindgetuserinfo="getUserInfo">授权登录</button>
<block wx:else>
<image src="{{ userInfo.avatarUrl }}" class="user-img"></image>
<view class="user-nickName">{{ userInfo.nickName }}</view>
</block>
//api.js文件
const app = getApp();
Page({
data:{
userInfo:null
},
onLoad(){
//获取全局数据中的userInfo
if(app.userInfo){
this.setData({
userInfo: app.userInfo
});
}else{
//由于getUserInfo是异步请求,可能会在page.onload之后才返回数据,
//所以在获取到授权信息后进行方法回调,将授权信息传给page
app.userInfoReadyCallback = res => {
this.setData({
userInfo: res.userInfo
});
};
}
},
getUserInfo(e){
console.log(e);
this.setData({
userInfo: e.detail.userInfo
});
//将用户信息存储到全局数据
app.userInfo = e.detail.userInfo;
}
})
八、模块化
基于node实现模块化,可以进行接口功能的统一定义
- module.exports
- require
参考 https://developers.weixin.qq.com/miniprogram/dev/reference/api/module.html
//定义模块内容并向外暴露
const sayHello = function(name=''){
return '您好:$(name)';
}
const sayGoodbye = function(name=''){
return '再见:$(name)';
}
module.exports = {
sayHello,
sayGoodbye
}
//导入模块
const common = require('../../modules/common.js');
Page({
onReady(){
console.log(common.sayHello('tom'));
console.log(common.sayGoodbye('tom'));
}
})