HarmonyOS鸿蒙Next中使用@Watch + setTimeout实现带防抖的搜索建议功能

HarmonyOS鸿蒙Next中使用@Watch + setTimeout实现带防抖的搜索建议功能 如何使用 [@Watch](/user/Watch) + setTimeout 实现带防抖的搜索建议功能?

3 回复

使用场景

针对于任何联想搜索相关的地方,比如商品搜索、通讯录联系人查找、文章标题检索、地点搜索等等

实现思路

一、防抖控制:用户停止输入多少秒后才出发搜索,防止抖动。

this.debounceTimer = setTimeout(() => {
  this.fetchSuggestions(this.searchText.trim());
}, 300); // 300ms 防抖

二、缓存管理:使用 Map<string, string[]> 缓存相关数据列表。

  private cache: Map<string, string[]> = new Map(); // 本地缓存
   if (this.cache.has(keyword)) {
      this.suggestions = this.cache.get(keyword)!;
      return;
    }

三、使用 @State 管理状态且通过 @Watch('searchText') 来监听输入变化。

 @Watch('onSearchTextChanged')
  @State searchText: string = '';
  @State suggestions: string[] = [];
  @State isLoading: boolean = false;

完整可运行代码

@Entry
@Component
struct SearchPage {
  @Watch('onSearchTextChanged')
  @State searchText: string = '';
  @State suggestions: string[] = [];
  @State isLoading: boolean = false;

  private debounceTimer: number = 0;
  private cache: Map<string, string[]> = new Map(); // 本地缓存

  // 监听搜索框输入

  private onSearchTextChanged(newVal: string) {
    console.log(this.searchText)
    if (this.searchText.trim() === '') {
      this.suggestions = [];
      return;
    }

    // 清除上一次定时器
    clearTimeout(this.debounceTimer);

    // 设置新防抖
    this.debounceTimer = setTimeout(() => {
      this.fetchSuggestions(this.searchText.trim());
    }, 300); // 300ms 防抖
  }

  // 模拟网络请求(实际项目替换为 fetch 或 ohos.request)
  private async mockApiRequest(keyword: string): Promise<string[]> {
    // 模拟网络延迟
    // await new Promise(resolve => setTimeout(resolve, 500));

    // 返回模拟建议(实际应调用后端接口)
    const base = ['shouji', 'diannao', 'erji', 'pingban', 'shoubiao'];
    return base.filter(item => item.includes(keyword)).slice(0, 5);
  }

  private async fetchSuggestions(keyword: string) {
    // 1. 先查缓存
    if (this.cache.has(keyword)) {
      this.suggestions = this.cache.get(keyword)!;
      return;
    }

    // 2. 缓存未命中,发起请求
    this.isLoading = true;
    try {
      const result = await this.mockApiRequest(keyword);
      this.suggestions = result;

      // 3. 写入缓存
      this.cache.set(keyword, result);
    } catch (e) {
      console.error('[Search] 请求失败:', e);
      this.suggestions = ['网络错误,请重试'];
    } finally {
      this.isLoading = false;
    }
  }

  build() {
    Column({ space: 15 }) {
      Text('商品搜索')
        .fontSize(20)
        .fontWeight(FontWeight.Bold)

      // 搜索框
      TextInput({ placeholder: '请输入商品名称' })
        .onChange((value: string) => {
          this.searchText = value; // 触发 @Watch
        })
        .width('100%')
        .height(50)
        .borderRadius(8)
        .backgroundColor('#F5F5F5')

      // 加载状态
      if (this.isLoading && this.searchText.trim() !== '') {
        Text('搜索中...')
          .fontColor('#999')
          .fontSize(14)
      }

      // 建议列表
      if (this.suggestions.length > 0) {
        List({ space: 5 }) {
          ForEach(
            this.suggestions,
            (item: string, index: number) => {
              ListItem() {
                Row() {
                  Image($r('app.media.startIcon'))
                    .width(16)
                    .height(16)
                    .margin({ right: 10 })
                  Text(item)
                    .fontSize(16)
                }
                .padding(12)
                .width('100%')
                .borderRadius(6)
                .backgroundColor('#FAFAFA')
              }
            }
          )
        }
        .width('100%')
        .height(200)
      }
    }
    .padding(25)
    .width('100%')
  }
}

