uniAPP笔记

uni-app 介绍
%title插图%num

uni-app 是一个使用 Vue.js 开发所有前端应用的框架,开发者编写一套代码,
可发布到iOS、Android、Web(响应式)、以及各种小程序
(微信/支付宝/百度/头条/飞书/QQ/快手/钉钉/淘宝)、快应用等多个平台

官网链接:https://uniapp.dcloud.net.cn/

安装

使用 HBuilderX 编辑器进行安装

%title插图%num

官网下载地址:https://www.dcloud.io/hbuilderx.html

HBuilderX 内置相关环境,开箱即用,无需配置nodejs;
H是HTML的首字母,Builder是构造者,X是HBuilder的下一代版本。
简称HX。 HX轻如编辑器、强如IDE的合体版本

教程

B站相关视频教程 – 详细:https://www.bilibili.com/video/BV1mT411K7nW
B站相关视频教程 – 入门:https://www.bilibili.com/video/BV1BJ411W7pX

入门操作
创建项目

新建项目目录

HBuilderX 可以很迅速的创建 uniAPP 项目的基本结构。通过 文件 -> 新建 -> 项目 创建对应的 uniAPP项目

%title插图%num

选择默认模板,等待 HBuilderX 配置 uniAPP 项目结构。选择对应模板

%title插图%num

结构介绍

项目创建后,自动生成默认文件目录结构,各自负责对应的功能

%title插图%num

开发规范

为了实现多端兼容,综合考虑编译速度、运行性能等因素,uni-app 约定了如下开发规范:

  • 页面文件遵循 Vue单文件组件 (SFC) 规范
  • 组件标签靠近小程序规范
  • 接口能力 (JS API) 靠近微信小程序规范,但需将前缀 wx 替换为 uni
  • 数据绑定及时间处理同 Vue.js 规范,同时补充了 APP 及页面的生命周期
  • 为兼容多端运行,建议使用 flex 布局进行开发
绑定微信小程序

需要提前安装 微信小程序工具,并在微信小程序工具的安全设置中打开端口

%title插图%num
%title插图%num

通过绑定微信小程序的安装目录,即可在 运行 中选择微信小程序的封装操作

%title插图%num
真机调试

手机开启开发者模式并开启USB调试。并在 HBuilderX 程序中下载真机调试插件即可选择连接操作

%title插图%num

连接成功后,即可在真机状态下打包安卓APP并安装在手机上进行调试

%title插图%num
全局外观配置

该内容可查阅官方参考文档:https://uniapp.dcloud.net.cn/collocation/pages.html#globalstyle

介绍

在根目录的 pages.json 文件中,globalStyle属性 用于设置应用的状态栏、导航条、标题、窗口背景色等

参数介绍

属性 类型 默认值 描述 平台差异说明
navigationBarBackgroundColor HexColor #F7F7F7 导航栏背景颜色(同状态栏背景色) APP与H5为#F7F7F7,小程序平台请参考相应小程序文档
navigationBarTextStyle String white 导航栏标题颜色及状态栏前景颜色,仅支持 black/white 支付宝小程序不支持,请使用 my.setNavigationBar
navigationBarTitleText String 导航栏标题文字内容
navigationStyle String default 导航栏样式,仅支持 default/custom。custom即取消默认的原生导航栏,需看使用注意 微信小程序 7.0+、百度小程序、H5、App(2.0.3+)
backgroundColor HexColor #ffffff 下拉显示出来的窗口的背景色 微信小程序
backgroundTextStyle String dark 下拉 loading 的样式,仅支持 dark / light 微信小程序
enablePullDownRefresh Boolean false 是否开启下拉刷新,详见页面生命周期
onReachBottomDistance Number 50 页面上拉触底事件触发时距页面底部距离,单位只支持px,详见页面生命周期
backgroundColorTop HexColor #ffffff 顶部窗口的背景色(bounce回弹区域) 仅 iOS 平台
backgroundColorBottom HexColor #ffffff 底部窗口的背景色(bounce回弹区域) 仅 iOS 平台
titleImage String 导航栏图片地址(替换当前文字标题),支付宝小程序内必须使用https的图片链接地址 支付宝小程序、H5、APP
transparentTitle String none 导航栏整体(前景、背景)透明设置。支持 always 一直透明 / auto 滑动自适应 / none 不透明 支付宝小程序、H5、APP
titlePenetrate String NO 导航栏点击穿透 支付宝小程序、H5
pageOrientation String portrait 横屏配置,屏幕旋转设置,仅支持 auto / portrait / landscape 详见 响应显示区域变化 App 2.4.7+、微信小程序、QQ小程序
animationType String pop-in 窗口显示的动画效果,详见:窗口动画 App
animationDuration Number 300 窗口显示动画的持续时间,单位为 ms App
app-plus Object 设置编译到 App 平台的特定样式,配置项参考下方 app-plus App
h5 Object 设置编译到 H5 平台的特定样式,配置项参考下方 H5 H5
mp-alipay Object 设置编译到 mp-alipay 平台的特定样式,配置项参考下方 MP-ALIPAY 支付宝小程序
mp-weixin Object 设置编译到 mp-weixin 平台的特定样式 微信小程序
mp-baidu Object 设置编译到 mp-baidu 平台的特定样式 百度小程序
mp-toutiao Object 设置编译到 mp-toutiao 平台的特定样式 字节跳动小程序
mp-lark Object 设置编译到 mp-lark 平台的特定样式 飞书小程序
mp-qq Object 设置编译到 mp-qq 平台的特定样式 QQ小程序
mp-kuaishou Object 设置编译到 mp-kuaishou 平台的特定样式 快手小程序
mp-jd Object 设置编译到 mp-jd 平台的特定样式 京东小程序
usingComponents Object 引用小程序组件,参考 小程序组件
renderingMode String 同层渲染,webrtc(实时音视频) 无法正常时尝试配置 seperated 强制关掉同层 微信小程序
leftWindow Boolean true 当存在 leftWindow 时,默认是否显示 leftWindow H5
topWindow Boolean true 当存在 topWindow 时,默认是否显示 topWindow H5
rightWindow Boolean true 当存在 rightWindow 时,默认是否显示 rightWindow H5
rpxCalcMaxDeviceWidth Number 960 rpx 计算所支持的最大设备宽度,单位 px App(vue2 且不含 nvue)、H5(2.8.12+)
rpxCalcBaseDeviceWidth Number 375 rpx 计算使用的基准设备宽度,设备实际宽度超出 rpx 计算所支持的最大设备宽度时将按基准宽度计算,单位 px App(vue2 且不含 nvue)、H5(2.8.12+)
rpxCalcIncludeWidth Number 750 rpx 计算特殊处理的值,始终按实际的设备宽度计算,单位 rpx App(vue2 且不含 nvue)、H5(2.8.12+)
dynamicRpx Boolean false 动态 rpx,屏幕大小变化会重新渲染 rpx App-nvue(vue3 固定值为 true) 3.2.13+
maxWidth Number 单位px,当浏览器可见区域宽度大于maxWidth时,两侧留白,当小于等于maxWidth时,页面铺满;不同页面支持配置不同的maxWidth;maxWidth = leftWindow(可选)+page(页面主体)+rightWindow(可选) H5(2.9.9+)

