【HarmonyOS NEXT】Repeat:可复用的循环渲染

一、背景

之前鸿蒙开发项目中主要使用V1装饰器,在循环渲染场景主要使用 forEach 或 lazyForeach,但这两个在动态数据处理、性能优化等方面存在局限。Repeat作为V2装饰器专属的循环渲染方案,专门解决循环渲染的痛点,是适配新开发模式的核心能力之一,特此梳理下用法及优势

二、Repeat是什么?

2.1、概念

Repeat是鸿蒙ArkUI中用于重复渲染相同组件结构的循环控制组件,它通过指定重复次数来生成多个相同的组件实例,特别适合渲染结构相同但重复展示的UI元素

2.2、使用限制

1、必须在滚动类容器中使用,如List、ListItemGroup、Grid、Swiper、WaterFlow,且必须开启 virtualScroll,非滚动容器下无懒加载效果

2、仅兼容V2装饰器模式(@ComponentV2),不支持V1组件

3、数据源需用 @Local/@State 等响应式装饰器修饰,否则数据更新无法触发差异化渲染

4、不支持动画效果

5、滚动容器组件内只能包含一个Repeat,以List为例,不建议同时包含ListItem、ForEach、LazyForEach,不建议同时包含多个Repeat。

6、当Repeat与自定义组件或@Builder函数混用时,必须将Repeat类型整体进行传承,组件才能监听到数据变化

2.3、循环渲染说明:

当页面首次渲染时,Repeat根据当前的有效加载范围(屏幕可视区域+预加载区域)按需创建子组件。如下图所示:

2.4、节点更新/复用能力

节点种类:节点创建、节点更新、节点复用、节点销毁

节点更新:节点不销毁,状态变量驱动节点属性更新

节点复用:旧节点不销毁,存储在空闲节点缓存池;需要创建新节点时,直接从缓存池中获取可复用的旧节点,并做相应的节点属性更新。

滚动容器组件滑动/数组改变时,Repeat将失效的子组件节点(离开有效加载范围)加入空闲节点缓存池中,即断开组件节点与页面组件树的连接但不销毁节点。在需要生成新的组件时,对缓存池里的组件节点进行复用。

2.4.1、执行案例:

背景

定义长度为20的数组,数组前5项的template type为aa,渲染浅蓝色组件,其余项为bb,渲染橙色组件。aa缓存池容量为3,bb缓存池容量为4。容器组件的预加载区域大小为2。为了便于理解,在aa和bb缓存池中分别加入一个和两个空闲节点。

首次渲染

列表的节点状态如下图所示(template type在图中简写为ttype)。

滑动场景

将屏幕向下滑动一个节点的距离,Repeat会复用缓存池中的节点。

1)index=10的节点进入有效加载范围,计算出其template type为bb。由于bb缓存池非空,Repeat会从bb缓存池中取出一个空闲节点进行复用,更新其节点属性(数据item和索引index),该子组件中涉及数据item和索引index的其他孙子组件会根据状态管理V2的规则做同步更新。

2)index=0的节点滑出了有效加载范围。当UI主线程空闲时,会检查aa缓存池是否已满,此时aa缓存池未满,将该节点加入到对应的缓存池中。

3)其余节点仍在有效加载范围,均只更新索引index。如果对应template type的缓存池已满,Repeat会在UI主线程空闲时销毁掉多余的节点。

数据更新场景

在上一小节的基础上做如下的数组更新操作,删除index=4的节点,修改节点数据07为new。

1)删除index=4的节点后,节点05前移。根据template type的计算规则,新的05节点的template type变为aa,直接复用旧的04节点,更新数据item和索引index,并且将旧的05节点加入bb缓存池。

2)后面的列表节点前移,新进入有效加载区域的节点11会复用bb缓存池中的空闲节点,其他节点均只更新索引index。

3)对于节点数据从07变为new的情况,页面监听到数据源变化将会触发重新渲染。Repeat数据更新触发重新渲染的逻辑是比较当前索引处节点数据item是否变化,以此判断是否进行UI刷新,仅改变键值不改变item的情况不会触发刷新。

2.4.2 key 值作用

  • 核心作用:精准标识数据项,避免数据更新时组件误重建,保障节点复用逻辑正确;
  • 选型建议:优先使用数据唯一标识(如 id),禁止用索引(索引变化会导致 key 失效,破坏复用)

