UniApp X 网络请求避坑指南:从 JS 到 UTS 的 JSON 数据处理全解析

在 UniApp 开发中,我们经常需要通过 uni.request 获取服务器返回的 JSON 数据,并将其绑定到页面或进行逻辑处理。

但在 UniApp X(基于 UTS) 中,由于引入了 强类型语言特性,处理 JSON 数据的方式与 JS 有明显不同。如果你还停留在 JS 的开发习惯中,很容易踩坑。

本文将带你从 JS 的 JSON 处理方式出发,逐步过渡到 UTS 的两种主流处理方式:

  1. ✅ UTSJSONObject:兼容 JS 的灵活方式
  2. ✅ 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 处理对比表

特性UTSJSONObjecttype + 泛型
类型提示❌ 无✅ 有
代码可读性⬇️ 略差✅ 好
类型安全❌ 弱✅ 强
性能表现⬇️ 略差✅ 好
使用难度✅ 简单⬇️ 稍复杂
适用人群初学者有 TS 经验者
推荐指数⭐⭐⭐⭐⭐⭐⭐⭐

📌 六、注意事项

  • ✅ UTSJSONObject 适用于键名动态或结构不稳定的数据
  • ✅ type + 泛型 更适合结构固定、追求类型安全和代码提示的项目
  • ⚠️ type 中属性名不能包含特殊字符如 :-,否则需手动处理或改用 UTSJSONObject
  • ⚠️ 泛型不支持动态传参,封装 request 时建议使用 UTSJSONObject

🧠 最后一句话送大家:

“从 JS 到 UTS,不是语法的改变,而是对数据结构理解的升华。”
掌握好 JSON 数据的处理方式,你就能在 UniApp X 的世界里,写出更稳定、更高效、更跨平台的应用!


如果你觉得这篇文章对你有帮助,欢迎点赞、收藏、转发给还在为 UTS JSON 问题发愁的小伙伴!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值