案例演示

pages.json
{
	"pages": [ 
 // pages数组中第一项表示应用启动页,
 // 参考 https://uniapp.dcloud.io/collocation/pages
		{
			"path": "pages/index/index"
		}
	],
	"globalStyle": {
		// 导航栏标题颜色 白色
		"navigationBarTextStyle": "white",
		// 导航栏标题文字内容 初号机
		"navigationBarTitleText": "初号机",
		// 导航栏背景色(同状态栏背景色) #66ccff
		"navigationBarBackgroundColor": "#66CCFF",
		// 下拉框背景色 #66cc
		"backgroundColor": "#66CC",
		// 是否开启下拉刷新 是
		"enablePullDownRefresh": true,
		// 下拉加载样式 亮色
		"backgroundTextStyle":"light"
	},
	"uniIdRouter": {}
}

效果展示

%title插图%num
局部外观配置

该内容可查阅官方参考文档:https://uniapp.dcloud.net.cn/collocation/pages.html#style

介绍

pages.json 的 pages 属性可用于设置每个页面的状态栏、导航条、标题、窗口背景色等,
该配置项会覆盖 globalStyle 中相同的配置项

参数介绍

属性 类型 默认值 描述 平台差异说明
navigationBarBackgroundColor HexColor #000000 导航栏背景颜色(同状态栏背景色),如”#000000″
navigationBarTextStyle String white 导航栏标题颜色及状态栏前景颜色,仅支持 black/white
navigationBarTitleText String 导航栏标题文字内容
navigationBarShadow Object 导航栏阴影,配置参考下方 导航栏阴影
navigationStyle String default 导航栏样式,仅支持 default/custom。custom即取消默认的原生导航栏,需看使用注意 微信小程序 7.0+、百度小程序、H5、App(2.0.3+)
disableScroll Boolean false 设置为 true 则页面整体不能上下滚动(bounce效果),只在页面配置中有效,在globalStyle中设置无效 微信小程序(iOS)、百度小程序(iOS)
backgroundColor HexColor #ffffff 窗口的背景色 微信小程序、百度小程序、字节跳动小程序、飞书小程序、京东小程序
backgroundTextStyle String dark 下拉 loading 的样式,仅支持 dark/light
enablePullDownRefresh Boolean false 是否开启下拉刷新,详见页面生命周期
onReachBottomDistance Number 50 页面上拉触底事件触发时距页面底部距离,单位只支持px,详见页面生命周期
backgroundColorTop HexColor #ffffff 顶部窗口的背景色(bounce回弹区域) 仅 iOS 平台
backgroundColorBottom HexColor #ffffff 底部窗口的背景色(bounce回弹区域) 仅 iOS 平台
disableSwipeBack Boolean false 是否禁用滑动返回 App-iOS(3.4.0+)
titleImage String 导航栏图片地址(替换当前文字标题),支付宝小程序内必须使用https的图片链接地址 支付宝小程序、H5、App
transparentTitle String none 导航栏透明设置。支持 always 一直透明 / auto 滑动自适应 / none 不透明 支付宝小程序、H5、APP
titlePenetrate String NO 导航栏点击穿透 支付宝小程序、H5
app-plus Object 设置编译到 App 平台的特定样式,配置项参考下方 app-plus App
h5 Object 设置编译到 H5 平台的特定样式,配置项参考下方 H5 H5
mp-alipay Object 设置编译到 mp-alipay 平台的特定样式,配置项参考下方 MP-ALIPAY 支付宝小程序
mp-weixin Object 设置编译到 mp-weixin 平台的特定样式 微信小程序
mp-baidu Object 设置编译到 mp-baidu 平台的特定样式 百度小程序
mp-toutiao Object 设置编译到 mp-toutiao 平台的特定样式 字节跳动小程序
mp-lark Object 设置编译到 mp-lark 平台的特定样式 飞书小程序
mp-qq Object 设置编译到 mp-qq 平台的特定样式 QQ小程序
mp-kuaishou Object 设置编译到 mp-kuaishou 平台的特定样式 快手小程序
mp-jd Object 设置编译到 mp-jd 平台的特定样式 京东小程序
usingComponents Object 引用小程序组件,参考 小程序组件 App、微信小程序、支付宝小程序、百度小程序、京东小程序
leftWindow Boolean true 当存在 leftWindow时,当前页面是否显示 leftWindow H5
topWindow Boolean true 当存在 topWindow 时,当前页面是否显示 topWindow H5
rightWindow Boolean true 当存在 rightWindow时,当前页面是否显示 rightWindow H5
maxWidth Number 单位px,当浏览器可见区域宽度大于maxWidth时,两侧留白,当小于等于maxWidth时,页面铺满;不同页面支持配置不同的maxWidth;maxWidth = leftWindow(可选)+page(页面主体)+rightWindow(可选) H5(2.9.9+)

案例演示

1. 创建子组件 建议使用 view 标签,而不是 div ,因为有兼容问题

message/message.vue
<template>
	<view>
		Hello-uni
	</view>
</template>

<script>
	export default {}
</script>

<style>

</style>

2. pages 中使用 path 引用 子组件路径,并使用 style 声明组件样式
【注意组件放置的顺序,第一项为应用启动项】