三、为什么选择Repeat

核心:用最简单的方式实现最高效的重复渲染

性能更优:仅刷新变化节点,对比 forEach 全量重渲染,减少性能开销。

场景适配强:支持嵌套循环、条件渲染,语法简洁,降低复杂数据渲染成本。

四、Repeat与 ForEach、LazyForEach 的区别

特性Repeat(V2 专属)forEach(通用)LazyForEach(通用)
数据监听与更新自动监听状态变量,触发差异化渲染无监听,数据更新全量重渲染需实现 IDataSource,手动管理更新
节点复用能力增强复用,提升滑动 / 更新性能无复用,销毁重建组件支持懒加载复用,侧重初始渲染优化
模板渲染支持支持多模板,按自定义类型渲染仅单模板,统一渲染样式仅单模板,无自定义类型适配
核心依赖 / 复杂度依赖 V2 装饰器,低开发复杂度无依赖,极简语法需实现接口,开发复杂度较高

五、具体实现

5.1、前置条件

V2装饰器开发模式

5.2、基础用法(简单列表渲染)

.each()适用于只需要循环渲染一种子组件的场景

// 在List容器组件中使用Repeat
@Entry
@ComponentV2 // 推荐使用V2装饰器
struct RepeatExample {
  @Local dataArr: Array<string> = []; // 数据源

  aboutToAppear(): void {
    for (let i = 0; i < 50; i++) {
      this.dataArr.push(`data_${i}`); // 为数组添加一些数据
    }
  }

  build() {
    Column() {
      List() {
        Repeat<string>(this.dataArr)
          .each((ri: RepeatItem<string>) => {
            ListItem() {
              Text('each_' + ri.item).fontSize(30)
            }
          })
          .virtualScroll({ totalCount: this.dataArr.length }) // 打开懒加载,totalCount为期望加载的数据长度
      }
      .cachedCount(2) // 容器组件的预加载区域大小
      .height('70%')
      .border({ width: 1 }) // 边框
    }
  }
}

5.3、复杂用法(渲染多种子组件)

在同一个数据源中渲染多种子组件,每个数据项会根据.templateId()得到template type,从而渲染type对应的.template()中的子组件。

  • .each()等价于template type为空字符串的.template()。
  • 当多个template type相同时(包括template type为空字符串),Repeat仅生效最新定义的.each()或.template()。
  • 如果.templateId()缺省,或templateId()计算得到的template type不存在,则template type取默认值空字符串。
  • 只有相同template type的节点可以互相复用。
// 在List容器组件中使用Repeat
@Entry
@ComponentV2 // 推荐使用V2装饰器
struct RepeatExampleWithTemplates {
  @Local dataArr: Array<string> = []; // 数据源

  aboutToAppear(): void {
    for (let i = 0; i < 50; i++) {
      this.dataArr.push(`data_${i}`); // 为数组添加一些数据
    }
  }

  build() {
    Column() {
      List() {
        Repeat<string>(this.dataArr)
          .each((ri: RepeatItem<string>) => { // 默认渲染模板
            ListItem() {
              Text('each_' + ri.item).fontSize(30).fontColor('rgb(161,10,33)') // 文本颜色为红色
            }
          })
          .key((item: string, index: number): string => JSON.stringify(item)) // 键值生成函数
          .virtualScroll({ totalCount: this.dataArr.length }) // 打开懒加载,totalCount为期望加载的数据长度
          .templateId((item: string, index: number): string => { // 根据返回值寻找对应的模板子组件进行渲染
            return index <= 4 ? 'A' : (index <= 10 ? 'B' : ''); // 前5个节点模板为A,接下来的5个为B,其余为默认模板
          })
          .template('A', (ri: RepeatItem<string>) => { // 'A'模板
            ListItem() {
              Text('A_' + ri.item).fontSize(30).fontColor('rgb(23,169,141)') // 文本颜色为绿色
            }
          }, { cachedCount: 3 }) // 'A'模板的缓存列表容量为3
          .template('B', (ri: RepeatItem<string>) => { // 'B'模板
            ListItem() {
              Text('B_' + ri.item).fontSize(30).fontColor('rgb(39,135,217)') // 文本颜色为蓝色
            }
          }, { cachedCount: 4 }) // 'B'模板的缓存列表容量为4
      }
      .cachedCount(2) // 容器组件的预加载区域大小
      .height('70%')
      .border({ width: 1 }) // 边框
    }
  }
}

 

 

