uniapp写小程序时常用的数据

449 阅读17分钟

小程序的启动和打包

通过HBuilderX

点击工具栏里的文件 -> 新建 -> 项目(快捷键Ctrl+N

image.png

完成后创建项目文件

右击pages页面,选择新建,选择目录,输入对应的文件名称,这样一个对应的文件就新建好了。

这个文件下这时是没有页面的

image.png

右击对应的文件,选择新建页面

image.png

在新弹出的页面中输入文件名称,如果勾选了右侧的同名目录,则会创建出一个index文件夹下,有一个index.vue文件

image.png

完成后点击pages.json文件,这个是uniapp的路由文件,点击yes,就可以把刚才创建的文件自动录入到这个路由中( 路由是自动导入的 )

image.png

打包

1.配置微信AppID 2.在HBuilderX工具栏,点击发行,选择小程序微信

image.png

通过vue-cli

vue3的js处理

npx degit dcloudio/uni-preset-vue#vite my-vue3-project  

克隆 `dcloudio/uni-preset-vue` 仓库的 `vite` 分支到本地 `my-vue3-project` 文件夹。

npx degit dcloudio/uni-preset-vue#vite-alpha my-vue3-project

克隆同一仓库的 `vite-alpha` 分支到 **已存在的 `my-vue3-project` 文件夹**。

** vue2的处理**


需要全局安装 vue-cli `npm install -g @vue/cli`

使用正式版(对应HBuilderX最新正式版) vue create -p dcloudio/uni-preset-vue my-project

** 运行、发布uni-app**

npm run dev:mp-weixin
npm run build:mp-weixin

tabBar的讲解

这个美团小程序下方红圈内的部分就是tabBar部分

image.png

很多小程序都有这部分,在pages.json部分 color:字体默认颜色

selectedColor:字体选中时的颜色

borderStyle:tabBar上边框的颜色

backgroundColor: tabBar背景色

pagePath:点击时页面的路径

iconPath:菜单图标路径

selectedIconPath:点击菜单后图标路径

text:菜单文字

"tabBar": {
		"color": "#535353",
		"selectedColor": "#0bb584",
		"borderStyle": "white",
		"backgroundColor": "#ffffff",
		"list": [{
			"pagePath": "pages/index/index",
			"iconPath": "static/resource/images/tab_index.png",
			"selectedIconPath": "static/resource/images/tab_index_seled.png",
			"text": "首页"
		}, {
			"pagePath": "pages/order/index",
			"iconPath": "static/resource/images/tab_pub.png",
			"selectedIconPath": "static/resource/images/tab_pub_seled.png",
			"text": "订单"
		},{
			"pagePath": "pages/user/index",
			"iconPath": "static/resource/images/tab_user.png",
			"selectedIconPath": "static/resource/images/tab_user_seled.png",
			"text": "我的"
		}]
	},

easycom自动导入引入和main注册

在使用 npm i @dcloudio/uni-ui 安装后,组件太多了,手动导入过于繁琐,设置自动导入

image.png

// pages.json
{       // 组件自动导入规则
	"easycom": {
                // 是否开启自动导入,查找components文件夹是否有uniapp的组件,有的话自动导入
		"autoscan": true,
                // 正则方式表达自定义组件匹配方式导入
		"custom": {
			// uni-ui 规则如下配置
			"^uni-(.*)": "@dcloudio/uni-ui/lib/uni-$1/uni-$1.vue"
		}
	},
	
	// 其他内容
	pages:[
		// ...
	]
}

在uniapp中,注册一个组件名称为compontens,在这个组件内的文件,其他文件使用时不需要引入就可以直接使用。这种方式为easycom引入

在main页面中,引入文件,在下方注册组件实例。也可以实现其他文件使用时不需要引入就可以直接使用

image.png

getSystemInfoSync和getCurrentPages().length,uni.navigateBack()

getSystemInfoSync可以根据不同的机型返回不同的数据,常用于页面适配

getCurrentPages获取页面站的数量,有时我们常常要返回页面,或者在不同页面的同一个位置显示不同的图片。 image.png

const pages = getCurrentPages()
	console.log(pages,'pages')

navigateBack 关闭当前页面,返回上一页面或多级页面。

switchTab

跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面,(注意这是跳转 tabBar页面专属的)。

uni.switchTab({url:'/pages/index/index'})

navigateTo 跳转到一个非 tabBar 页面。

在UniApp小程序中实现页面跳转

  1. 使用uni.navigateTo方法(保留当前页面,跳转到新页面)
// 在点击事件中调用
uni.navigateTo({
  url: '/pages/targetPage/targetPage'  // 目标页面路径
})

2. 使用uni.redirectTo方法(关闭当前页面,跳转到新页面,重新创建页面 → ❌ 数据丢失)

uni.redirectTo({
  url: '/pages/targetPage/targetPage'
})

3. 使用uni.switchTab方法(跳转到tabBar页面)

uni.switchTab({
  url: '/pages/tabPage/tabPage'  // 必须是已在pages.json中定义的tabBar页面
})

4. 使用uni.navigateBack()方法(关闭当前页面,跳转到新页面,数据存在)

uni.navigateBack({
  url: '/pages/targetPage/targetPage'
})
跳转方式         | 页面栈变化        | 栈深度    | 页面实例  | 数据保持 |
| ------------ | ------------ | ------ | ----- | ---- |
| navigateTo   | 添加新页面到栈顶     | ⬆️ 增加  | 新建    | -    |
| navigateBack | 移除栈顶页面       | ⬇️ 减少  | 恢复之前的 | ✅ 保持 |
| redirectTo   | 替换栈顶页面       | ➡️ 保持  | 重新创建  | ❌ 丢失 |
| reLaunch     | 清空所有页面,添加新页面 | ➡️ 变为1 | 重新创建  | ❌ 丢失

小程序跳转传参

1. wx.navigateTo 跳转 + url 传参(适合简单数据)

适用于传递 字符串、数字、简单对象(需转成 JSON)。

// 当前页面(跳转并传参)
wx.navigateTo({
  url: '/pages/detail/detail?id=123&name=test&data=' + encodeURIComponent(JSON.stringify({key: 'value'}))
})

新页面(detail)接收参数:

// detail.js
Page({
  onLoad(options) {
    const { id, name, data } = options; // 从url中解析
    const parsedData = JSON.parse(decodeURIComponent(data)); // 解析对象
    
    console.log(id);      // 输出: 123
    console.log(name);    // 输出: "test"
    console.log(parsedData); // 输出: {key: "value"}
  }
})

注意:

  • 参数会暴露在 URL 中,敏感数据不要用这种方式
  • 传递对象需用 JSON.stringify 和 encodeURIComponent 处理。

分包

一、多分包配置示例*

在 pages.json 中声明多个分包,每个模块独立成包:


{
  "subPackages": [
    {
      "root": "pages_power", // 充电模块分包
      "pages": [
        {"path": "index", "style": { /*...*/ }},
        {"path": "detail", "style": { /*...*/ }}
      ]
    },
    {
      "root": "pages_mall", // 商城模块分包
      "pages": [
        {"path": "home", "style": { /*...*/ }},
        {"path": "goods", "style": { /*...*/ }}
      ]
    },
    {
      "root": "pages_social", // 社交模块分包
      "pages": [
        {"path": "chat", "style": { /*...*/ }},
        {"path": "profile", "style": { /*...*/ }}
      ]
    }
  ]
}

* * *

### **二、多分包的核心优势**

1.  **按需加载**  
    用户只有访问对应模块时才会下载该分包资源,比如:

    -   访问 `/pages_power/index` → 下载 `pages_power` 分包
    -   访问 `/pages_mall/home` → 下载 `pages_mall` 分包

1.  **突破主包体积限制**

    -   主包限制:2MB(微信小程序)
    -   总分包限制:20MB(微信小程序)
    -   每个分包最大:2MB(建议控制在 1MB 内)

1.  **独立编译更新**  
    修改某个分包的代码后,只有该分包会重新编译,提升开发效率。

* * *

### **三、关键注意事项**

#### 1. 目录结构规范

text

复制

下载

├── pages # 主包页面 │ ├── home
│ └── ... ├── pages_power # 充电模块分包 │ ├── index.vue │ └── detail.vue ├── pages_mall # 商城模块分包 │ ├── home.vue │ └── ... └── pages_social # 社交模块分包 ├── chat.vue └── ...


#### 2. 跳转分包页面

必须使用**完整路径**(包含分包目录名):

javascript

复制

下载

// 正确 uni.navigateTo({ url: '/pages_power/index' })

// 错误(无法找到页面) uni.navigateTo({ url: '/index' })


#### 3. 共享资源处理

-   **组件/工具库**    如果多个分包需要共用组件/工具,建议:

    -   要么放在主包中(增加主包体积)
    -   要么在每个分包中单独存放(增加重复代码但减少主包压力)

-   **图片资源**    推荐使用网络图片或通过 `copy-webpack-plugin` 复制到分包目录。

#### 4. 预加载策略

通过 `preloadRule` 提前加载高频使用的分包(微信小程序专属):

json

复制

下载

{ "preloadRule": { "pages/home/home": { "network": "all", "packages": ["pages_mall"] // 访问首页时预加载商城分包 } } }


* * *

### **四、分包优化技巧**

1.  **合理划分模块**

    -   高频功能放主包(如首页、登录页)
    -   低频功能放分包(如设置页、帮助中心)

1.  **控制分包体积**  
    单个分包建议 ≤1MB,可通过以下方式优化:

    -   压缩图片资源
    -   移除未使用的组件
    -   使用小程序专用组件(如 `vant-weapp`1.  **依赖分析**  
    使用 `webpack-bundle-analyzer` 分析包体积:

    bash

    复制

    下载

    ```
    npm run build:mp-weixin --report
    ```

* * *

### **五、常见问题解决方案**

#### Q1:分包后出现文件找不到错误?

-   检查 `root` 和 `path` 的拼写
-   确认文件实际存在于对应目录

#### Q2:如何跨分包共享组件?

-   方案一:升级到 UniApp 3.5+ 使用 [easycom 自动引入](https://uniapp.dcloud.io/component/easycom.html)
-   方案二:将组件声明为 [全局组件](https://uniapp.dcloud.io/collocation/pages.html#globalstyle)

#### Q3:测试时如何验证分包加载?

在微信开发者工具中:

1.  打开「调试器 → Network」
1.  过滤 `.wxapkg` 请求
1.  切换页面观察分包下载情况

uni.login(OBJECT) 和globalData,getApp()

在uni.login中有接口调用成功的回调函数 success,和接口调用失败的回调函数 fail

image.png

封装完成后,为了在每个页面都可以使用,要在App.vue页面中,使用globalData,将数据放在其中。

image.png

调用的时候通过getApp()API应用实例,返回我们需要的实例

image.png

onShow、onLoad、onLaunch、onHide

onUnload() {
	// 返回上一页(包括侧滑返回、头部返回)时,若已选择证书则同步给上一页
	if (this.selectedCertificates && this.selectedCertificates.length > 0) {
		try {
			uni.$emit("updateCer", { key: this.selectedCertificates })
		} catch (error) {
			console.error("返回时数据传递失败:", error)
		}
	}
},
onBackPress() {
	// App/H5 端物理返回或手势返回时的兜底同步
	if (this.selectedCertificates && this.selectedCertificates.length > 0) {
		try {
			uni.$emit("updateCer", { key: this.selectedCertificates })
		} catch (error) {
			console.error("返回键数据传递失败:", error)
		}
	}
	return false
},

使用ts时的的uniapp的类型怎么解决呢

在uniapp开发时,使用的是js开发,这样在ts中就有类型问题,下载一个插件可以解决

npm i D @uni-helper/uni-ui-types

image.png

    "types": [
      "@dcloudio/types",
      "miniprogram-api-typings",
      "@uni-helper/uni-app-types",
      "@uni-helper/uni-ui-types"
    ]

onLaunch - 全局初始化

-   **作用域:**  `App` 中定义(app.js)

-   **触发时机:**  **整个小程序启动时**(冷启动)或从后台切到前台**且小程序未被销毁**时,**仅触发一次**(整个小程序生命周期中只执行一次)。

-   **主要用途:**

    -   初始化全局数据
    -   获取用户登录状态(`wx.login`    -   获取系统信息(`wx.getSystemInfo`    -   检查新版本(`wx.getUpdateManager`-   **注意:**  这是整个小程序最早执行的生命周期函数。无法获取页面级数据。

onLoad - 页面首次加载

-   **作用域:**  `Page` 中定义(页面的 .js 文件)

-   **触发时机:**  **页面首次加载时触发**(一个页面实例化时),**一次页面生命周期内只执行一次**(除非页面被销毁后重新创建)。

-   **参数:**  接收打开当前页面路径中的 `query` 参数(`options`)。

-   **主要用途:**

    -   接收路由参数(`options.query`    -   初始化页面专用数据(`this.setData`    -   根据参数发起页面特定的网络请求

-   **注意:**  这是页面级生命周期中最早执行的函数。

onShow - 页面显示/切入前台

-   **作用域:**

    -   **全局:**  在 `App` 中定义(`app.js`),表示**整个小程序**显示/切前台。
    -   **页面级:**  在 `Page` 中定义(页面的 .js 文件),表示**该特定页面**显示/切前台。

-   **触发时机:**

    -   **全局:**  小程序**启动时**(紧跟在 `onLaunch` 之后),或小程序从**后台切换到前台**时。

    -   **页面级:**

        -   页面**首次加载完成**后(紧跟在 `onLoad` 和 `onReady` 之后)。
        -   从其他页面**返回**该页面时(例如 `wx.navigateBack`)。
        -   小程序从**后台切换到前台**且当前显示的是该页面时。
        -**Tab页切换**回到该页面时。

-   **主要用途:**

    -   更新需要**实时刷新**的数据(如用户信息、计时器、位置信息)。
    -   每次页面展示时执行的逻辑(如统计页面曝光)。
    -   从后台恢复时检查状态(全局 `onShow`)。

-   **注意:**  `onShow` 在一个页面的生命周期内**可以多次触发**

onHide - 页面隐藏/切入后台

-   **作用域:**

    -   **全局:**  在 `App` 中定义(`app.js`),表示**整个小程序**隐藏/切后台。
    -   **页面级:**  在 `Page` 中定义(页面的 .js 文件),表示**该特定页面**隐藏/切后台。

-   **触发时机:**

    -   **全局:**  小程序**切到后台**时(用户点击右上角胶囊关闭、按Home键回桌面、切换到其他微信聊天窗口等)。

    -   **页面级:**

        -   使用 `wx.navigateTo``wx.redirectTo``wx.switchTab``wx.reLaunch` **离开当前页面**时。
        -   小程序**切到后台**且当前显示的是该页面时。
        -   从当前页面**跳转到新的 Tab 页**时。

-   **主要用途:**

    -   停止消耗资源的操作(如清除定时器、停止动画、暂停音乐播放)。
    -   保存临时状态。
    -   执行页面隐藏时的清理工作。

-   **注意:**  `onHide` 在一个页面的生命周期内**可以多次触发**

公共的css怎么设置

在App.vue中引入就行了

image.png

网络请求:uni.request uni.showLoading uni.getStorageSync('')

uni.showLoading:显示 loading 提示框, 需主动调用 uni.hideLoading 才能关闭提示框。

uni.getStorageSync(''):小程序的缓存

二次封装网络请求:使用uni.login调用登录的api,将登录的地址分切开前一部分,放在constructor实例 es6的class语法中,后一部分传递后,将两段代码拼接起来

class Utils {
	constructor(){
		this.baseUrl = 'https://code.itndedu.com/pz'
	}
	//获取用户信息
	getUserInfo() {
		// 调用登录的api
		uni.login({
			success:(res)=> {
				console.log(res)
				this.request({
					url:'/auth/wxLogin',
					data:{
						code:res.code
					},
					success:res=>{
						console.log(res,'res')
					}
				})
			}
		})
	}
	request(option = {
		// 在用户没有传option时默认的数据为false
		showLoading:false
	}) {
		// 判断url是否存在
		if(!option.url) {
			return false
		}
		if (option.showLoading) {
			this.showLoading()
		}
		// http://159.75.169.224:7300/pz/auth/wxLogin
		uni.request({
			url:this.baseUrl + option.url,
			data:option.data?option.data:{},
			header:option.header ? option.header:{},
			method:option.method? option.method:'GET',
			success:(response)=>{
				uni.hideLoading()
				// 后端返回的数据是异常的
				if(response.data.code != 10000){
					// 将失败的结果返回出去
					if(option.fail && typeof option.fail ==='function'){
						option.fail(response)
					}
				}else{
					// 将成功的结果返回
					if(option.success && typeof option.success ==='function') {
						option.success(response.data)
					}
				}
			},
			fail:response =>{
				uni.hideLoading()
				console.log(response)
			}
		})
	}
	// 创建加载的loading效果
	showLoading() {
		const isShowLoading = uni.getStorageSync('isShowLoading')
		if (isShowLoading) {
			uni.hideLoading()
			uni.setStorageSync('isShowLoading',false)
		}
		uni.showLoading({
			title:'加载中...',
			complete:function(){
				uni.setStorageSync('isShowLoading',true)
			},
			fail:function(){
				uni.setStorageSync('isShowLoading',false)
			}
		})
	}
}

export default new Utils()

uni.onuni.on和uni.emit

通过 uni.on创建的事件,可以通过uni.on创建的事件,可以通过uni.emit在全局任意一个位置触发

下面两段代码:通过 uni.on建立一个全局的响应式数据,uni.on建立一个全局的响应式数据,uni.emit触发后将{msg:'页面更新'}传递到uni.on中,uni.on中,uni.on接收后console.log('监听到事件来自 update ,携带参数 msg 为:' + data.msg);打印。

	uni.$on('update',function(data){
		console.log('监听到事件来自 update ,携带参数 msg 为:' + data.msg);
	})

	uni.$emit('update',{msg:'页面更新'})

uni.chooseAddress(OBJECT)和requiredPrivateInfos

	// 点击收件信息
	const onAddressChange = ()=>{
		uni.chooseAddress({
			success:res =>{
				console.log(res)
				order.address.userName = res.userName
				order.address.cityName = res.cityName
				order.address.countyName = res.countyName
				order.address.detailInfo = res.detailInfo
			},
			fail:res=>{
				console.log(res)
			}
		})
	}

注意,里面要配置requiredPrivateInfos

image.png

如果是使用uniapp的话则在这里配置对应的信息。

image.png

将链接转换成二维码

image.png

引入

import UQRCode from 'uqrcodejs'

原生js实现

image.png

uniapp实现

<canvas id="qrcode" canvas-id="qrcode" style="width: 300rpx;height: 300rpx;"></canvas>
				  // 获取uQRCode实例
				  const qr = new UQRCode();
				  // 设置二维码内容
				  qr.data = res.wx_code;
				  // 设置二维码大小,必须与canvas设置的宽高一致
				  qr.size = 150;
				  // 调用制作二维码方法
				  qr.make();
				  // 获取canvas上下文
				  const canvasContext = uni.createCanvasContext('qrcode'); // 如果是组件,this必须传入
				  // 设置uQRCode实例的canvas上下文
				  qr.canvasContext = canvasContext;
				  // 调用绘制方法将二维码图案绘制到canvas上
				  qr.drawCanvas();

image.png

后端返回的是二维码图片(URL 或 base64)的处理

后端返回的不一定是 短文本券码 可能是 二维码图片的 base64/URL

		// 判断是否是图片来源(http(s)地址 或 base64 图片)
		isImageSource(value) {
			if (!value || typeof value !== 'string') return false
			if (/^https?:\/\//i.test(value)) return true
			if (/^data:image\/(png|jpeg|jpg);base64,/i.test(value)) return true
			// 无前缀但很长的 base64 字符串也视为图片
			return value.length > 1000 && /^[A-Za-z0-9+/=]+$/.test(value)
		},
		// 将图片绘制到 canvas(支持网络图、dataURL、纯 base64)
		drawImageToCanvas(src, size) {
			const draw = (path) => {
				const ctx = uni.createCanvasContext("qrcode-img", this)
				ctx.clearRect(0, 0, size, size)
				ctx.drawImage(path, 0, 0, size, size)
				ctx.draw()
			}
			if (/^https?:\/\//i.test(src)) {
				uni.getImageInfo({
					src,
					success: (res) => draw(res.path),
					fail: (e) => {
						console.error('getImageInfo fail', e)
					}
				})
			} else if (/^data:image\/(png|jpeg|jpg);base64,/i.test(src)) {
				const base64Data = src.split(',')[1]
				const fsm = uni.getFileSystemManager && uni.getFileSystemManager()
				if (fsm && typeof wx !== 'undefined' && wx.env && wx.env.USER_DATA_PATH) {
					const filePath = `${wx.env.USER_DATA_PATH}/qrcode_${Date.now()}.png`
					fsm.writeFile({
						filePath,
						data: base64Data,
						encoding: 'base64',
						success: () => draw(filePath),
						fail: (e) => { console.error('writeFile base64 fail', e) }
					})
				}
			} else {
				// 可能是不带 dataURL 头的纯 base64 字符串
				const base64Data = src
				const fsm = uni.getFileSystemManager && uni.getFileSystemManager()
				if (fsm && typeof wx !== 'undefined' && wx.env && wx.env.USER_DATA_PATH) {
					const filePath = `${wx.env.USER_DATA_PATH}/qrcode_${Date.now()}.png`
					fsm.writeFile({
						filePath,
						data: base64Data,
						encoding: 'base64',
						success: () => draw(filePath),
						fail: (e) => { console.error('writeFile base64 fail', e) }
					})
				}
			}
		},

地图

1.在pages.json中添加一个数据

	"plugins": {
	    "routePlan": {
	      "version": "1.0.19",
	      "provider": "wx603853422" //注意,这里的微信id一定要是腾讯位置服务插件完成授权的
	    }
	},
        

要使用插件需要后台传递具体的坐标(经度,纬度)

	const map = (lng, lat) => {
		let x_pi = (3.141592653589793 * 3000) / 180;
		let x = lng - 0.0065;
		let y = lat - 0.006;
		let z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * x_pi);
		let theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * x_pi);
		let lngs = z * Math.cos(theta);
		let lats = z * Math.sin(theta);
		return {
			lng: lngs,
			lat: lats
		}
	}

@tap和@click的区别

相同点:在uniapp中两者同样是点击事件

不同点: @click是组件被点击时触发,会有约300ms的延迟(内置处理优化了); @tap是手指触摸离开时触发,没有300ms的延迟,但是会有事件穿透;

微信小程序打包流程

1.在uniapp中的manifest.json文件中微信小程序配置中要有对应的微信小程序AddId,如果是使用其他编辑器(vscode)打开,则要在源码视图中有微信小程序AppId

image.png

2.在开发时微信开发者工具使用时会点击不校验合法域名,将其取消,将后端地址改成已经上线的合法地址,

image.png

3.打开微信公共平台,找到管理/开发管理,点击修改

image.png 4.上面这些都完成后,点击发行 image.png

5.发版,点击上传,输入版本号,

image.png

image.png

6,版本管理,在微信公共平台上可以看见对应的版本

image.png

小程序的登录

在使用小程序的时候,微信是已经登录的,那么我们只需要让微信授权就可以了,成员要在开发者名单中,且将appid在开发者工具和uniapp微信小程序中配置好

必须的流程---1

1, 小程序登录的时候必须有wx.login 方法获取到用户的临时登录凭证 code。这个 code 是后续获取用户身份标识的关键。 wx.login({ success(res) { if (res.code) { // 将code发送到开发者服务器 } } });

2,encryptedData,通过@getphonenumber事件获取

3,iv,通过@getphonenumber事件获取 (注意:现在微信不再返回 encryptedData/iv,改为返回临时 code。后端需调用新接口:)

获取手机号

open-type="getPhoneNumber" @getphonenumber="ongetphonenumber"
注意:一定要添加open-type="getPhoneNumber",不然@getphonenumber="ongetphonenumber"无法触发

image.png

必要的流程---2

 1,使用wx.getUserInfo获取小程序的 iv和encryptedData,可能需要rewData,signature
 
     getUserInfo() {
      // 获取用户信息
      uni.getUserInfo({
        // 指定返回微信的用户数据
        provider: "weixin",
        success: function (infoRes) {
          console.log("infoRes", infoRes)
          // uni.setStorageSync("encryptedData", infoRes.encryptedData)
          // uni.setStorageSync("iv", infoRes.iv)
        },
	fail(){
	  alert('已取消')
	}
      })
    },

image.png

接着请求wx.login(),获取code,

      uni.login({
    provider: "weixin",
    success: (res) => {
      console.log("login点击获取", res)
      uni.setStorageSync("wxCode", res.code)
    }
  })

image.png

3,前端请求后端的接口,将返回的code给到后端,得到返回的code,这个code判断用户是否注册过,

   3.1  6003没有注册

   3.2  200注册过

4, code码是6003的时候,返回数据unionId,openId,sessionKey我们要去注册
   4.1调用后台给的注册接口,传递 wx.getUserInfo 得到的数据加上unionId,openId
   {
      unionId:res.data.unionId?res.data.unionId:res.data.openId(unionId可能不存在)
      openId
      sessionKey
      signature
      rawData
      encryptedData
      iv
   }
   4.2注册成功后后端会返回code代码进入下一步
5, 当code200时,判断是否绑定手机号
   5.1把token保存起来

将token存储到开发者工具中

1.wx.setStorageSync() 2.wx.getStorageSync()

或者储存在pinia中

token需要持久化,使用 persist 插件

Pinia的持久化插件

    import { createPinia } from 'pinia'
    import persist from 'pinia-plugin-persistedstate'

    // 创建 pinia 实例
    const pinia = createPinia()
    // 使用持久化存储插件
    pinia.use(persist)

    // 默认导出,给 main.ts 使用
    export default pinia

    // 模块统一导出
    export * from './modules/member'
    
    

完成后在需要持久化的文件下完成下面的配置 image.png

获取虚拟头像和虚拟昵称等

## wx.getUserInfo

拦截器的请求

h5的前端跨域处理

image.png

request请求封装

//通过拦截器监听request这个api // uni.addInterceptor拦截器 uni.addInterceptor('request') // 拦截前触发 invoke // 拦截后触发 returnValue

image.png

uni.addInterceptor('request',{
    invoke:(config)=> {
        console.log(config)
    }
})
config输入内容如下所示

image.png

请求拦截器

/**
 * 添加拦截器:
 *   拦截 request 请求
 *   拦截 uploadFile 文件上传
 *
 * TODO:
 *   1. 非 http 开头需拼接地址
 *   2. 请求超时
 *   3. 添加小程序端请求头标识
 *   4. 添加 token 请求头标识
 */

import { useMemberStore } from '@/stores'

const baseURL = 'https://pcapi-xiaotuxian-front-devtest.itheima.net'

// 添加拦截器
const httpInterceptor = {
  // 拦截前触发invoke
  // 拦截后触发returnValue
  invoke(options: UniApp.RequestOptions) {
    console.log('请求拦截器', options)
    // 1. 非 http 开头需拼接地址 startsWith:判断字符串是否以http字符串开头
    if (!options.url.startsWith('http')) {
      options.url = baseURL + options.url
    }
    // 2. 请求超时, 默认 60s
    options.timeout = 10000
    // 3. 添加小程序端请求头标识
    // source-client 和 client-type 的区别与使用场景
    // 字段名称	典型值	作用场景	示例说明
    // source-client	 'miniapp'	标识请求来源的具体客户端类型	微信小程序、支付宝小程序、H5 等具体平台
    // client-type	   'mobile'	标识请求来源的设备大类	移动端、PC 端、TV 端等宏观分类
    //                 'weapp'	更细分的平台标识	专指微信小程序
    //                 'ios'/'android'	操作系统类型	区分 iOS 和 Android 原生应用
    // **使用场景**:后端可能需要根据不同的客户端返回不同的数据。例如:
    //  - 小程序端可能需要某些特定的字段,而Web端不需要。
    //  - 或者针对不同平台进行不同的业务逻辑处理(如支付方式在不同平台可能不同)。  注意请求头怎么写要和后端商量
    options.header = {
      // 开始的时候...options.header是空的,所以这里只会有'source-client': 'miniapp'
      ...options.header, //你如果有header的话,会合并到一起,这样写不会覆盖你自己的header
      'source-client': 'miniapp',
    }
    // 4. 添加 token 请求头标识
    const memberStore = useMemberStore()
    // 如果 `memberStore.profile` 是 `null` 或 `undefined`,那么整个表达式就返回 `undefined`,
    // 而不会尝试去访问 `token` 属性,从而避免出现因为访问 `null` 或 `undefined` 上的属性而导致的运行时错误。
    // 这是一种安全访问嵌套对象属性的方式。如果用户清理了用户信息,那么 `token` 就会是 `undefined`,不会添加到请求头中。
    const token = memberStore.profile?.token
    // console.log('token', token)
    if (token) {
      // 在options.header中是没有Authorization这个属性的,这种写法可以加上Authorization属性并赋值为token
      options.header.Authorization = token
    }
  },
}
// 拦截 request 请求
uni.addInterceptor('request', httpInterceptor)
// 拦截 uploadFile 文件上传
uni.addInterceptor('uploadFile', httpInterceptor)

响应拦截器

// 2.2 添加类型,支持泛型
// 这段代码是因为uniapp的响应拦截器不够完善,我们通过Promise来包装一下,使得我们能够更好的处理响应数据。
export const http = <T>(options: UniApp.RequestOptions) => {
  // 1. 返回 Promise 对象
  return new Promise<Data<T>>((resolve, reject) => {
    uni.request({
      ...options,
      // 响应成功
      success(res) {
        // 状态码 2xx, axios 就是这样设计的
        if (res.statusCode >= 200 && res.statusCode < 300) {
          // 2.1 提取核心数据 res.data
          resolve(res.data as Data<T>)
        } else if (res.statusCode === 401) {
          // 401错误  -> 清理用户信息,跳转到登录页
          const memberStore = useMemberStore()
          // 清理用户信息
          memberStore.clearProfile()
          uni.navigateTo({ url: '/pages/login/login' })
          // 标记为已拒绝,不再继续执行,回传res
          reject(res)
        } else {
          // 其他错误 -> 根据后端错误信息轻提示
          uni.showToast({
            icon: 'none',
            title: (res.data as Data<T>).msg || '请求错误',
          })
          reject(res)
        }
      },
      // 响应失败
      fail(err) {
        uni.showToast({
          icon: 'none',
          title: '网络错误,换个网络试试',
        })
        reject(err)
      },
    })
  })
}