pages.json
{
    "pages": [
        //pages数组中第一项表示应用启动页
        {
            "path": "pages/message/message",
            "style": {
                "navigationBarTitleText": "信息页",
                "navigationBarBackgroundColor": "#007AFF"
            }
        },
        {
            "path": "pages/index/index"
        }
    ],
    "globalStyle": {
        //...
    },
    "uniIdRouter": {}
}

效果展示

%title插图%num
H5样式

该内容可查阅官方参考文档:https://uniapp.dcloud.net.cn/collocation/pages.html#h5

介绍

配置编译到 H5 平台时的特定样式

参数介绍

属性 类型 描述
titleNView Object 导航栏
pullToRefresh Object 下拉刷新

导航栏

属性 类型 默认值 描述 最低版本
backgroundColor String #F7F7F7 背景颜色,颜色值格式为”#RRGGBB”。
buttons Array 自定义按钮,参考 buttons
titleColor String #000000 标题文字颜色
titleText String 标题文字内容
titleSize String 标题文字字体大小
type String default 导航栏样式。”default”-默认样式;”transparent”-透明渐变。
searchInput Object 导航栏上的搜索框样式,详见:searchInput 1.6.5

案例演示

JSON
{
    "pages": [
        {
            "path": "pages/message/message",
            "style": {
                // ...
                "h5": {
                    "pullToRefresh": {
                        "color": "red"
                    }
                }
            }
        },
        {
            "path": "pages/index/index"
        }
    ],
    "globalStyle": {},
    "uniIdRouter": {}
}

效果展示

%title插图%num
命令行创建uni-app

由于 HbuilderX 默认创建的是 vue2 的框架,且不支持 TS 语法的提示。故应采用 vscode 开发并构建。

使用 npx 创建

PowerShell
npx degit dcloudio/uni-preset-vue#vite-ts 项目名称

# 如果下载失败 可以尝试清除缓存 和更新 npm 版本
npm cache clean --force
npm install -g npm@latest

效果展示

%title插图%num

安装项目依赖包

PowerShell
cd 项目目录
npm install

运行项目

package.json 包中会根据参数运行编译指定平台的代码(如下图所示)

%title插图%num

若要以运行微信小程序项目运行,例如可使用:npm run dev:wp-weixin

PowerShell
npm run dev:mp-weixin

运行后,微信开发者工具找到对应包文件位置 项目根目录 \dist\dev\mp-weixin 同步打开,即可同步调试

问题解决

部署完成后,tsconfig.json 文件会提示如下报错,修改配置项即可

Option 'importsNotUsedAsValues' is deprecated and will stop functioning in TypeScript 5.5. Specify compilerOption '"ignoreDeprecations": "5.0"' to silence this error.
  Use 'verbatimModuleSyntax' instead.

可以在tsconfig.json文件中”compilerOptions”配置项内添加”ignoreDeprecations”: “5.0” 修复

JavaScript
  "compilerOptions": {
    "ignoreDeprecations": "5.0"
  },

或者,使用该教程提供的策略: https://blog.csdn.net/anech/article/details/143733836

插件安装

要在 vscode 上开发 uniapp-vue3 项目,可以安装几款插件去辅助开发,提高效率

uni-create-view

%title插图%num

上面这是一款可以右键新建目录并在 package.json 注册对应路由的包,
注意需要在插件扩展配置中将配置改为 vue3

%title插图%num
%title插图%num

uni-helper

%title插图%num

uniapp 的专用配置项的代码提示工具

uniapp小程序扩展

%title插图%num

为 uniapp 相关api提供文档及文档链接

安装类型声明文件

PowerShell
pnpm i -D @types/wechat-miniprogram @uni-helper/uni-app-types

配置 tsconfig.json

JSON
// tsconfig.json
{
  "extends": "@vue/tsconfig/tsconfig.json",
  "compilerOptions": {
    "ignoreDeprecations": "5.0",
    "sourceMap": true,
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"]
    },
    "lib": ["esnext","dom"],
    "types": [
      "@dcloudio/types", // uni-app API 类型
      "miniprogram-api-typings", // 原生微信小程序类型
      "@uni-helper/uni-app-types" // uni-app 组件类型
    ]
  },
  // vue 编译器类型,校验标签类型
  "vueCompilerOptions": {
    "nativeTags": ["block","component","template","slot"],
  },
  "include": ["src/**/*.ts","src/**/*.d.ts","src/**/*.tsx","src/**/*.vue"]
}

另外后续设置其他操作,可以查看其他文档 ↓

相关文档来源:https://huaweicloud.csdn.net/654cad4b8c4ad05cd82aaf8d.html

前言
%title插图%num

实际上,uni-app 的大部分功能实现与 Vue 相似,其中夹杂了一些 微信小程序 的 api。这让我怎么写笔记…

写详细吧,这笔记就特别的冗余,写简单吧;好像笔记的效益不大

那不如直接让学 uniApp 的小朋友直接先学 微信小程序Vue 可能更适合;

%title插图%num

因此,我就写一些uniApp比较特别的内容吧

唯一遗憾大概就是没有二级路由的设定,做子级嵌套的内容切换会有点麻烦吧,或许有提供第三方包?

特性方案
安全区域

安全区域的顶部和底部间隔

当使用 uniapp 开发手机端的自定义导航栏时,为了适配刘海屏等机型。需要去做安全区域适配

%title插图%num

使用 uni.getSystemInfoSync().safeAreaInsets 去获取屏幕边界到安全区域的位置,并设置导航栏与手机端顶部安全区域的合适间隔,实现适配

Vue
<script setup lang="ts">
// 获取屏幕边界到安全区域的位置
const { safeAreaInsets } = uni.getSystemInfoSync()
</script>

<template>
  <view class="navbar" :style="{ paddingTop: safeAreaInsets?.top + 'px' }">
    <!-- ... -->
  </view>
</template>

动态设置 scroll-view 组件高度

如若需要组件设置占满高度,为了兼容所有机型高度,使用 uni.getSystemInfoSync() 获取设备高度
关于 uni.getSystemInfoSync() 相关文档

%title插图%num
Vue
<script>
export default {
  data() {
    return {
      wh: 0
    };
  },
  // 页面加载完成后
  onLoad() {
    // 获取设备信息
    const info = uni.getSystemInfoSync();
    // 为当前 可用高度对应变量进行赋值
    this.wh = info.windowHeight;
  }
}
</script>
查看大图

