You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在文本框输入@符号时显示与隐藏提及组件?

社交应用提及功能实现问题解决

问题背景

我通过文本框的onChanged属性监听内容变化,想要实现社交应用的提及功能:输入@时显示提及组件,输入空格后隐藏;同时需要支持在文本中间输入@时也能触发组件。

期望实现效果

  • 检测到@符号输入时显示提及组件,输入空格则隐藏;
  • 在文本中间输入@时也能触发显示提及组件。

已尝试方案的问题

使用正则匹配含@的内容,通过分割文本判断是否显示组件,但效果不符合预期——在文本框内容中间输入@时,提及组件不会触发。

原代码

void onChanged(String value) { 
    final _mentionRegEx = RegExp(AppUtils.mentionPattern, caseSensitive: false);
    final _checkRegEx = RegExp(
      r"^@[a-zA-Z0-9_ ]+[a-zA-Z0-9_]*$",
      // caseSensitive: false,
      multiLine: true,
    );
    Iterable<Match> matches = _mentionRegEx.allMatches(value);

    for (var m in matches) {
      String match = m[0]!;
      final withoutMentonTag = match.substring(1);
      state = state.copyWith(matched: withoutMentonTag);
      print('MENTION => ${state.matched}');
    }

    final sentences = value.split(' ');
    for (var sentence in sentences) {
      print('SENTENCE => $sentence');
      final words = sentence.split(' ');
      final withMentionTag = words.last;

      if (_checkRegEx.hasMatch(sentence)) {
        toggleMentionWidget(true);
        String withoutMentionTag = withMentionTag.substring(1);
        print('MENTIONED USER => $withoutMentionTag');
      } else {
        toggleMentionWidget(false);
      }
    }
  }

问题分析与修正方案

原代码的核心问题:

  1. 文本分割逻辑有误,按空格分割后循环处理,会忽略中间位置输入的@,仅判断最后一段内容;
  2. 正则用^限制行首,只能匹配以@开头的整段内容,无法匹配文本中间的@。

修正后的代码(基础版)

void onChanged(String value) {
  // 匹配文本末尾以@开头,后跟字母、数字、下划线的内容(排除空格结尾的情况)
  final mentionMatch = RegExp(r'@[a-zA-Z0-9_]*$').firstMatch(value);
  
  if (mentionMatch != null) {
    // 提取@后的内容用于搜索用户
    final matchedText = mentionMatch.group(0)!.substring(1);
    state = state.copyWith(matched: matchedText);
    toggleMentionWidget(true);
    print('MENTION => $matchedText');
  } else {
    // 无有效@输入状态,隐藏组件
    toggleMentionWidget(false);
    state = state.copyWith(matched: '');
  }
}

代码说明

  • 正则r'@[a-zA-Z0-9_]*$'专门匹配文本末尾的@开头内容,不管@在文本的哪个位置,只要用户输入@后还没输入空格,就会触发匹配;
  • 匹配成功时显示组件并更新搜索关键词,匹配失败则隐藏组件。

进阶版(输入@ 后才隐藏组件)

如果需要严格实现「输入空格后隐藏」的逻辑(即用户输入@ 后才关闭组件),可以调整正则并增加判断:

void onChanged(String value) {
  final mentionMatch = RegExp(r'@[a-zA-Z0-9_]*\s?$').firstMatch(value);
  
  if (mentionMatch != null) {
    final matchedContent = mentionMatch.group(0)!;
    // 若匹配内容以空格结尾,说明用户结束提及输入
    if (matchedContent.endsWith(' ')) {
      toggleMentionWidget(false);
      state = state.copyWith(matched: '');
    } else {
      final matchedText = matchedContent.substring(1);
      state = state.copyWith(matched: matchedText);
      toggleMentionWidget(true);
      print('MENTION => $matchedText');
    }
  } else {
    toggleMentionWidget(false);
    state = state.copyWith(matched: '');
  }
}

这个版本可以完美满足需求:

  • 文本任意位置输入@都会触发显示提及组件;
  • 输入空格后(@后跟空格),自动隐藏组件。

内容的提问来源于stack exchange,提问作者MElochukwu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 09:31:42