携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第19天,点击查看活动详情
网络请求
微信提供了专属的API接口,用于网络请求: wx.request(Object object)
Page({
// 一般在onLoad中发送一些网络数据
onLoad() {
// 发送网络请求 可以使用微信内置api -> wx.request
// 参数为一个配置对象,配置对象中的url是必传的
// url必须是在微信后台白名单中的地址,或者在测试的时候关闭地址校验
wx.request({
url: 'http://api.example.com/api/home/houselist',
// data用于设置参数
// 无论是post请求的参数还是get请求的参数都设置在data配置项中
data: {
page: 1
},
// 成功时候的回调
// 写成箭头函数是因为方面内部在调用this.setData的时候可以使用正确的this
success: res => {
console.log(res.data.data)
},
fail: err => console.log(err)
})
}
})
简单封装
import { BASE_URL, TIME_OUT } from './env'
class API {
#BASE_URL = ''
#TIME_OUT = 10000
constructor(BASE_URL, TIME_OUT) {
this.#BASE_URL = BASE_URL
this.#TIME_OUT = TIME_OUT
}
// 传入options是为了方便进行更多的配置,例如 header
request(url, data = {}, options = { method: 'get' }) {
return new Promise((resolve, reject) => {
wx.request({
url: new URL(url, this.#BASE_URL).href,
timeout: this.#TIME_OUT
data,
...options,
success: res => {
resolve(res.data)
},
fail: reject
})
})
}
get(url, query, options = {}) {
return this.request(url, query, {
...options,
method: 'get'
})
}
post(url, data, options = {}) {
return this.request(url, data, {
...options,
method: 'post'
})
}
}
export default new API(BASE_URL)
使用
// 小程序在引入外部模块的时候,不支持以/开头的绝对路径
// 也不支持自动查找index文件,只支持省略后缀名
import api from '../../utils/api'
Page({
data: {
homeList: [],
page: 1
},
onLoad() {
this.fetchList()
},
onReachBottom() {
this.data.page += 1
this.fetchList()
},
async fetchList() {
try {
const res = await api.get('/home/houselist', { page: this.data.page ?? 1 })
this.setData({
homeList: [...this.data.homeList, ...res.data]
})
} catch(e) {
console.error(e.message)
}
}
})
域名配置
每个微信小程序需要事先设置通讯域名,小程序只可以跟指定的域名进行网络通信
服务器域名请在 「小程序后台 - 开发 - 开发设置 - 服务器域名」 中进行配置,配置时需要注意
- 域名只支持 https (wx.request、wx.uploadFile、wx.downloadFile) 和 wss (wx.connectSocket) 协议
- 域名不能使用 IP 地址(小程序的局域网 IP 除外)或 localhost, 且域名必须经过 ICP 备案
- 可以配置端口, 但请求的时候必须携带端口号,如果没有配置端口,则在请求的时候,不可以配置端口号,即使是默认的也不可以
弹窗
小程序中展示弹窗有四种方式: showToast、showModal、showLoading、showActionSheet
wx.showToast({
title: 'toast',
icon: "success",
duration: 3000
})
showLoading
的功能和showToast是类似的,其相当于设置了icon的值为loading的toast
只不过showModal的关闭是通过duration属性,而showLoading需主动调用 wx.hideLoading 才能关闭提示框
wx.showModal({
title: '我是title',
content: '我是内容',
success: res => {
if (res.cancel) {
console.log('用户退出了弹框')
}
if (res.confirm) {
console.log('用户点击了确定')
}
},
fail: err => console.log(err)
})
wx.showActionSheet({
itemList: ['从相册中选取', '拍照'],
// 具体点击了那一项 可以通过res.tapindex来获取
success: res => console.log(res),
fail: err => console.log(err)
})
分享
分享是小程序扩散的一种重要方式,小程序中有两种分享方式:
- 点击右上角的菜单按钮,之后点击转发
- 点击某一个按钮,直接转发
监听用户点击页面内转发按钮(button 组件 open-type="share")或右上角菜单“转发”按钮的时
可以通过 onShareAppMessage方法自定义转发内容,此事件处理函数需要 return 一个 Object,用于自定义转发内容
Page({
onShareAppMessage() {
return {
title: '设置分享的标题,默认是小程序名',
path: '/pages/profile/profile',
imgUrl: 'https://i1.hdslb.com/bfs/face/7c409a397356632362171fd6a25a8ed44f064e40.jpg'
}
}
})
获取信息
获取设备信息
我们可以通过getSystemInfo方法获取用户当前设备信息,用于收集设备信息或者进行一些适配工作
wx.getSystemInfo({
// res.screenHeight --- 手机的屏幕高度
// res.windowHeight -- 小程序可视窗口的高度
// 小程序的可视窗口 = 屏幕高度 - 导航栏高度 - 状态栏高度
success: res => console.log(res),
})
获取地址位置信息
可以通过getLocation方法,获取用户的位置信息,以方便给用户提供相关的服务
对于用户的关键信息,需要获取用户授权后才能获得
App.json
{
"permission": {
"scope.userLocation": {
// 向用户申请授权时候的描述信息
// 授权是授权给appid的,一个小程序对应着一个appid
// 也就意味着,用户只要授权一次即可,下次再进小程序就都不需要再次授权
"desc": "获取用户地址位置"
}
}
}
page.js
wx.getLocation({
// 只有用户授权后,小程序才可以获取用户地理位置
success: res => console.log(res),
})
设置页面title
// 动态设置NavigationBar的title
wx.setNavigationBarTitle({
title: '测试',
})
存储
在开发中,某些常见我们需要将一部分数据存储在本地:比如token、用户信息等, 小程序提供了专门的Storage用于进行本地存储
同步存取数据的方法:
-
wx.setStorageSync(string key, any data)
-
wx.getStorageSync(string key)
-
wx.removeStorageSync(string key)
-
wx.clearStorageSync()
// 小程序中的storage 的key值必须是字符串
// 但是小程序中的value值是any类型,也就是任意类型都可以被存储
// 添加
wx.setStorageSync('name', 'Klaus')
// 获取
console.log(wx.getStorageSync('name'))
// 移除具体某一项
wx.removeStorageSync('name')
// 清空storage
wx.clearStorageSync()
异步存储数据的方法:
- wx.setStorage(Object object)
- wx.getStorage(Object object)
- wx.removeStorage(Object object)
- wx.clearStorage(Object object)
所有的异步操作获取值都需要通过success属性监听获取,错误信息也需要通过fail属性来进行监听
自小程序V2.21.3开始,在异步存储数据API中可以对存储的数据进行加密操作,同步存储数据方法不可以
// 存储
wx.setStorage({
key: 'name', // key
data: 'Klaus', // value
encrypt: true, // 对存储的数据进行加密
success: () => {
// 获取
wx.getStorage({
key: 'name', // key
// 如果存储的数据是加密的,那么获取数据的时候 也必须开启encrypt 已进行正确的加密和解密操作
// 如果存储的数据没有加密,获取数据的时候,是不可以开启encrypt的, 因为此时对明文数据进行解密操作会失败
encrypt: true,
success: res => console.log(res),
fail: err => console.log(err)
})
}
})
跳转
界面的跳转有两种方式:通过navigator组件 和 通过wx的API跳转
在小程序中 和浏览器类似,每开启一个新的页面,会在小程序的页面栈
中压入一个新的页面,以便于进行页面的前进和回退
api方式进行页面跳转
方法 | 说明 |
---|---|
wx.switchTab | 跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面 |
wx.reLaunch | 关闭所有页面,打开到应用内的某个页面 即清空页面栈,并加入当前页 |
wx.redirectto | 关闭当前页面,跳转到应用内的某个页面 相当于router.replace |
wx.navigateTo | 保留当前页面,跳转到应用内的某个页面 但是不能跳到 tabbar 页面 |
wx.navigateBack | 关闭当前页面,返回上一页面或多级页面 |
navigateTo
当前页面
wx.navigateTo({
// 如果我们希望向另一个页面传递数据的时候
// 可以通过query参数的形式进行传递
url: '/pages/shop/shop?name=Klaus&age=23',
})
跳转过去的页面
Page({
// 在前一个页面传入的参数可以通过onLoad方法的参数获取到
onLoad(option) {
console.log(option.query)
}
})
navigateBack
// navigateBack方法可以不传配置对象
// 在navigateBack方法的配置参数中可以设置delta属性来控制页面回退数
// delta的默认值为1, 也就会回退一个页面
// delta的值为0或者负数的时候,会默认失效,采用默认值
wx.navigateBack()
数据传递
很多时候在在界面跳转过程中我们需要相互传递一些数据
- 首页 -> 详情页:使用URL中的query字段
- 详情页 -> 首页:在详情页内部拿到首页的页面对象,直接修改数据
详情页 -> 首页 数据传递方式一
Page({
// 在页面卸载事件中进行数据传递是为了保证
// 无论是通过按钮点击返回 还是通过小程序导航栏自带返回按钮返回
// 都可以向对应组件传递对应数据
onUnload() {
// getCurrentPages方法可以获取到这个页面调用栈中所有的页面
const pages = getCurrentPages()
// 拿到上一个页面数据
const prePage = pages[pages.length - 2]
// 向上一个页面传递所需要的数据
prePage.setData({
msg: {
name: 'Klaus',
age: 23
}
})
}
})
详情页 -> 首页 数据传递方式二
早期数据的传递方式只能通过上述的方式来进行,在小程序基础库 2.7.3 开始支持events参数,也可以用于数据的传递
首页
Page({
data: {
msg: {}
},
handleTap() {
wx.navigateTo({
url: '/pages/shop/shop',
// 通过events属性添加对应的事件 -- 有点类似于事件总线
events: {
// 使用箭头函数,以便于内部可以获取正确的this
customEvent: payload => {
this.setData({
msg: payload
})
},
triggerEvent: payload => {
console.log(payload)
}
},
success(res) {
// 主动向下一个页面传递对应的数据
res.eventChannel.emit('triggerEvent', {
name: 'triggerEvent'
})
}
})
}
})
详情页
Page({
onLoad() {
const events = this.getOpenerEventChannel()
// 监听对应的页面,以获取上一个页面传递过来的数据
events.on('triggerEvent', res => console.log(res))
},
onUnload() {
// 获取上一个页面的事件总线
const events = this.getOpenerEventChannel()
// 触发自定义事件
events.emit('customEvent', {
name: 'Klaus',
age: 23
})
}
})
naviagtor组件
navigator组件主要就是用于界面的跳转的,也可以跳转到其他小程序中
<!--
navigator 是一个块级组件
url属性 决定了需要跳转到哪里
open-type 跳转方式 和 api中四种小程序跳转方式是一一对应的
open-type 的默认值是 navigate
-->
<navigator url="/pages/shop/shop?name=Klaus&age=23">前进</navigator>
<navigator open-type="navigateBack">返回</navigator>
登录
为了增加用户的粘性和产品的停留时间,我们往往需要用户在应用中进行登录
而小程序是依赖于微信这个宿主环境的,所以我们可以借助微信已经登录的环境
实现静默登录,也就是什么操作都不执行,直接实现登录行为
在小程序中,可以通过openid和unionid来识别用户身份
分类 | 说明 |
---|---|
openid | 用户针对每个公众号或小程序等应用会产生一个安全的OpenID 在小程序中,openID是小程序的普通用户的一个唯一的标识,只针对当前的小程序有效 在公众号中openID是公众号的普通用户的一个唯一的标识,只针对当前的公众号有效 |
unionid | 同一个微信开放平台帐号下,用户的 UnionID 是唯一的 同一用户,对同一个微信开放平台下的不同应用,unionid是相同的 如果开发者拥有多个移动应用、网站应用、和公众帐号(包括小程序),可通过 UnionID 来区分用户的唯一性 |
多平台账号共享
如果希望用户在小程序中登录后进行的操作,可以在网页端或移动端同时进行同步
就希望其它平台的账号程序和小程序中的账号实现关联绑定
实现方式是账号绑定或手机号绑定
但无论那种实现方式 都需要用户在小程序静默登录后,在手动输入账号密码或手机号短信进行登录
以将多平台账号进行关联
getCode
export function getCode() {
return new Promise((resolve, reject) => {
// 通过调用wx.login方法可以获取到对应的code
wx.login({
timeout: 10000,
success(res) {
resolve(res.code)
},
fail(err) {
reject(err)
}
})
})
}
业务逻辑
import { loginApi } from './utils/api'
import { getCode } from './utils/login'
App({
// 如果在进入小程序的时候就需要登录的话,可以在onShow生命周期中完成
// 如果需要在某一个组件中触发对应登录流程的时候,可以在组件的onLoad生命周期中完成
async onShow() {
const token = await this.login()
console.log(token)
},
// /auth
async login() {
const loginToken = wx.getStorageSync('token')
if (loginToken && await this.checkTokenAuth(loginToken)) {
return loginToken
}
const code = await getCode()
const { token } = await loginApi.post('/login', {
code
})
wx.setStorageSync('token', token)
return token
},
async checkTokenAuth(token) {
const { message } = await loginApi.post('/auth', {}, {
header: {
token
}
})
return message === '已登录'
}
})