当需要全屏展示一组图片列表时,可以使用 uni.previewImage({current:string,urls:string[]}) 方法

Vue
<script setup lang="ts">
const imageList = ["xxx.jpg","xxx.jpg","..."]
// 点击图片时业务
const onTapImage = (url: string) => {
  uni.previewImage({
    current: url,
    urls: imageList
  })
}
</script>
<template>
<swiper circular @change="onChange">
  <swiper-item v-for="src in imageList" :key="src">
    <image @tap="onTapImage(src)" mode="aspectFill" :src="src" />
  </swiper-item>
</swiper>
</template>

效果展示

%title插图%num

点击轮播图,打开大图预览

平台差异

uniapp 的代码在编译在不同平台的时候,都会有一些差异的内容。详情和部分解决方案可以看 官方文档

小程序不支持 * 选择器

为避免在编译小程序项目时报错,应避免使用 * 选择器,而使用并集选择器去选择对应标签

%title插图%num

解决不同平台定位时底部位置不同的问题

%title插图%num

由于每个平台的视口底部都不是同一个位置,使用 uniapp 内置提供的 --windows-bottom 去差异获取每个平台的最底部位置

CSS
.n {
  /* .. */
  top: var(--windows-top);
  bottom: var(--windows-bottom);
}

页面跳转
普通跳转

声明式跳转

在Uni-app中,可以使用声明式导航(Declarative Navigation)来实现页面的跳转。通过在模板中绑定特定的事件或属性,触发相应的导航操作;

下面是使用 <navigator> 标签进行页面跳转

Vue HTML
<navigator url="/pages/about">跳转到关于页面</navigator>

编程式导航

通过绑定事件,并触发事件后使用 uni.navigateTo() 的方式跳转;

Vue HTML
<button @click="redirectToAbout">跳转到关于页面</button>
JavaScript
methods: {
  redirectToAbout() {
    uni.navigateTo({
      url: '/pages/about'
    })
  }
}
Tab栏跳转

若是需要跳转到已经声明在 TabBar 的页面。为了同时切换底部导航栏选项。需要使用 uni.switchTab() 方式进行跳转。

JavaScript
uni.switchTab({
  url: '/pages/tabbar/home'
})
跳转并关闭页

关闭当前页跳转

使用 uni.redirectTo() 跳转时,会在 页面栈 中关闭当前页进行跳转。通常用于阻止用户表单多次提交使用

事件修饰符
事件监听

uniApp的事件监听写法与 vue 类似,详细请看 vue教程

事件修饰符

相关资料来自 CSDN

  • prevent:阻止默认行为
  • stop:阻止事件冒泡
  • capture:使用事件捕获模式
  • self:只有当事件是从事件源本身触发时才触发回调函数 (不兼容 android端)
  • once:只触发一次回调函数
  • passive:提高页面滚动的流畅度
Vue
<!-- 阻止默认行为 -->
<button @click.prevent="handleClick">点击我</button>

<!-- 阻止事件冒泡 -->
<button @click.stop="handleClick">点击我</button>

<!-- 使用事件捕获模式 -->
<button @click.capture="handleClick">点击我</button>

<!-- 只有当事件是从事件源本身触发时才触发回调函数 -->
<button @click.self="handleClick">点击我</button>

<!-- 只触发一次回调函数 -->
<button @click.once="handleClick">点击我</button>

<!-- 提高页面滚动的流畅度 -->
<button @click.passive="handleClick">点击我</button>
表单组件

uniApp官方相关文档

HTML中 表单组件通常为 input 并选择 type 的类型来实现 复选框、单选框、下拉框;在这有差异

button

button 组件的内容比较丰富,可自行文档查询 相关文档

Vue
<button type="primary">按钮</button>

size 按钮尺寸

设置预设的按钮的大小样式

说明
default 默认大小
mini 小尺寸

type 有效值

设置预设的按钮的外观样式

说明
primary 默认样式
default 白色
warn 红色

form-type 有效值

实现表单按钮事件

说明
submit 提交表单
reset 重置表单

代码演示

%title插图%num
checkbox

checkbox 是通过由 checkbox-group 包裹 checkbox 实现复选框效果 可自行文档查询 相关文档

Vue
 <template>
 <checkbox-group>
     <label>
         <checkbox value="cb" checked="true" />选中
     </label>
     <label>
         <checkbox value="cb" />未选中
     </label>
 </checkbox-group>
 </template>

效果展示

%title插图%num

checkbox-group 参数

属性名 类型 说明
@change EventHandle <checkbox-group>中选中项发生改变是触发 change 事件,detail = {value:[选中的checkbox的value的数组]}

checkbox 参数

属性名 类型 默认值 说明
value String <checkbox> 标识,选中时触发 <checkbox-group> 的 change 事件,并携带 <checkbox> 的 value。
disabled Boolean false 是否禁用
checked Boolean false 当前是否选中,可用来设置默认选中
color Color checkbox的颜色,同css的color
  • checkbox的默认颜色,在不同平台不一样。微信小程序、360小程序是绿色的,字节跳动小程序为红色,
    其他平台是蓝色的。更改颜色使用color属性。
  • 如需调节 checkbox 大小,可通过 css 的 scale 方法调节,如缩小到70% style=”transform:scale(0.7)”
组件传参

组件放置在 uniApp 的根目录的 component 文件夹内,在 HBuilder 软件中对 component 文件夹右键 新建组件,即可创建组件

%title插图%num

创建组件后,引用的名称就为组件创建的文件夹的名称,可以驼峰命名,也可以用 – 命名

Vue HTML
<smm-title></smm-title>
父传子

父级直接在 组件标签上 定义变量 并 传值,即可传到子级同名下的 props 对象中创建的变量中

Vue HTML
<smm-lyricBar name='你好'></smm-lyricBar>

子级通过 props 接收对应参数

JavaScript
export default {
// 也可以用数组的简化方式 props:["name"]
props: {
   name: {
    // 限制传入的类型
    type: String,
    // 默认值
    default: ""
   }
 }
}
子传父

子级组件通过 $emit 向外主动发起事件并传参,父级通过对组件绑定事件来触发事件处理函数并接收参数

Vue
<template>
    <view @click="cilckFn"></view>
</template>
<script>
export default {
    methods: {
        cilckFn() {
            this.$emit('click', 1);
        }
    }
}
</script>

