- 微信小程序-封装请求API——promise方式
目录 第一步:在app.js同级目录下,创建一个文件夹 第二步:封装wx.request方法成promise对象 第三步:页面中引用封装的请求API 1.设置基础请求路径 2.解构传入的参数 3.根据不同的url接口添加不同的header 4.添加请求发起时页面loading效果 完整的封装的API 的 js文件 微信小程序原生的请求API就是wx.request [代码]wx.request({ url: 'example.php', //仅为示例,并非真实的接口地址 data: { x: '', y: '' }, header: { 'content-type': 'application/json' // 默认值 }, success (res) { console.log(res.data) } }) [代码] 有时候不能很好的适配我们的开发需求,比如我们要加一些基础url路径、请求前后的loading效果、不同接口名称下的header。而且,在success回调方法里写请求成功后的操作,看起来代码不太清晰。接下来讲一下封装的逻辑,完整代码放在最后。 第一步:在app.js同级目录下,创建一个文件夹 [图片] 在utils文件夹里新建一个service.js文件,用来放封装的wx.request方法 第二步:封装wx.request方法成promise对象 使用promise对象能很好的解决回调地狱,在.then(res=>{}).catch(err=>{})中能很清晰地看出代码的逻辑 [代码]export const 返回出去的方法名 = (parmas) => { // 返回一个promise对象 return new Promise((resolve, reject) => { wx.request({ url: parmas.url, //仅为示例,并非真实的接口地址 data:parmas.data, header: { 'content-type': 'application/json' // 默认值 }, success: (res)=> { // 请求成功,就将成功的数据返回出去 resolve(result) }, fail: (err) => { reject(err) }, }) }) } [代码] 注意:success: (result) => {} 使用箭头函数,防止出现this指向错误 这样,就算是封装了一个最简单、最基础(简陋)的请求API了,在需要使用这个方法的页面的js文件中,引入它 第三步:页面中引用封装的请求API [代码]/** * 小程序中要引用方法,哪个页面要用,就在哪个页面引入 */ import { cjRequest } from "../../utils/service"; Page({ /** * 页面的初始数据 */ data: { .......... .......... getGoodsList () { //因为返回的是promise对象,所以通过.then来获取resolve出来的请求成功的返回数据 cjRequest({ url: "https://xxxtest/goods/search", data: this.QueryParams }) .then((res) => { console.log(res); }) } [代码] 现在,来详细扩展一下封装的请求API 1.设置基础请求路径 [代码]// 基础url const baseUrl = "https://xxxtest" [代码] 这样,就可以简化调用这个方法时url的参数内容了,也方便统一修改开发环境地址、生产环境地址 [代码]// url: "/goods/search" ==》 url中不用再写前面的一长串了 cjRequest({ url: "/goods/search", data: this.QueryParams }).then((res) => { console.log(res); }) [代码] 2.解构传入的参数 我们可以通过ES6中的扩展运算符,将传入到封装方法里的参数直接全部解构出来,不用再一个个获取赋值给对应的键值对了 …parmas 直接解构出传入的参数 [代码]export const 返回出去的方法名 = (parmas) => { //设置基础请求头 const baseUrl = "https://xxxtest" // 返回一个promise对象 return new Promise((resolve, reject) => { /** * ...parmas ===>就是将传进来的参数扩展开,一行行展示在这里面 * 比如:传进来 * { * url:'xx', * data:{key1:val1,key2:val2} * } * 那么通过 ...parmas 就会把这些内容展示到这里了 */ wx.request({ ...parmas, // 注意,此行必须放在 ...parmas 之下,才能覆盖其解构出的,传入的url:xxx参数 url: baseUrl + parmas.url, success: (res)=> { // 请求成功,就将成功的数据返回出去 resolve(result) }, fail: (err) => { reject(err) }, }) }) } [代码] 3.根据不同的url接口添加不同的header header中的Authorization字段一般存储token,用来做身份验证,但有些请求不需要携带token,所以这个封装的API中需要能根据传入的url来判断什么时候该给请求添加上token,什么时候不用可以添加。 [代码]``` export const 返回出去的方法名 = (parmas) => { /** * 根据不同的url接口,来设置不同的header请求头 ** 判断 url中是否带有 /my/ 请求的是私有的路径 带上header token ** { ...parmas.header } ==> 先解构出传进来的header对象,然后再往这个对象里面添加 Authorization字段数据,这样即使有传入header的其他字段也能保留下来 * 如果传入的parmas参数中没有header,那myHeader就是个空的对象 {} 因为啥都没有 */ let myHeader = { ...parmas.header }; //通过includes方法查找字符串中是否包含指定内容,进而判断是否要添加token if (parmas.url.includes("/neddToken/")) { // 往myHeader这个对象里插入键值对 带上Storage中存储的token myHeader["Authorization"] = wx.getStorageSync("token"); } //设置基础请求头 const baseUrl = "https://xxxtest" // 返回一个promise对象 return new Promise((resolve, reject) => { /** * ...parmas ===>就是将传进来的参数扩展开,一行行展示在这里面 * 比如:传进来 * { * url:'xx', * data:{key1:val1,key2:val2} * } * 那么通过 ...parmas 就会把这些内容展示到这里了 */ wx.request({ ...parmas, // 注意,此行必须放在 ...parmas 之下,才能覆盖其解构出的,传入的url:xxx参数 url: baseUrl + parmas.url, /** * !可以设置上默认的content-type,然后再扩展出传入的myHeader,如果传入的myHeader 为空,那header就还是默认的content-type一个键值对 * !{ 'content-type': 'application/json', ...myHeader } ==》 扩展出myHeader这 个对象中的键值对; */ header: { 'content-type': 'application/json', ...myHeader }, success: (res)=> { // 请求成功,就将成功的数据返回出去 resolve(result) }, fail: (err) => { reject(err) }, }) }) [代码] } [代码][代码] 此时,在使用这个封装的API的时候,就可以对header进行设置了,例如: [代码] ``` cjRequest({ url: '/neddToken/home/swiperdata', // 使用的时候也可以传入一些header的字段 header: { 'content-type': 'application/json', 'Date': 'Tue, 15 Nov 2021 08:12:31 GMT' }, method: 'GET', }).then((result) => { console.log(result) }) [代码] [代码][代码] 此时,因为请求url中含有【neddToken】,就会在header中插入token [图片] 此时,这个请求的header中就会添加上token(也就是Authorization这个字段了) [图片] 4.添加请求发起时页面loading效果 当页面在加载数据的时候,最好要有一个loading的提示,同时有遮罩,防止用户乱点 所以,就需要在封装的API中加入微信小程序的wx.showLoading遮罩层了 [代码] // 显示加载中loading效果 wx.showLoading({ title: "加载中", mask: true //开启蒙版遮罩 }); ... ... // 关闭正在等待loading效果 wx.hideLoading(); [代码] 如果直接在封装的API的开始加上loading,在请求结束加上隐藏loading效果,那乍看一下,好像没错,但是细想一下,如果一个页面同时触发了多个请求呢?比如打开一个页面,同时加载多个模块,需要从不同的接口请求数据,那就会使用多次这个封装的API。 此时,就会出现,第一个请求结束,直接关闭了loading效果,而后面几个请求就没有loading效果的遮罩了。 所以,需要在封装的js文件中设置一个全局变量,每次调用这个封装的文件时,就对这个变量++,每次请求结束,返回数据出去的时候,就对这个变量–,最后判断一下这个变量是否为0(也就是所有请求的结束了),在决定是否关闭loading效果 [图片] [图片] 完整的封装的API 的 js文件 [代码]// 同时发送异步代码的次数 let ajaxTimes = 0; export const cjRequest = (parmas) => { // 当有地方调用请求方法的时候,就增加全局变量,用于判断有几个请求了 ajaxTimes++; // 显示加载中loading效果 wx.showLoading({ title: "加载中", mask: true //开启蒙版遮罩 }); /** * 根据不同的url接口,来设置不同的header请求头 ** 判断 url中是否带有 /my/ 请求的是私有的路径 带上header token ** { ...parmas.header } ==> 先解构出传进来的header对象,然后再往这个对象里面添加Authorization字段数据,这样即使有传入header的其他字段也能保留下来 *? 如果传入的parmas参数中没有header,那myHeader就是个空的对象 {} 因为啥都没有 */ let myHeader = { ...parmas.header }; if (parmas.url.includes("/neddToken/")) { // 往myHeader这个对象里插入键值对 带上Storage中存储的token myHeader["Authorization"] = wx.getStorageSync("token"); } // 基础url const baseUrl = "https://api-hmugo-web.itheima.net/api/public/v1" return new Promise((resolve, reject) => { /** * ...parmas ===>就是将传进来的参数扩展开,一行行展示在这里面 * 比如:传进来 * { * url:'xx', * data:{key1:val1,key2:val2} * } * 那么通过 ...parmas 就会把这些内容展示到这里了 */ wx.request({ ...parmas, // 注意,此行必须放在 ...parmas 之下,才能覆盖其传入的url:xxx参数 url: baseUrl + parmas.url, /** * !可以设置上默认的content-type,然后再扩展出传入的myHeader,如果传入的myHeader为空,那header就还是默认的content-type一个键值对 * !{ 'content-type': 'application/json', ...myHeader } ==》 扩展出myHeader这个对象中的键值对; */ header: { 'content-type': 'application/json', ...myHeader }, success: (result) => { // 请求成功,就将成功的数据返回出去 resolve(result) }, fail: (err) => { reject(err) }, // 不管请求成功还是失败,都会触发 complete: () => { /** * !loading效果同时被多个请求触发是可以显示一个的,但是关闭loading一旦被第一个请求完成后关闭,后面的请求触发的loading效果就没了 * !所以,需要通过全局设置一个变量,来监听同时触发了几个请求,当最后一个请求完成后,再关闭loading * ?每次结束请求后,就减少全局变量,当为0时,就表示这是最后一个请求了 */ ajaxTimes--; // 此时就可以关闭loading效果了 if (ajaxTimes === 0) { // 关闭正在等待loading效果 wx.hideLoading(); } } }); }) } [代码] 如果需要按照原生微信请求的格式来封装(调用时要传各种方法、参数),请参考: 微信小程序-封装请求API——原生方式_五速无头怪的博客-CSDN博客[图片]https://blog.csdn.net/black_cat7/article/details/120697607 参考:黑马微信商场小程序 黑马程序员微信小程序开发前端教程_零基础玩转微信小程序_哔哩哔哩_bilibili[图片]https://www.bilibili.com/video/BV1nE41117BQ?p=3
2023-10-18 - miniprogram-file-uploader支持多个new Uploader实例吗?
在循环上传文件的时Uploader中的fileName始终为一个值,未根据map遍历的结果传递 [图片] 一个视频,一个图片 [图片] 文件的唯一标识是不同的,但是fileName确实重复的 [图片][图片]
2022-09-28 - 一个组件解决隐私授权:小程序用户隐私保护授权弹窗组件
项目链接:https://github.com/94xy/miniprogram-privacy 效果预览: [图片] 使用方法: 1、复制项目 [代码]component[代码] 文件夹中的 [代码]privacy[代码] 文件夹到小程序项目中的组件目录; 2 、在 page.json 中引入组件 { "usingComponents": { "Privacy": "/component/privacy/privacy" } } 3 、在 page.wxml 中使用组件,需要授权显示弹窗,不需要不显示 <Privacy /> 4 、可以在所有使用了隐私接口的页面都加上该组件,授权一次之后使用所有隐私接口不再需要授权 跳过阅读: 可以不阅读就点击“同意”按钮 <Privacy skipRead="{{true}}" /> 流程: 页面显示时使用 wx.getPrivacySetting 接口查询是否需要授权,需要授权则显示组件;用户点击“拒绝”直接退出小程序,用户点击“同意”关闭弹窗并同步给微信,之后可以正常使用所有隐私接口。 注意事项: 2023 年 9 月 15 号之前,默认不会启用隐私相关功能,所以检测不到需要弹窗的情况,可以在 app.json 中配置 "__usePrivacyCheck__": true 之后,接口才可以检测到是否需要弹窗。个人实际情况:我在开发者工具中配置了 "__usePrivacyCheck__": true ,needAuthorization 无论如何返回的都是 false,但在真机模拟的情况下可以返回 true自动打开隐私保护指引界面需在「小程序管理后台」配置《小程序用户隐私保护指引》,官方用户隐私保护指引填写说明。 取消授权: 微信中「微信下拉-最近-最近使用的小程序」中删除小程序可取消授权。 开发者工具中「清除模拟器缓存-清除授权数据」可取消授权。
2023-08-28 - 小程序隐私保护指引设置最优的无感方案(需要有用户登录流程)
很简单,把 <button open-type="agreePrivacyAuthorization" /> 做成登录页中常见并且需要勾选的【已阅读并同意《用户协议》、《隐私协议》】的那个radio就行了 <template> <view> <view class="flex"><text>手机号</text><text>18612341234</text></view> <view class="flex"><text>短信验证码</text><text>1234</text></view> <button v-if="!isChecked" @click="handlegetPhonenumberFake">获取手机号(假)</button> <button v-else open-type="getPhoneNumber" @getphonenumber="handlegetPhonenumber"> 获取手机号(真)</button> <view class="flex"> <button class="radio" :class="{ current: isChecked }" open-type="agreePrivacyAuthorization" @click="handleClick" /> 已阅读并同意《隐私协议》、《用户协议》 </view> <button @click="handleLogin">登录</button> </view> </template> <script> export default { data() { return { isChecked: false }; }, mounted() {}, methods: { handlegetPhonenumberFake() { uni.showToast({ title: '请先阅读并勾选隐私协议、用户协议', icon: 'none', duration: 2000, }); }, handlegetPhonenumber(event) { if (this.isChecked) { const { iv, code } = event.detail; console.log('iv', iv); console.log('code', code); } else { uni.showToast({ title: '请先阅读并勾选隐私协议、用户协议', icon: 'none', duration: 2000, }); } }, handleClick() { this.isChecked = !this.isChecked; }, handleLogin() { if (this.isChecked) { // 登录业务代码... // 登录成功后返回页面 uni.navigateBack(); } else { uni.showToast({ title: '请先阅读并勾选隐私协议、用户协议', icon: 'none', duration: 2000, }); } }, }, };
2023-09-04 - 微信公众号栏目里跳转小程序,如何链接到不同的小程序页面?
小程序已经关联,但是在制作公众号跳转小程序时,应该怎么样添加不同的小程序页面?百度了其他方法,但是在生成小程序路径的时候 不同的页面都是pages/index/index.html,应该怎么样解决这个问题呢?
2023-08-09 - 微信公众号模板消息跳转小程序,怎么把详情更换成相应的小程序头像和名称?
[图片][图片] 详情怎么样能显示小程序头像和名称?我之前有官方回答过同样的问题,使用OPENTM前缀的模板就能显示,但我用了下图的模板,还是没显示呢。 [图片]
2022-12-28 - 小程序跳转微信公众号?
同主体小程序如何跳转公众号
2023-04-15