实现效果图

通过搜索shouji可联想带出相关的数据。

cke_47535.png

cke_34668.png

更多关于HarmonyOS鸿蒙Next中使用@Watch + setTimeout实现带防抖的搜索建议功能的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS Next中,使用@Watch装饰器监听搜索输入变化,结合setTimeout实现防抖。@Watch用于观察状态变量的变化,当输入值改变时触发回调。在回调中,先清除之前的定时器,再设置新的setTimeout延迟执行搜索建议请求。这能有效减少频繁请求,提升性能。示例代码结构包括状态变量、@Watch回调函数和防抖逻辑处理。

在HarmonyOS Next中,使用@Watch装饰器监听搜索关键词变化,结合setTimeout实现防抖的搜索建议功能,是一种高效且常见的做法。以下是核心实现步骤和代码示例:

1. 基本思路

  • 使用@State装饰器管理搜索关键词。
  • 使用@Watch装饰器监听关键词变化。
  • @Watch回调中,利用setTimeout实现防抖逻辑,延迟触发搜索建议请求。

2. 代码示例

import { SearchService } from '../services/SearchService'; // 假设的搜索服务

@Entry
@Component
struct SearchWithDebounce {
  @State keyword: string = ''; // 搜索关键词
  @State suggestions: string[] = []; // 搜索建议列表
  private timer: number | null = null; // 防抖计时器

  // 监听keyword变化
  @Watch('keyword')
  onKeywordChange() {
    // 清除之前的计时器
    if (this.timer) {
      clearTimeout(this.timer);
    }

    // 设置新的防抖计时器(延迟500毫秒)
    this.timer = setTimeout(() => {
      if (this.keyword.trim() !== '') {
        this.fetchSuggestions(this.keyword);
      } else {
        this.suggestions = []; // 关键词为空时清空建议
      }
    }, 500);
  }

  // 获取搜索建议
  async fetchSuggestions(keyword: string) {
    try {
      const result = await SearchService.getSuggestions(keyword);
      this.suggestions = result;
    } catch (error) {
      console.error('获取搜索建议失败:', error);
      this.suggestions = [];
    }
  }

  build() {
    Column() {
      // 搜索输入框
      TextInput({ placeholder: '请输入关键词' })
        .width('90%')
        .height(40)
        .onChange((value: string) => {
          this.keyword = value; // 触发@Watch监听
        })

      // 搜索建议列表
      List({ space: 10 }) {
        ForEach(this.suggestions, (item: string) => {
          ListItem() {
            Text(item)
              .fontSize(16)
              .padding(10)
          }
        })
      }
      .width('90%')
      .layoutWeight(1)
    }
    .padding(20)
    .width('100%')
    .height('100%')
  }
}

3. 关键点说明

  • 防抖逻辑:通过setTimeout延迟执行搜索请求,并在每次关键词变化时重置计时器,确保仅在用户停止输入后触发请求。
  • 资源清理:在组件销毁时(如使用aboutToDisappear生命周期)应清理计时器,避免内存泄漏。
  • 性能优化:对于频繁输入的场景,防抖能有效减少不必要的网络请求或计算开销。

4. 注意事项

  • 确保@Watch装饰器仅监听必要的状态变量,避免过度触发。
  • 根据实际需求调整防抖延迟时间(如300-800毫秒)。
  • 考虑网络请求的取消逻辑,避免旧请求覆盖新结果。

此方案结合了响应式状态管理和防抖技术,适用于实时搜索、表单验证等场景,能有效平衡用户体验与性能。

回到顶部