父级通过给组件绑定对应事件,即可获取子组件发送的数据

Vue
<template>
    <smm-title @click="cilckFn"></smm-title>
</template>
<script>
export default {
    methods: {
        cilckFn(e) {
            console.log(e); // 1
        }
    }
}
</script>
sync

【组件接收父级的参数实际上是单向数据流,因此即使子级改变了传入的参数;也不改变对父级的数据】
因此当我们想主动改变 props 对象中对应变量的值时,系统会抛出一个报错

为了简化 流程,父级界面通过对组件传参的变量使用 .sync 修饰符,这相当父级组件直接为该变量添加并绑定了
updata:变量名 的方法;并可以由组件的 this.$emit(‘updata:变量名’,新变量的值) 直接修改父级的变量

Vue
<template>
    <smm-title :name.sync="str"></smm-title>
</template>
<script>
export default {
    data() {
        return {
            str: 'hello'
        }
    }
}
</script>

子级组件通过 this.$emit(‘updata:xxx‘,xxx); 可直接修改对应的 props 值

Vue
<script>
export default {
    props: {
        name: {
            type: String,
            default: ''
        }
    },
    methods: {
        changeStr() {
            // 父级通过 .sync 修饰的变量 可由子级通过此方式修改
            this.$emit('updata:name', 'word');
        }
    }
}
</script>
原生事件

【默认在组件上使用 click 等原生事件是无效的,一般是由组件绑定对应事件并由 $emit 向外提供】
例如:若是 需要触发组件的单击事件,旧方式是 组件需要绑定 cilck 并使用 $emit 暴露出去

Vue
<template>
    <view @click="cilckFn"></view>
</template>
<script>
export default {
    methods: {
        cilckFn() {
            this.$emit('click');
        }
    }
}
</script>

如若需要直接对事件触发原生事件的需求,父级界面可在对组件进行的 事件监听 加上 .native 修饰符

Vue
<template>
    <!-- 直接对组件调用原生的 单击 事件 -->
    <smm-title @click.native="cilckFn"></smm-title>
</template>
网络拦截器
请求拦截器

创建拦截器文件 (http.ts / http.js),并使用 uni.addInterceptor 设置请求拦截器、基地址等操作

/utils/http
const baseURL = 'http接口地址'

const httpInterceptor = {
    // 拦截前触发
    invoke(options: UniApp.RequestOptions) {
        // 如果链接中没有地址
        if (!options.url.startsWith('http')) {
            options.url = baseURL + options.url
        }
        // 修改请求超时 默认60000毫秒
        options.timeout = 10000
        // 设置请求头
        options.header = {
            ...options.header,
            'source-client': 'app',
        }
        // ...
        // 如有 token
        if (token) {
            // 添加 token
            options.header.Authorization = token
        }
    },
}

uni.addInterceptor('request', httpInterceptor)
uni.addInterceptor('uploadFile', httpInterceptor)
响应拦截器

由于 uniappuni.request 的拦截器并没有 axios 完善,响应拦截器需要自己封装 uni.request 函数代替

JavaScript
// 响应拦截器
export const http = (options) => {
    return new Promise((resolve, reject) => {
        uni.request({
            ...options,
            // 响应成功
            success(res) {
                // 数据是否返回成功
                if (res.statusCode >= 200 && res.statusCode < 300) {
                    resolve(res.data)
                }
                // token 是否失效
                else if (res.statusCode === 401) {
                    // ...
                    // 失败回传
                    reject(res)
                } else {
                    uni.showToast({
                        title: (res.data).msg || "请求错误",
                        icon: "none"
                    })
                    reject(res)
                }
            },
            // 响应失败
            fail(err) {
                uni.showToast({
                    title: "网络错误,换个网络试试",
                    icon: "none"
                })
                reject(err)
            }
        })
    })
}
使用拦截器

在页面中引用该文件,即可实现拦截器效果

Vue
<script setup lang="ts">
import { http } from '@/utils/http'
// ...
http({
 // ...
})
</script>

<template>
</template>

<style lang="scss">
</style>
上传功能

uniapp 支持资源上传功能,默认使用 formData 的方式向服务器发起上传文件的请求。自带了如下选择工具:

%title插图%num
  • 图片选择器 uni.chooseImage()
  • 视频选择器 uni.chooseVideo()

通过选择器选择本地的资源路径,再通过 uni.uploadFile() 方法将其上传到服务器

手机端如若需要使用该方法,请确认已授权软件读取文件的权限

图片选择上传

使用 图片选择控件 uni.chooseImage 和 文件上传 uni.uploadFile 实现图片的上传功能
微信小程序从基础库 2.21.0 开始, wx.chooseImage 停止维护,请使用 uni.chooseMedia 代替

案例
uni.chooseImage({
  count: 1, // 最多可以选择的图片张数
  sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有
  sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有
  success: function (res) {
    var tempFilePaths = res.tempFilePaths;
    // 上传文件
    uni.uploadFile({
      url: 'your/upload/url',
      filePath: tempFilePaths[0],
      name: 'file',
      formData: {
        // 添加其他的 FormData 数据
        key1: value1,
        key2: value2,
        // ...
      },
      success: function (res) {
        console.log('上传成功', res);
        uni.showToast({
          title: '上传成功',
          icon: 'success',
          duration: 2000
        });
      },
      fail: function (res) {
        console.log('上传失败', res);
        uni.showToast({
          title: '上传失败',
          icon: 'none',
          duration: 2000
        });
      }
    });
  }
});
视频选择上传

使用 图片选择控件 uni.choosVideo 和 文件上传 uni.uploadFile 实现图片的上传功能

案例
uni.chooseVideo({
  sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有
  compressed: true, // 是否压缩视频,默认为 true
  maxDuration: 60, // 拍摄最长拍摄时间,单位秒,默认为 60
  camera: 'back', // 指定使用前置或后置摄像头,默认为后置摄像头
  success: function (res) {
    var tempFilePath = res.tempFilePath;
    // 上传文件
    uni.uploadFile({
      url: 'your/upload/url',
      filePath: tempFilePath,
      name: 'file',
      formData: {
        // 添加其他的 FormData 数据
        key1: value1,
        key2: value2,
        // ...
      },
      success: function (res) {
        console.log('上传成功', res);
        uni.showToast({
          title: '上传成功',
          icon: 'success',
          duration: 2000
        });
      },
      fail: function (res) {
        console.log('上传失败', res);
        uni.showToast({
          title: '上传失败',
          icon: 'none',
          duration: 2000
        });
      }
    });
  }
});
其他选择内容方法