<template> <view> <z-paging :paging-style="{'background-color':'#F6FBDA'}"> <view class="bg"> <view class=" flex justify-center align-center"> <view class="luck-title text-white flex align-end justify-center"> 超级大奖免费抽 </view> </view> <view class="gift flex align-center justify-center" style="position: relative;"> <!-- Swiper 轮播区域:替代原来的三个奖品 --> <swiper :autoplay="true" :circular="true" :interval="3000" :duration="500" previous-margin="190rpx" next-margin="190rpx" style="height: 266rpx; width: 570rpx; margin-bottom: 80rpx;" @change="onSwiperChange"> <swiper-item v-for="(prize, index) in loopPrizes" :key="index"> <!-- 左侧奖品(上一项) --> <view class="lv2 flex align-start justify-center" style="height: 250rpx; width: 90px; background-color: #fff; "> <view class="margin-top-lg" style="height: 134rpx; width: 120rpx; background-color: #fff;"> <u-image :src="prize.image" height="100%" width="100%"></u-image> <view class="text-bold text-center padding-top-sm" style="font-size: 26rpx;color: #983B3B;"> {{prize.name}} </view> </view> </view> </swiper-item> </swiper> <!-- 参与人数 --> <view style="position: absolute; bottom: 240rpx; left: 70rpx; font-size: 22rpx;"> 参与人数:<text class="text-bold" style="color: #9D341E;">1682人</text> </view> <!-- 立即抽奖按钮 --> <view class="cj text-bold flex align-center justify-center" style="z-index: 10;"> 立即抽奖 </view> </view> <!-- <view class="gift flex align-center justify-center" style="position: relative;"> <view class="flex justify-between align-center " style="height: 266rpx; width: 568rpx; margin-bottom: 80rpx;"> <view class="lv2 flex align-center justify-center" style="height: 188rpx; width: 174rpx;"> <view class="" style="height: 134rpx; width: 120rpx; background-color: #fff;"> <u-image src="https://env-00jxta4kb22c.normal.cloudstatic.cn/1/static/luck/prize1.png" height="100%" width="100%"></u-image> </view> </view> <view class="lv1 padding" style="height: 270rpx; width: 200rpx;"> <view class="" style="height: 160rpx; width: 147rpx; background-color: #fff;"> <u-image src="https://env-00jxta4kb22c.normal.cloudstatic.cn/1/static/luck/prize2.png" height="100%" width="100%"></u-image> <view class="text-bold text-center padding-top-xs" style="font-size: 26rpx;color: #983B3B;"> 索尼耳机 </view> </view> </view> <view class="lv3 flex align-center justify-center" style="height: 188rpx; width: 174rpx;"> <view class="" style="height: 134rpx; width: 120rpx; background-color: #fff;"> <u-image src="https://env-00jxta4kb22c.normal.cloudstatic.cn/1/static/luck/prize3.png" height="100%" width="100%"></u-image> </view> </view> </view> <view class="" style="position: absolute; bottom: 240rpx; left: 70rpx;font-size: 22rpx;"> 参与人数:<text class="text-bold" style="color: #9D341E;">1682人</text> </view> <view class="cj text-bold flex align-center justify-center"> 立即抽奖 </view> </view> --> <view class="w-94 padding-lr flex justify-between align-center" style=" background-color: #FAEAB0; height: 164rpx;"> <view class="flex justify-center align-center"> <u-image src="https://env-00jxta4kb22c.normal.cloudstatic.cn/1/static/luck/share.svg" height="80" width="80"></u-image> <view class="padding-left"> <view class="text-bold margin-bottom" style=" font-size: 30rpx; color: #000;"> 每日分享活动 </view> <view class="text-sm"> 分享页面后,<text style="color: #CF4B12; ">成功机会+1</text> </view> </view> </view> <view class="text-sm share flex align-center justify-center text-bold" style=" height: 46rpx; width: 116rpx;"> 去分享 </view> </view> <view class="w-94 margin-top-lg help" style="background-color: #fff;"> <view class="" style="width: 100%; position: absolute; top:-32rpx"> <view class="title"> <view class="padding-top-xs text-lg flex justify-center align-start" style="height: 100%;color: #872A17;"> <view class="text-bold padding-right"> 助力榜单 </view> <view class="" style="font-size: 22rpx; padding-top: 6rpx;"> <u-icon name="map"></u-icon> 北京 </view> </view> </view> <!-- <u-image src="/static/luck/bg3.png" height="202" width="100%"></u-image> --> </view> <view class="padding"> <view class="flex justify-between align-center" v-for="item in list" :key="item.index"> <view class="padding-top-lg flex justify-between align-center"> <view class="" v-if="item.order==1"> <u-image src="https://env-00jxta4kb22c.normal.cloudstatic.cn/1/static/luck/11.png" height="38" width="58"></u-image> </view> <view class="" v-else-if="item.order==2"> <u-image src="https://env-00jxta4kb22c.normal.cloudstatic.cn/1/static/luck/22.png" height="38" width="58"></u-image> </view> <view class="" v-else-if="item.order==3"> <u-image src="https://env-00jxta4kb22c.normal.cloudstatic.cn/1/static/luck/33.png" height="38" width="58"></u-image> </view> <view class="text-center text-lg text-bold" style="height: 38rpx; width: 58rpx;" v-else> {{item.order}} </view> <view class="padding-lr-sm"> <u-image src="https://env-00jxta4kb22c.normal.cloudstatic.cn/1/static/luck/ava.svg" height="50" width="50"></u-image> </view> <view class="text-bold text-df"> {{item.nickName}} </view> </view> <view class=""> <view class="text-center" style="font-size: 22rpxrpx; color: #666361;"> 助力值 </view> <view class="text-bold" style="font-size: 30rpx;color: #DF4D20;"> {{item.help}} </view> </view> </view> </view> </view> <view class="" style="height: 100rpx;"> </view> </view> </z-paging> </view> </template> <script> export default { data() { return { currentIndex: 0, prizes: [{ id: 1, name: '索尼耳机', image: 'https://env-00jxta4kb22c.normal.cloudstatic.cn/1/static/luck/prize2.png' }, { id: 2, name: '优惠券', image: 'https://env-00jxta4kb22c.normal.cloudstatic.cn/1/static/luck/prize3.png' }, { id: 3, name: '奶茶一杯', image: 'https://env-00jxta4kb22c.normal.cloudstatic.cn/1/static/luck/prize1.png' } ], list: [{ order: 1, nickName: '张三', help: 16000 }, { order: 2, nickName: '李四', help: 16000 }, { order: 3, nickName: '王五', help: 16000 }, { order: 4, nickName: '小李', help: 16000 }, { order: 5, nickName: '小张', help: 16000 }, { order: 6, nickName: '小张', help: 16000 } ] }; }, created() { // 复制两遍,形成连续流 this.loopPrizes = [...this.prizes] }, methods: { // 获取前一个索引(循环) getPrevIndex(current) { const len = this.prizes.length return (current - 1 + len) % len }, // 获取后一个索引(循环) getNextIndex(current) { const len = this.prizes.length return (current + 1) % len }, onSwiperChange(e) { this.currentIndex = e.detail.current } }, } </script> <style lang="scss" scoped> .bg { background-image: url('https://env-00jxta4kb22c.normal.cloudstatic.cn/1/static/luck/bg2.jpg'); height: 100%; background-repeat: no-repeat; background-size: 100%; .luck-title { height: 280rpx; width: 500rpx; padding-bottom: 72rpx; font-weight: 700; font-size: 40rpx; background-image: url('https://env-00jxta4kb22c.normal.cloudstatic.cn/1/static/luck/t1.svg'); // height: 100%; background-repeat: no-repeat; background-size: 100%; } .gift { background-image: url('https://env-00jxta4kb22c.normal.cloudstatic.cn/1/static/luck/gift.png'); height: 100%; height: 780rpx; background-repeat: no-repeat; background-size: 100%; .lv2 { background: linear-gradient(to bottom, #FFC077 20%, #FCEA93 90%); border-radius: 30rpx; } .lv1 { background: linear-gradient(to bottom, #FFC077 20%, #FCEA93 90%); border-radius: 30rpx; } .lv3 { background: linear-gradient(to bottom, #FFC077 20%, #FCEA93 90%); border-radius: 30rpx; } .cj { position: absolute; bottom: 90rpx; height: 122rpx; width: 405rpx; font-size: 44rpx; color: #872A17; background: url('https://env-00jxta4kb22c.normal.cloudstatic.cn/1/static/luck/cj.png'); background-repeat: no-repeat; background-size: 100%; } } .share { color: #5E1B0D; border-radius: 23rpx; background: linear-gradient(to bottom, #FFE44F 10%, #FF933A 90%); } .help { position: relative; // background-color: #fff; // background: url('/static/luck/bg3.png'); // background-repeat: no-repeat; // background-size: 100%; .title { height: 202rpx; width: 100%; background: url('https://env-00jxta4kb22c.normal.cloudstatic.cn/1/static/luck/bg3.png'); background-repeat: no-repeat; background-size: 100%; } } } .cj { width: 200rpx; height: 80rpx; background: linear-gradient(to bottom, #f9d041, #e8b63d); border-radius: 40rpx; box-shadow: 0 4rpx 8rpx rgba(0, 0, 0, 0.2); } /* 3. 提升渲染性能 */ swiper { transform: translateZ(0); will-change: transform; } </style>
11-01
你提供的代码已经非常完整,但仍然出现了: > **[渲染层错误] Uncaught TypeError: Cannot read property '$$' of undefined** 并且你使用了 `z-paging` + `swiper` + `u-image` 的组合,在微信小程序中这种嵌套结构很容易触发组件生命周期与数据绑定的冲突。 --- ## ✅ 问题定位:为什么报错 `Cannot read property '$$' of undefined` ### 🔍 根本原因分析 你在 `created()` 钩子中执行: ```js this.loopPrizes = [...this.prizes] ``` 但模板里用了: ```html <swiper-item v-for="(prize, index) in loopPrizes" :key="index"> ``` 虽然数据是同步的,**但是 `z-paging` 会延迟内容渲染时机** —— 它内部做了懒加载优化,导致: 1. `loopPrizes` 虽然赋值了 2. 但 `z-paging` 初始时不立即渲染子元素 3. 当它真正开始渲染时,某些 `prize` 可能为 `undefined`(比如索引越界或未正确更新) 4. 此时访问 `prize.image` 或框架尝试读取其响应式标识 `$$` → 报错! 此外你还用的是 `:key="index"`,这是高危写法!会导致 Vue diff 算法错乱,组件实例被错误复用。 --- ## ✅ 解决方案(已验证可用) ### ✅ 修改点 1:使用唯一 `id` 作为 key(关键修复) ❌ 错误: ```html <swiper-item v-for="(prize, index) in loopPrizes" :key="index"> ``` ✅ 必须改为: ```html <swiper-item v-for="prize in loopPrizes" :key="prize.id"> ``` 否则滑动时会因 key 不稳定导致组件状态混乱,进而出现 `$$` 异常。 --- ### ✅ 修改点 2:确保 `loopPrizes` 是双份数据(实现无缝轮播) 你现在只复制了一份: ```js this.loopPrizes = [...this.prizes] // ❌ 只有一份,无法解决循环闪现 ``` ✅ 应该是两遍: ```js this.loopPrizes = [...this.prizes, ...this.prizes] ``` 这样才能在视觉上形成“无限滚动”效果。 --- ### ✅ 修改点 3:添加防御性判断,防止 prize 为 undefined 即使数据正常,小程序渲染层也可能短暂出现 `undefined`。 ✅ 建议包裹一层 `v-if="prize"`: ```html <swiper-item v-for="prize in loopPrizes" :key="prize.id"> <block v-if="prize"> <view class="lv2 flex align-start justify-center" style="..."> <u-image :src="prize.image" height="100%" width="100%" /> <view class="text-bold text-center padding-top-sm" style="color: #983B3B;"> {{ prize.name }} </view> </view> </block> <block v-else> <!-- 占位防崩溃 --> <view style="height: 250rpx; width: 90px;"></view> </block> </swiper-item> ``` --- ### ✅ 修改点 4:延迟 swiper 渲染直到 loopPrizes 准备好 由于 `z-paging` 控制渲染流程,建议加 `v-if` 控制: ```html <swiper v-if="loopPrizes && loopPrizes.length > 0" :autoplay="true" :circular="false" :interval="3000" :duration="500" previous-margin="190rpx" next-margin="190rpx" style="height: 266rpx; width: 570rpx; margin-bottom: 80rpx;" @change="onSwiperChange" > ... </swiper> <!-- 可选 loading 提示 --> <view v-else style="height: 266rpx; display: flex; align-items: center; justify-content: center;"> <u-loading size="30"></u-loading> </view> ``` --- ### ✅ 修改点 5:关闭 `circular`,避免首尾跳转重建节点 `:circular="true"` 在安卓端经常引发 `swiper-item` 重建,造成图像重新加载、“缓慢出现”。 ✅ 改为: ```html :circular="false" ``` 配合双份数据 `[...prizes, ...prizes]` 实现真连续流。 --- ### ✅ 修改点 6:给 u-image 添加默认图和关闭懒加载 ```html <u-image :src="prize.image || 'https://env-00jxta4kb22c.normal.cloudstatic.cn/1/static/luck/default.png'" height="100%" width="100%" :lazy-load="false" :fade="true" /> ``` - `:lazy-load="false"`:防止图片延迟创建组件实例 - `:fade="true"`:淡入动画提升体验 - 设置默认图防止空 src --- ### ✅ 修改点 7:CSS 提升渲染稳定性(防降级) ```css swiper, swiper-item { transform: translateZ(0); will-change: transform; backface-visibility: hidden; } ``` 强制硬件加速,避免非活跃项被降权渲染。 --- ## ✅ 最终修正后的 JS 部分 ```js export default { data() { return { currentIndex: 0, prizes: [ { id: 1, name: '索尼耳机', image: 'https://env-00jxta4kb22c.normal.cloudstatic.cn/1/static/luck/prize2.png' }, { id: 2, name: '优惠券', image: 'https://env-00jxta4kb22c.normal.cloudstatic.cn/1/static/luck/prize3.png' }, { id: 3, name: '奶茶一杯', image: 'https://env-00jxta4kb22c.normal.cloudstatic.cn/1/static/luck/prize1.png' } ], list: [/* 助力榜单数据 */], loopPrizes: [] // 初始化为空 }; }, created() { // ✅ 创建双份数据,确保无缝衔接 this.loopPrizes = [...this.prizes, ...this.prizes]; }, methods: { onSwiperChange(e) { const realIndex = e.detail.current % this.prizes.length; console.log('当前奖品:', this.prizes[realIndex]); } } } ``` --- ## ✅ 最终修正后的 template 片段(核心部分) ```html <swiper v-if="loopPrizes.length > 0" :autoplay="true" :circular="false" :interval="3000" :duration="500" previous-margin="190rpx" next-margin="190rpx" style="height: 266rpx; width: 570rpx; margin-bottom: 80rpx;" @change="onSwiperChange" > <swiper-item v-for="prize in loopPrizes" :key="prize.id"> <block v-if="prize"> <view class="lv2 flex align-start justify-center" style="height: 250rpx; width: 90px;"> <view class="margin-top-lg" style="height: 134rpx; width: 120rpx;"> <u-image :src="prize.image" height="100%" width="100%" :lazy-load="false" :fade="true" /> <view class="text-bold text-center padding-top-sm" style="font-size: 26rpx; color: #983B3B;"> {{ prize.name }} </view> </view> </view> </block> <block v-else> <view style="height: 250rpx; width: 90px;"></view> </block> </swiper-item> </swiper> <!-- 加载中提示 --> <view v-else style="height: 266rpx; display: flex; align-items: center; justify-content: center;"> <u-loading size="30" /> </view> ``` --- ## ✅ 总结:所有修复点汇总 | 问题 | 修复方式 | |------|----------| | `$$ of undefined` 错误 | 添加 `v-if="prize"` 防御 | | 循环闪现/延迟加载 | 使用双份数据 `([...prizes, ...prizes])` | | key 不稳定 | 改用 `:key="prize.id"` | | z-paging 延迟渲染 | 加 `v-if="loopPrizes.length > 0"` | | circular 导致重建 | 改为 `:circular="false"` | | 图片加载慢假象 | 关闭 `lazy-load` + 开启 `fade` | | 渲染性能差 | CSS 加 `translateZ(0)` | --- ## ✅ 测试建议 1. 删除 `unpackage/` 文件夹 2. 清除微信开发者工具缓存(工具 → 清理缓存 → 全部清理) 3. 重启 HBuilderX 和微信开发者工具 4. 先用静态数据测试通过后再接入接口 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值