在 UniApp 开发中,我们经常需要通过 uni.request
获取服务器返回的 JSON 数据,并将其绑定到页面或进行逻辑处理。
但在 UniApp X(基于 UTS) 中,由于引入了 强类型语言特性,处理 JSON 数据的方式与 JS 有明显不同。如果你还停留在 JS 的开发习惯中,很容易踩坑。
本文将带你从 JS 的 JSON 处理方式出发,逐步过渡到 UTS 的两种主流处理方式:
- ✅ UTSJSONObject:兼容 JS 的灵活方式
- ✅ type + 泛型:强类型推荐方案
🧩 一、JS 中的 JSON 处理方式(回顾)
在 JS 中,uni.request
获取的 JSON 数据可以直接使用 .属性名
的方式访问:
uni.request({
url: "https://example.com/api",
success: (res) => {
console.log(res.data.data[0].plugin_name);
}
});
但这种方式在 UTS 中会报错,因为:
UTS 是强类型语言,res.data 是 any 类型,不能安全访问未定义的属性。
🛠️ 二、UTS 中处理 JSON 的两种方式
方式一:UTSJSONObject(兼容 JS 的灵活方式)
1. 基本用法:通过下标访问属性
uni.request({
url: "https://example.com/api",
success: (res) => {
const data = res.data as UTSJSONObject;
const pluginName = (data["data"] as UTSJSONObject[])[0]["plugin_name"];
console.log(pluginName);
}
});
2. 使用 keypath 访问深层属性(推荐)
UTSJSONObject 支持 keypath 写法,穿透访问嵌套属性:
const pluginName = data.getString("data[0].plugin_name");
console.log(pluginName); // 输出:插件名称A
3. 其他 keypath 方法
方法名 | 返回类型 | 说明 |
---|---|---|
getString(path: string) | string | 获取字符串 |
getNumber(path: string) | number | 获取数字 |
getBoolean(path: string) | boolean | 获取布尔值 |
getJSON(path: string) | UTSJSONObject | 获取对象 |
getArray(path: string) | UTSJSONObject[] | 获取数组 |
getAny(path: string) | any | 获取任意类型 |
⚠️ 缺点:没有类型提示、需要手动处理类型转换、性能略差。
方式二:type + 泛型(强类型推荐方式)
1. 定义数据类型(使用 HBuilderX 自动生成)
将服务器返回的 JSON 数据粘贴到 HBuilderX 的 JSON 编辑器中,右键选择 “转 type”,自动生成类型定义。
例如服务器返回如下数据:
{
"code": 200,
"desc": "",
"data": [
{
"plugin_id": 123,
"plugin_name": "插件名称A"
}
]
}
生成的类型为:
type Data = {
plugin_id: number;
plugin_name: string;
};
type IRootType = {
code: number;
desc: string;
data: Data[];
};
2. 使用泛型调用 uni.request
uni.request<IRootType>({
url: "https://example.com/api",
success: (res) => {
if (res.data && res.data.data.length > 0) {
console.log(res.data.data[0].plugin_name); // 直接使用 . 操作符
}
}
});
3. 泛型写法说明
- ✅ 泛型写法:
uni.request<IRootType>(...)
,告诉编译器期望返回的数据类型。 - ✅ 数组类型:如果
res.data
是数组,应写为uni.request<IRootType[]>(...)
- ✅ 安全访问:使用
?.
防止空值访问错误,如res.data?.data
🧠 三、type 与泛型的常见问题
1. type 要写在 export default
之前
为了在 data()
或 computed
中使用类型定义,必须把 type
写在 export default
之前:
type Data = {
plugin_id: number;
plugin_name: string;
};
export default {
data() {
return {
dataList: [] as Data[]
};
}
};
2. 属性可能缺失怎么办?
使用 ?
表示该属性可为空:
type Data = {
plugin_id: number;
plugin_name?: string; // plugin_name 可能不存在
age: number | null; // age 可为 null
};
3. 泛型支持情况
- ✅ 当前版本支持传入
type
作为泛型 - ❌ 不支持动态泛型,如将泛型作为函数参数传递
- ✅ Web 端目前仅支持类型校验,不支持实例化
📦 四、实战案例:网络请求 + 数据绑定 + 分页加载
<template>
<list-view style="flex: 1;" @scrolltolower="loadData">
<template v-for="(item, index) in dataList" :key="index">
<list-item style="flex-direction: row; padding: 10px;">
<text>{{ item.plugin_name }}</text>
</list-item>
</template>
<list-item v-if="loadingText">
<text>{{ loadingText }}</text>
</list-item>
</list-view>
</template>
<script lang="uts">
type Plugin = {
plugin_id: number;
plugin_name: string;
};
type ResponseType = {
code: number;
desc: string;
data: Plugin[];
};
export default {
data() {
return {
dataList: [] as Plugin[],
loading: false,
isEnded: false,
currentPage: 1
};
},
computed: {
loadingText(): string {
if (this.loading) return "加载中...";
if (this.isEnded) return "没有更多了";
return "";
}
},
onLoad() {
this.loadData();
},
methods: {
loadData() {
if (this.loading || this.isEnded) return;
this.loading = true;
uni.request<ResponseType>({
url: "https://example.com/api",
data: {
page: this.currentPage,
pageSize: 10
},
success: (res) => {
if (res.data?.data?.length) {
this.dataList.push(...res.data.data);
this.currentPage++;
} else {
this.isEnded = true;
}
},
fail: (err) => {
console.error("加载失败", err);
},
complete: () => {
this.loading = false;
}
});
}
}
};
</script>
🧪 五、UTS JSON 处理对比表
特性 | UTSJSONObject | type + 泛型 |
---|---|---|
类型提示 | ❌ 无 | ✅ 有 |
代码可读性 | ⬇️ 略差 | ✅ 好 |
类型安全 | ❌ 弱 | ✅ 强 |
性能表现 | ⬇️ 略差 | ✅ 好 |
使用难度 | ✅ 简单 | ⬇️ 稍复杂 |
适用人群 | 初学者 | 有 TS 经验者 |
推荐指数 | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
📌 六、注意事项
- ✅
UTSJSONObject
适用于键名动态或结构不稳定的数据 - ✅
type + 泛型
更适合结构固定、追求类型安全和代码提示的项目 - ⚠️
type
中属性名不能包含特殊字符如:
、-
,否则需手动处理或改用UTSJSONObject
- ⚠️ 泛型不支持动态传参,封装
request
时建议使用UTSJSONObject
🧠 最后一句话送大家:
“从 JS 到 UTS,不是语法的改变,而是对数据结构理解的升华。”
掌握好 JSON 数据的处理方式,你就能在 UniApp X 的世界里,写出更稳定、更高效、更跨平台的应用!
如果你觉得这篇文章对你有帮助,欢迎点赞、收藏、转发给还在为 UTS JSON 问题发愁的小伙伴!