除了 uni.chooseImage() uni.chooseVideo() 方法,uniapp 还提供了其他选择方法,可以根据不同的需求选择合适的方法,例如:

  • uni.chooseFile():选择文件,可以选择任意类型的文件,包括图片、视频、文档等。
  • uni.chooseMedia():拍摄或从手机相册中选择图片或视频,选择视频或者图片

这些方法都有各自的参数和返回值,具体使用方法可以参考 uniapp 的官方文档。根据具体的需求,选择合适的方法来实现相应的功能

下载功能

使用 uni.downloadFile() 方法 下载文件资源到本地,客户端直接发起一个 HTTP GET 请求,返回文件的本地临时路径

视频下载示例
// 下载直链视频
uni.downloadFile({
  url: 'https://example.com/my-video.mp4',
  success: function (res) {
    if (res.statusCode === 200) {
      uni.showToast({
        title: '视频下载成功',
        icon: 'success'
      });
    }
  },
  fail: function (error) {
    uni.showToast({
      title: '视频下载失败',
      icon: 'none'
    });
  }
});

通过该方法获取临时文件存放路径后,一般再通过 uni.saveFile 方法保存文件到本地

该方法不支持 H5,且 saveFile 会把临时文件移动,因此调用成功后传入的 tempFilePath 将不可用

示例
uni.chooseImage({
  success: function (res) {
    var tempFilePaths = res.tempFilePaths;
    uni.saveFile({
      tempFilePath: tempFilePaths[0],
      success: function (res) {
        // 文件保存的所在目录
        let savedFilePath = res.savedFilePath;
      }
    });
  }
});

当然,如果是视频或者图片,一般使用的是 uni.saveImageToPhotosAlbum() 保存图片到相册 或 uni.saveVideoToPhotosAlbum() 保存视频到相册

保存到相册

通过 uni.saveImageToPhotosAlbum()uni.saveVideoToPhotosAlbum() 保存视频或图片到相册

参数介绍

参数名 类型 必填 说明
filePath String 视频文件路径,可以是临时文件路径也可以是永久文件路径
success Function 接口调用成功的回调函数
fail Function 接口调用失败的回调函数
complete Function 接口调用结束的回调函数(调用成功、失败都会执行)

案例演示

示例
// 下载并保存视频
uni.downloadFile({
  url: 'https://example.com/my-video.mp4',
  success: function (res) {
    if (res.statusCode === 200) {
      // 保存视频到相册
      uni.saveVideoToPhotosAlbum({
        filePath: res.tempFilePath,
        success: function () {
          uni.showToast({
            title: '视频保存成功',
            icon: 'success'
          });
        },
        fail: function (error) {
          uni.showToast({
            title: '视频保存失败',
            icon: 'none'
          });
        }
      });
    }
  },
  fail: function (error) {
    uni.showToast({
      title: '视频下载失败',
      icon: 'none'
    });
  }
});
条件编译
介绍

uniApp官方相关文档

每个平台有自己的一些特性,即使是API在每个平台不一定都是支持的,因此会存在一些无法跨平台的情况

  • 大量写 if else,会造成代码执行性能低下和管理混乱。
  • 编译到不同的工程后二次修改,会让后续升级变的很麻烦

因此,推荐使用条件编译来对不同平台写特定的代码样式

语法

使用语法介绍

条件编译是用特殊的注释作为标记,在编译时根据这些特殊的注释,将注释里面的代码编译到不同平台

**写法:**以 #ifdef  #ifndef 加 %PLATFORM% 开头,以 #endif 结尾。

  • #ifdef:if defined 仅在某平台存在
  • #ifndef:if not defined 除了某平台均存在
  • %PLATFORM%:平台名称
条件编译写法说明
#ifdef APP-PLUS
需条件编译的代码
#endif
仅出现在 App 平台下的代码
#ifndef H5
需条件编译的代码
#endif
除了 H5 平台,其它平台均存在的代码
#ifdef H5 || MP-WEIXIN
需条件编译的代码
#endif
在 H5 平台或微信小程序平台存在的代码(这里只有||,不可能出现&&,因为没有交集)
全局共享数据

Vuex 之前已经写了相关文档,若需要详细了解请直接查阅

uniapp 官方提供了 getApp().globalData.data 的方法去实现全局共享,但功能不多因此不加以介绍。详情请看文档说明:

官方文档容易出现的问题

说明

uniapp 内置了全局共享数据 vuex 模块,将极大简化并方便了项目的全局共享状态的模块开发

一般搭配本地存储,在 vuex 的操作方法若执行 uni.setStorageSync(); 即可实现永久存值

创建模块

配置模块

在项目的根目录中新建 store 目录,创建 index.js 文件

store/index.js
import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

const store = new Vuex.Store({
    state: {
        // 定义状态
        sayhi:'hello'
        }
    },
    mutations: {
        // 定义方法
        changeData(state, payload){
          state.sayhi = payload;
        }
    }
})

export default store;

导入模块

在根目录下的 main.js 中,引用 vuex 并其配置的全局共享数据

main.js
import store from './store/index.js'

// #ifndef VUE3
import Vue from 'vue'
import App from './App'

Vue.prototype.$store = store;

Vue.config.productionTip = false

App.mpType = 'app'

const app = new Vue({
    ...App
})
app.$mount()
// #endif

// #ifdef VUE3
import { createSSRApp } from 'vue'

import App from './App.vue'

export function createApp() {
  const app = createSSRApp(App)
  return {
    app
  }
}
// #endif
使用模块

获取状态

通过使用 vuex 提供的方法,或者直接使用 this.$store.state 来获取 vuex 中 state 存储的状态

Vue
<template>
  <div>
    <p>{{ count }}</p>
  </div>
</template>

<script>
export default {
  computed: {
    count() {
      return this.$store.state.sayhi
    }
  }
}
</script>

修改状态

使用 mapMutations 辅助函数将 vuex 中的 mutations 映射到当前组件的 methods 中,并在需要修改 state 值的地方调用该方法即可

Vue
<template>
  <div>
    <p>{{ count }}</p>
    <button @click="increment">Increment</button>
  </div>
</template>

<script>
import { mapMutations } from 'vuex'

export default {
  computed: {
    count() {
      return this.$store.state.sayhi
    }
  },
  methods: {
    ...mapMutations([
      'changeData'
    ])
  }
}
</script>

在组件的 methods 中定义需要修改 state 值的方法,并在方法中通过 this.$store.commit 调用对应的 mutation

JavaScript
methods: {
  increment() {
    this.$store.commit('changeData')
  }
}
i18n 多语言

uniapp 支持多语言切换,其基础组件和API,内置如下语言:

  • 中文简体
  • 中文繁体
  • 英语
  • 法语
  • 西班牙语
配置说明

关于配置多语言,可参考 uniapp 官方文档

uni-app的国际化,即多语言,分为应用部分和框架部分

  • 应用部分,即开发者自己的代码里涉及的界面部分
  • 框架部分,即uni-app内置组件和API涉及界面的部分
框架多语言配置

框架部分会自动获取当前设备或软件配置的语言环境并进行切换,如若有除上述语中的多语言需求,请自行配置

在 locale 文件夹中新建 uni-app.对应地区语言代码.json ,并进行对应语种配置 相关教程

uni-app.zh-Hans.json
{
  "common": {
    "uni.app.quit": "再按一次退出应用",
    "uni.async.error": "连接服务器超时,点击屏幕重试",
    "uni.showActionSheet.cancel": "取消",
    "uni.showToast.unpaired": "请注意 showToast 与 hideToast 必须配对使用",
    "uni.showLoading.unpaired": "请注意 showLoading 与 hideLoading 必须配对使用",
    "uni.showModal.cancel": "取消",
    "uni.showModal.confirm": "确定",
    "uni.chooseImage.cancel": "取消",
    "uni.chooseImage.sourceType.album": "从相册选择",
    "uni.chooseImage.sourceType.camera": "拍摄",
    "uni.chooseVideo.cancel": "取消",
    "uni.chooseVideo.sourceType.album": "从相册选择",
    "uni.chooseVideo.sourceType.camera": "拍摄",
    "uni.previewImage.cancel": "取消",
    "uni.previewImage.button.save": "保存图像",
    "uni.previewImage.save.success": "保存图像到相册成功",
    "uni.previewImage.save.fail": "保存图像到相册失败",
    "uni.setClipboardData.success": "内容已复制",
    "uni.scanCode.title": "扫码",
    "uni.scanCode.album": "相册",
    "uni.scanCode.fail": "识别失败",
    "uni.scanCode.flash.on": "轻触照亮",
    "uni.scanCode.flash.off": "轻触关闭",
    "uni.startSoterAuthentication.authContent": "指纹识别中...",
    "uni.picker.done": "完成",
    "uni.picker.cancel": "取消",
    "uni.video.danmu": "弹幕",
    "uni.video.volume": "音量",
    "uni.button.feedback.title": "问题反馈",
    "uni.button.feedback.send": "发送"
  },
  "ios": {},
  "android": {}
}
uni-app.ja.json
{
  "common": {
    "uni.app.quit": "もう一度押すと、アプリケーションが終了します",
    "uni.async.error": "サーバーへの接続がタイムアウトしました。画面をクリックして再試行してください",
    "uni.showActionSheet.cancel": "キャンセル",
    "uni.showToast.unpaired": "使用するには、showToastとhideToastをペアにする必要があることに注意してください",
    "uni.showLoading.unpaired": "使用するには、showLoadingとhideLoadingをペアにする必要があることに注意してください",
    "uni.showModal.cancel": "キャンセル",
    "uni.showModal.confirm": "OK",
    "uni.chooseImage.cancel": "キャンセル",
    "uni.chooseImage.sourceType.album": "アルバムから選択",
    "uni.chooseImage.sourceType.camera": "カメラ",
    "uni.chooseVideo.cancel": "キャンセル",
    "uni.chooseVideo.sourceType.album": "アルバムから選択",
    "uni.chooseVideo.sourceType.camera": "カメラ",
    "uni.previewImage.cancel": "キャンセル",
    "uni.previewImage.button.save": "画像を保存",
    "uni.previewImage.save.success": "画像をアルバムに正常に保存します",
    "uni.previewImage.save.fail": "画像をアルバムに保存できませんでした",
    "uni.setClipboardData.success": "コンテンツがコピーされました",
    "uni.scanCode.title": "スキャンコード",
    "uni.scanCode.album": "アルバム",
    "uni.scanCode.fail": "認識に失敗しました",
    "uni.scanCode.flash.on": "タッチして点灯",
    "uni.scanCode.flash.off": "タップして閉じる",
    "uni.startSoterAuthentication.authContent": "指紋認識...",
    "uni.picker.done": "完了",
    "uni.picker.cancel": "キャンセル",
    "uni.video.danmu": "「弾幕」",
    "uni.video.volume": "ボリューム",
    "uni.button.feedback.title": "質問のフィードバック",
    "uni.button.feedback.send": "送信"
  },
  "ios": {},
  "android": {}
}
应用多语言配置

创建多语言 json 文件

建议在根目录中新建 locale 文件夹,在里面配置多语言模块

创建俩个 json 文件,对应不同语言环境下显示的内容

en.json
{
    "login.login": "login",
    "message.changeLang.title": "prompt",
    "message.changeLang.content": "Do you want to switch languages?",
    "tabBar.index": "index",
    "tabBar.live": "live",
    "tabBar.song": "song",
    "tabBar.my": "my"
}
zh-Hans.json
{
    "login.login": "登录",
    "message.changeLang.title": "提示",
    "message.changeLang.content": "是否要切换语言?",
    "tabBar.index": "首页",
    "tabBar.live": "直播",
    "tabBar.song": "歌曲",
    "tabBar.my": "我的"
}

创建入口文件 并引入 json 文件

通过入口 index.js 文件,引入所有 文本数据 并向外暴露

locale/index.js
import en from './en.json'
import zhHans from './zh-Hans.json'

export default {
  en,
  'zh-Hans': zhHans
}

在项目中挂载多语言模块

mian.js
import messages from './locale/index'

let i18nConfig = {
  locale: uni.getLocale(),
  messages
}

// vue2 配置方案
// #ifndef VUE3
import Vue from 'vue'
import App from './App'

// 引入 VueI18n 库
import VueI18n from 'vue-i18n'
// 在 Vue 中使用 VueI18n
Vue.use(VueI18n)
// 创建一个 VueI18n 实例,传入 i18nConfig 配置
const i18n = new VueI18n(i18nConfig)

// ...

const app = new Vue({
  i18n,
  ...App
})
app.$mount()
// #endif


// vue3 配置方案
// #ifdef VUE3
import { createSSRApp } from 'vue'
import { createI18n } from 'vue-i18n'

import App from './App.vue'

const i18n = createI18n(i18nConfig)
export function createApp() {
  const app = createSSRApp(App)
  app.use(i18n)
  return {
    app
  }
}
// #endif

使用多语言模块

通过 uni.setLocale(lang) 并 that.$i18n.locale = lang; 进行当前语言的切换,注意this 应指向 Vue

在界面上 通过 {{ $t( ‘text’ ) }} 引入多语言文本

Vue
<template>
<view class="list-item">
  <button>{{$t('login.login')}}</button>
</template>

在 js 中 通过 this.$t( ‘text’ ) 引入多语言文本

JavaScript
that = this
// ....
data() {
  return {
    langList: [{
      text: '简体中文',
      code: 'zh-Hans'
    }, {
      text: 'English',
      code: 'en'
    }],
    nowLang: ''
  };
},
methods: {
    changeLanguage(c) {
        const lang = c.code;
        uni.showModal({
            title: this.$t('message.changeLang.title'),
            content: this.$t('message.changeLang.content')
            success(e) {
                if (e.confirm) {
                    // 设置当前语言环境
                    uni.setLocale(lang);
                    // 在当前 VueI18n 实例中切换语言
                    that.$i18n.locale = lang;
                }
            }
        })
    }
}

在 .json 文件中使用 %text% 引用多语言文本

JSON
"tabBar": {
    "selectedColor": "rgba(249,94,0,1)",
    "list": [
        {
            "text": "%tabBar.index%",
            // ..
        },
        {
            "text": "%tabBar.live%",
            // ..
        },
        {
            "text": "%tabBar.song%",
            // ..
        },
        {
            "text": "%tabBar.my%",
            // ..
        }
    ]
},

效果展示

%title插图%num
TypeScript内容
安装 uni-ui 组件库

调用第三方样式组件并实现自动导入 节约开发成本

uni-uiuniapp 官方推出。使用安全放心,并且支持多端兼容开发

下载包

PowerShell
pnpm i @dcloudio/uni-ui
# uni-ui 使用了 sass
npm install sass --save-dev

配置 easycom

easycomuniapp 特有的配置,在 pages.json 设置后就可以完成组件的自动导入

pages.json
{
  // 组件自动导入
  "easycom": {
    "autoscan": true,
    "custom": {
      // uni-ui 规则如下配置  // [!code ++]
      "^uni-(.*)": "@dcloudio/uni-ui/lib/uni-$1/uni-$1.vue" // [!code ++]
    }
  },
  "pages": [
    // …省略
  ]
}

安装类型声明文件

使组件代码的调用有类型提示

PowerShell
pnpm i -D @uni-helper/uni-ui-types

配置类型声明文件

如有报错请将 vscodeVue - Official 插件降级到 2.0.12

tsconfig.json
{
  "compilerOptions": {
    // ...
    "types": [
      "@dcloudio/types", // uni-app API 类型
      "miniprogram-api-typings", // 原生微信小程序类型
      "@uni-helper/uni-app-types", // uni-app 组件类型
      "@uni-helper/uni-ui-types" // uni-ui 组件类型  // [!code ++]
    ]
  },
  // vue 编译器类型,校验标签类型
  "vueCompilerOptions": {
    "nativeTags": ["block", "component", "template", "slot"]
  }
}
安装 pinia

piniavue3 项目中使用的全局数据共享依赖

安装pinia和 持久化 插件

PowerShell
# 强制安装 pinia
# 如果安装出现报错比如说:Pinia 依赖的 
# @vue/composition-api 要求 Vue 的版本在 “>= 2.5 < 2.7” 范围内,
# 但实际上你的项目使用的是 Vue 3。
# 对于@vue/composition-api是Vue2版本提供组合式API的插件,
# Vue3不需要所以碰到这个问题直接强制安装pinia
npm install pinia@2.2.0 --force
npm install pinia-plugin-persistedstate

还有一种方式是直接升级 vue 版本,再安装 pinia

PowerShell
npm install vue@^3.5.11

配置 Pinia

建议是配置完 pinia 相关内容后,再导入到 mian.ts 入口

src/stores/index.ts
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'
src/main.ts
import { createSSRApp } from "vue";
import App from "./App.vue";
import pinia from "./stores";

export function createApp() {
  const app = createSSRApp(App);
  app.use(pinia);
  return {
    app,
  };
}

创建 pinia 数据模块

为了方便每个模块独立管理,可以在创建的 src/stores 下新建 modules 文件夹,存放 pinia 数据

src/stores/modules/user.ts
import { defineStore } from "pinia";
import { ref } from "vue";

type UserInfo = {
    name: string
}

export const useUserInfoStore = defineStore('userInfo', () => {
    const userInfo = ref<UserInfo>()
    const setUserInfo = (val: UserInfo) => {
        userInfo.value = val
    }
    const clearUserInfo = () => {
        userInfo.value = undefined
    }
    return { userInfo, setUserInfo, clearUserInfo }
}, {
    // 修正本地化存放的操作 为兼容多平台的存储策略
    persist: {
        storage: {
            getItem(key) {
                return uni.getStorageSync(key)
            },
            setItem(key, value) {
                uni.setStorageSync(key, value)
            },
        },
    }
})

pinia 的入口文件直接导入进来即可

src/stores/index.ts
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/user'

使用 pinia 数据

Vue
<script setup lang="ts">
import { ref } from 'vue'
import { useUserInfoStore } from '@/stores';
const userInfoStore = useUserInfoStore()
const login = () => {
  userInfoStore.setUserInfo({ name: '屎猫猫' })
}
const clear = () => {
  userInfoStore.clearUserInfo()
}
</script>
<template>
  {{ userInfoStore.userInfo }}
  <button @tap="login">登录</button>
  <button @tap="clear">清除</button>
</template>

效果展示

%title插图%num