一、文本输入类组件核心认知

(一)组件整体定位

TextInput、TextArea、Search是鸿蒙ArkTS核心文本输入类组件,基于统一输入底层能力封装,支持通用样式与高频事件;针对单行短文本、多行长文本、搜索专属三大场景做差异化优化,是移动端应用开发必备基础组件。

(二)核心选型原则与组件差异

核心原则:按输入形态和业务场景选型,禁止跨场景混用。三者核心差异、专属优势与适配场景如下:

组件名 核心特性 专属优势 适用场景
TextInput 单行输入,不自动折行 输入模式丰富,控制器光标/选框控制能力精细 账号、密码、手机号、验证码等短文本输入
TextArea 多行输入,自动折行,支持滚动 适配长文本,可配置自动高度/滚动条,支持长文本编辑控制 评论、留言、文章编辑、长备注填写
Search 单行输入,搜索场景专属 内置搜索/清除图标,默认回车搜索逻辑,降低自定义开发成本 全局搜索、商品检索、页面内搜索栏

(三)核心绑定规范与组件接口

各组件对应专属构造函数,彼此独立不通用,核心接口与绑定规则如下:

组件名 专属构造函数接口 核心可选属性
TextInput TextInputOptions text: ResourceStrcontroller: TextInputControllerplaceholder: ResourceStr
TextArea TextAreaOptions text: ResourceStrcontroller: TextAreaControllerplaceholder: ResourceStr
Search SearchOptions value: ResourceStrcontroller: SearchControllerplaceholder: ResourceStricon:string

说明ResourceStr为联合类型(Resource | string),支持直接传入字符串或通过$r引用系统/应用资源。

二、核心能力

(一)通用事件

TextInput、TextArea、Search事件触发逻辑统一,仅onSubmit回调参数存在组件差异,其余事件参数完全一致:

事件名称 功能说明
onChange 输入内容实时变化触发,用于实时校验、字数统计、数据同步、自定义过滤
onSubmit 按下回车/搜索键触发(Search支持点击搜索按钮),用于表单提交、搜索请求、内容发布
onFocus 组件获得焦点触发,用于样式高亮、提示展示、键盘唤起前置处理
onBlur 组件失去焦点触发,用于格式校验、样式恢复、草稿自动保存
onCopy 复制内容触发,用于复制监控、敏感内容脱敏、操作日志记录
onCut 剪切内容触发,用于剪切行为监控、自定义剪切逻辑
onPaste 粘贴内容触发,用于粘贴内容校验、长度限制、格式过滤
onEditChange 编辑状态变化触发,用于编辑状态监控、键盘显隐联动
onTextSelectionChange 光标/文本选中范围变化触发,用于选中内容处理、光标位置联动
onContentScroll 内容滚动触发,用于长文本滚动监控、联动布局调整
onWillInsert 系统输入法插入内容前触发,用于前置校验、非法内容拦截
onDidInsert 内容插入完成触发,用于格式后置修正、数据同步
onWillDelete 内容删除前触发,用于关键内容防删、删除确认
onDidDelete 内容删除完成触发,用于空白内容兜底、状态同步
onWillChange 文本即将变更触发(时序晚于增删事件),用于全局内容拦截、复合规则校验

时序说明onWillChange执行时序晚于onWillInsert/onWillDelete,早于onDidInsert/onDidDelete

(二)输入内容过滤

三大组件支持统一过滤方案,Search仅需将text绑定替换为value,过滤逻辑可直接复用:

  • inputFilter:原生正则过滤,轻量高效,适用于基础字符级规则
  • onWillChange:内容变更前拦截,支持自定义逻辑,适用于位置、字节、自动修正等复杂场景。
1. inputFilter 原生正则过滤

仅需编写允许的字符集,无需添加^$首尾限定符,非法字符直接拦截:

// 仅允许字母/数字(账号/验证码场景)
TextInput({ text: this.content, placeholder: '请输入字母/数字' })
  .inputFilter('[0-9A-Za-z]', (filtered) => {
    console.log('过滤的非法内容:', filtered);
  })
2. onWillChange 自定义逻辑过滤

仅支持返回boolean类型(true允许本次内容变更,false拦截变更,界面不更新),如需实现内容自动修正,需手动更新绑定的状态变量并返回false拦截原始输入,覆盖复杂业务规则:

// 首位禁止输入空格
TextInput({ text: this.inputText, placeholder: '首位无空格' })
 .onWillChange((changeInfo:EditableTextChangeValue)=>{
    return changeInfo.content.trimStart() !== "";
  })
3. 组合过滤(生产高频用法)

inputFilter做底层字符限制 + onWillChange做业务规则校验,兼顾性能与需求:

// 账号规则:仅字母/数字 + 首位不能为数字
TextInput({ text: this.account, placeholder: '字母开头,字母/数字组合' })
  .inputFilter('[0-9A-Za-z]')
  .onWillChange((newValue) => {
    return newValue.content.replace(/^[0-9]/, '') !== "";
  });

(三)组件控制器

所有控制器继承自TextContentControllerBase必须与组件一对一绑定,禁止跨组件混用,用于光标、选框、编辑状态精细控制。

1. 控制器-组件对应关系
输入组件 专属控制器 核心能力
TextInput TextInputController 单行文本光标定位、选框控制、退出编辑态
TextArea TextAreaController 多行文本光标定位、选框控制、长文本编辑适配
Search SearchController 继承TextInputController能力,适配搜索框控制
2. 通用核心方法
方法名称 功能说明 典型场景
caretPosition(pos: number): void 设置光标位置(索引从0开始) 提交后光标归位、验证码输入后光标跳转
setTextSelection(start: number, end: number): void 获焦状态下设置文本选中区域 快速选中错误文本、批量编辑前置操作
stopEditing(): void 退出编辑态,关闭自定义键盘 自定义键盘手动关闭、提交后退出编辑
3. 控制器基础使用方法
private inputController = new TextInputController();
// 光标移至文本开头
this.inputController.caretPosition(0);
// 选中0~6位字符
this.inputController.setTextSelection(0, 6);
// 主动退出编辑状态
this.inputController.stopEditing();

(四)全局焦点控制

焦点控制为页面级能力,与组件控制器解耦,是鸿蒙标准焦点管理方案:

1. 核心方法
核心方法 功能说明 参数/场景
requestFocus(id: string): boolean 指定ID组件获取焦点,唤起输入法 参数:组件唯一ID;场景:页面自动聚焦、校验失败定位
clearFocus(): void 清除全页面焦点,收起软键盘 无参数;场景:点击空白处、提交/搜索完成
2. 标准使用代码
// 获取全局焦点控制器
const focusController = this.getUIContext().getFocusController();
// 精准聚焦(组件必须绑定id)
focusController.requestFocus("account_input");
// 全局失焦,收起键盘
focusController.clearFocus();

注意:调用requestFocus前,必须为目标组件设置唯一.id('xxx'),否则聚焦失效。

(五)专属输入模式枚举

强制规范:各组件仅可使用自身专属枚举,严禁跨组件混用。

1. TextInput 专属:InputType
枚举成员 功能说明 适用场景
Normal 基础通用输入 用户名、普通文本
Number 纯数字输入 验证码、订单号
PhoneNumber 电话格式输入 手机号、座机号
Email 邮箱格式输入 邮箱登录/注册表单
Password 密码隐藏输入 账号登录密码
NUMBER_PASSWORD 纯数字密码 支付密码、锁屏密码
USER_NAME 用户名专属,支持密码库填充 账号登录/注册
NEW_PASSWORD 新密码,支持强度校验 密码重置、新用户注册
NUMBER_DECIMAL 带一位小数点数字 金额、身高、体重
URL 网址格式输入 链接填写、校验
ONE_TIME_CODE 一次性验证码(API20+) 短信验证码输入
2. TextArea 专属:TextAreaType
枚举成员 功能说明 适用场景
NORMAL 基础多行输入 评论、留言、长文本
NUMBER 纯数字多行输入 长数字序列、数字备注
PHONE_NUMBER 电话格式多行输入 批量号码录入
EMAIL 邮箱格式多行输入 邮箱批量录入
NUMBER_DECIMAL 带小数点数字 长文本内含数值
URL 网址格式 长文本内含链接
ONE_TIME_CODE 一次性验证码(API20+) 验证码批量录入
3. Search 专属:SearchType
枚举成员 功能说明 适用场景
NORMAL 通用搜索输入 全文、关键词检索
NUMBER 纯数字搜索 订单号、快递号、ID检索
PHONE_NUMBER 电话格式搜索 手机号、联系电话检索
EMAIL 邮箱格式搜索 用户邮箱检索
NUMBER_DECIMAL 小数搜索 金额、数值区间检索
URL 网址搜索 链接、外链检索
ONE_TIME_CODE 验证码检索 校验码信息检索

(六)通用回车键类型:EnterKeyType

三大组件通用枚举,自定义软键盘回车按钮样式与语义,触发后均执行onSubmit

枚举成员 键盘显示 语义 核心场景
Go 前往/箭头 执行操作、页面跳转 单输入框提交、密码框确认
Search 搜索/放大镜 搜索触发 Search组件、搜索栏
Send 发送 内容发送 聊天、评论快速发送
Next 下一个/右箭头 切换下一个输入框 表单连续输入(账号→密码→验证码)
Done 完成/对勾 结束输入、收起键盘 长文本编辑完成、表单最后一项输入
PREVIOUS 上一个/左箭头 切换上一个输入框 表单反向连续输入(验证码→密码→账号)
NEW_LINE 回车/换行 换行/确认 TextArea长文本换行、多行内容编辑

三、各组件专属能力

(一)Search 组件专属能力

基于TextInput封装,聚焦搜索场景,提供原生图标与按钮配置:

属性名称 功能说明 实战场景
searchButton 右侧搜索按钮配置(文字/样式),点击触发onSubmit 搜索栏内置提交按钮,无需自定义
searchIcon 自定义左侧搜索图标(尺寸、颜色、资源) 统一APP图标风格,适配深色模式
cancelButton 清除按钮配置(显隐规则、图标) 输入后一键清空内容

(二)TextArea 组件专属能力

聚焦多行长文本,提供排版与高度控制能力:

属性名称 功能说明 实战场景
minLines/maxLines 最小/最大行数,支持溢出滚动/截断 评论区3~5行,超出滚动
lineSpacing 行间距,支持仅行间生效 长文本排版优化,提升可读性
ellipsisMode 超长文本省略位置(首/中/尾) 非编辑态长文本预览
heightAdaptivePolicy 高度自适应策略 动态适配输入内容高度

(三)TextInput 组件专属能力

聚焦单行表单/密码场景,提供表单专属样式与交互:

1. 专属属性
属性名称 功能说明 实战场景
showUnderline 开启下划线样式,替代常规边框 表单输入框简约下划线风格
underlineColor 配置多状态下划线颜色(常态/聚焦/错误/禁用) 输入态高亮、错误态标红
showPassword/showPasswordIcon 密码显隐开关 + 显隐图标控制 密码框一键切换可见/隐藏
showUnit 输入框后置单位展示(需配合下划线) 金额框显示「元」、手机号框标注用途
showError 绑定错误提示文本,自动展示/隐藏 表单校验失败实时提示
passwordRules 密码生成规则,透传密码保险箱 新密码输入自动生成合规密码
2. 专属事件
事件名称 功能说明 实战场景
onSecurityStateChange 密码显隐状态切换回调 同步图标状态、全局显隐联动

四、工程结构

基于鸿蒙6.0 API 20、Stage模型创建InputApplication工程,标准目录结构如下:

InputApplication/
├── AppScope/
│   └── app.json5
├── entry/
│   ├── src/
│   │   ├── main/
│   │   │   ├── ets/
│   │   │   │   ├── entryability/
│   │   │   │   │   └── EntryAbility.ets
│   │   │   │   ├── pages/
│   │   │   │   │   ├── Index.ets                  // 导航主页面
│   │   │   │   │   ├── InputBasicPage.ets         // 示例1:三大组件基础用法
│   │   │   │   │   ├── RegisterFormPage.ets       // 示例2:注册表单实战
│   │   │   │   │   └── InputSearchBarPage.ets     // 示例3:顶部搜索栏实战
│   │   │   │   │   └── CommentAreaPage.ets     // 示例4:评论区实战
│   │   │   ├── resources/
│   │   │   │   └── media/                        // 自定义图标:icon_back、search、icon_clear
│   │   │   └── module.json5
│   │   └── build-profile.json5
└── build-profile.json5

五、导航主页面(Index.ets)

import { router } from '@kit.ArkUI';

interface RouterButton {
  title: string;
  url: string;
}

@Entry
@Component
struct Index {
  private buttonList: RouterButton[] = [
    { title: "示例1:三大组件基础用法", url: 'pages/InputBasicPage' },
    { title: "示例2:标准注册表单实战", url: 'pages/RegisterFormPage' },
    { title: "示例3:顶部搜索栏实战", url: 'pages/InputSearchBarPage' },
    { title: "示例4:发布评论实战", url: 'pages/CommentAreaPage' },
  ];

  build() {
    Column({ space: 12 }) {
      Text("TextInput/TextArea/Search")
        .fontSize(30)
        .fontWeight(FontWeight.Bold)
        .margin({ bottom: 30 });

      ForEach(
        this.buttonList,
        (item: RouterButton) => {
          Button(item.title)
            .width('85%')
            .height(42)
            .backgroundColor($r('sys.color.brand'))
            .fontColor(Color.White)
            .borderRadius(8)
            .fontSize(15)
            .onClick(() => router.pushUrl({ url: item.url }));
        },
        (item: RouterButton) => item.url
      );
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
    .backgroundColor('#F5F5F5');
  }
}
运行效果

输入组件入口

六、示例1:三大组件基础用法(InputBasicPage.ets)

核心掌握点

  1. 区分TextInput/TextArea的text绑定与Search的value绑定;
  2. 正确使用组件专属输入类型枚举;
  3. 完成核心事件绑定与数据实时同步;
  4. 控制器一对一绑定规范;
  5. TextArea行数、行间距、溢出等长文本配置。
import { router } from '@kit.ArkUI';

interface RouterButton {
  title: string;
  url: string;
}

@Entry
@Component
struct Index {
  private buttonList: RouterButton[] = [
    { title: "示例1:三大组件基础用法", url: 'pages/InputBasicPage' },
    { title: "示例2:标准注册表单实战", url: 'pages/RegisterFormPage' },
    { title: "示例3:顶部搜索栏实战", url: 'pages/InputSearchBarPage' },
    { title: "示例4:发布评论实战", url: 'pages/CommentAreaPage' },

  ];

  build() {
    Column({ space: 12 }) {
      Text("TextInput/TextArea/Search")
        .fontSize(30)
        .fontWeight(FontWeight.Bold)
        .margin({ bottom: 30 });

      ForEach(
        this.buttonList,
        (item: RouterButton) => {
          Button(item.title)
            .width('85%')
            .height(42)
            .backgroundColor($r('sys.color.brand'))
            .fontColor(Color.White)
            .borderRadius(8)
            .fontSize(15)
            .onClick(() => router.pushUrl({ url: item.url }));
        },
        (item: RouterButton) => item.url
      );
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
    .backgroundColor('#F5F5F5');
  }
}
运行效果

输入组件基础用法2026-02-02T235403

七、示例2:标准注册表单实战(RegisterFormPage.ets)

核心掌握点

  1. TextInput表单场景完整配置与属性绑定;
  2. inputFilter字符级过滤与业务校验;
  3. 密码框全局显隐双向联动;
  4. 实时+失焦+提交三层校验逻辑;
  5. 全局焦点控制与键盘避让;
  6. 表单按钮动态状态控制。
@Entry
@Component
struct RegisterFormPage {
  @State phone: string = '';
  @State pwd: string = '';
  @State confirmPwd: string = '';
  @State phoneError: string = '';
  @State pwdError: string = '';
  @State confirmPwdError: string = '';
  @State isShowPwd: boolean = false;

  private phoneController = new TextInputController();
  private pwdController = new TextInputController();
  private confirmPwdController = new TextInputController();

  private showToast(message: string) {
    try {
      this.getUIContext().getPromptAction().showToast({ message, duration: 2000 });
    } catch (error) {}
  }

  private validateForm(): boolean {
    this.phoneError = this.pwdError = this.confirmPwdError = '';
    let isPass = true;

    if (!/^1[3-9]\d{9}$/.test(this.phone.trim())) {
      this.phoneError = this.phone ? '手机号格式错误' : '请输入手机号';
      isPass = false;
    }

    if (this.pwd.trim().length < 6 || this.pwd.trim().length > 16) {
      this.pwdError = this.pwd ? '密码长度为6-16位' : '请设置密码';
      isPass = false;
    }

    if (this.confirmPwd.trim() !== this.pwd.trim()) {
      this.confirmPwdError = this.confirmPwd ? '两次密码不一致' : '请确认密码';
      isPass = false;
    }

    return isPass;
  }

  private submitRegister() {
    if (this.validateForm()) {
      this.showToast('注册成功');
      this.phone = this.pwd = this.confirmPwd = '';
      this.isShowPwd = false;
      this.getUIContext().getFocusController().clearFocus();
    }
  }

  onPageShow(): void {
    try {
      setTimeout(() => {
        this.getUIContext().getFocusController().requestFocus('phone_id');
      }, 200);
    } catch (error) {}
  }

  build() {
    Scroll() {
      Column({ space: 20 }) {
        Text("用户注册")
          .fontSize(28)
          .fontWeight(FontWeight.Bold)
          .margin({ top: 40, bottom: 20 })
          .width('100%')
          .textAlign(TextAlign.Center);

        // 手机号输入
        TextInput({
          placeholder: '请输入手机号',
          controller: this.phoneController,
          text: this.phone
        })
          .inputFilter('[0-9]', (filteredChars) => {
            console.log('过滤非数字字符:', filteredChars);
          })
          .type(InputType.PhoneNumber)
          .maxLength(11)
          .width('90%')
          .showUnderline(true)
          .underlineColor({ error: '#FF4D4F' })
          .showError(this.phoneError)
          .id('phone_id')
          .onChange((value) => {
            this.phone = value;
            this.phoneError = '';
          })
          .onBlur(() => {
            if (this.phone && !/^1[3-9]\d{9}$/.test(this.phone)) {
              this.phoneError = '手机号格式错误';
            }
          })
          .onSubmit(() => {
            try {
              this.getUIContext().getFocusController().requestFocus('pwd_id');
            } catch (error) {}
          });

        // 密码输入
        TextInput({
          placeholder: '请设置密码(6-16位)',
          controller: this.pwdController,
          text: this.pwd
        })
          .type(InputType.Password)
          .maxLength(16)
          .width('90%')
          .id('pwd_id')
          .onWillChange((newValue) => {
            return newValue.content.trimStart() !== "";
          })
          .inputFilter('[a-zA-Z0-9!@#$%^&*]', (filtered) => {
            filtered && this.showToast(`禁止输入:${filtered}`);
          })

          .showPasswordIcon(true)
          .showPassword(this.isShowPwd)
          .onSecurityStateChange((isShowPassword: boolean) => {
            this.isShowPwd = isShowPassword;
          })
          .onChange((value) => {
            this.pwd = value;
            this.pwdError = '';
          })
          .onSubmit(() => {
            try {
              this.getUIContext().getFocusController().requestFocus('confirm_pwd_id');
            } catch (error) {}
          });

        // 确认密码
        TextInput({
          placeholder: '请再次输入密码',
          controller: this.confirmPwdController,
          text: this.confirmPwd
        })
          .type(InputType.Normal)
          .maxLength(16)
          .width('90%')
          .showUnderline(true)
          .underlineColor({ error: '#FF4D4F' })
          .showError(this.confirmPwdError)
          .id('confirm_pwd_id')
          .inputFilter('[a-zA-Z0-9!@#$%^&*]')
          .showPasswordIcon(true)
          .showPassword(this.isShowPwd)
          .onSecurityStateChange((isShowPassword: boolean) => {
            this.isShowPwd = isShowPassword;
          })
          .onChange((value) => {
            this.confirmPwd = value;
            this.confirmPwdError = '';
          })
          .onSubmit(() => this.submitRegister());

        Row({ space: 8 }) {
          Checkbox()
            .select(this.isShowPwd)
            .selectedColor($r('sys.color.brand'))
            .onChange((v) => this.isShowPwd = v);
          Text('显示密码').fontSize(14).fontColor('#666666');
        }
        .width('90%')
        .margin({ top: 5 });

        Button("立即注册")
          .width('90%')
          .height(45)
          .backgroundColor(
            this.phone.trim() && this.pwd.trim() && this.confirmPwd.trim()
              ? $r('sys.color.brand')
              : '#CCCCCC'
          )
          .fontColor(Color.White)
          .enabled(this.phone.trim() && this.pwd.trim() && this.confirmPwd.trim() ? true:false)
          .onClick(() => this.submitRegister());
      }
      .width('100%')
      .alignItems(HorizontalAlign.Center);
    }
    .width('100%')
    .onClick(() => this.getUIContext().getFocusController().clearFocus())
    .backgroundColor(Color.White);
  }
}
运行效果
账号-输入框样式-数字键盘 密码-输入框样式—密码键盘 密码-输入框样式—有图标

输入组件注册页面

输入组件注册页面_1

输入组件注册页面_2

八、示例3:顶部搜索栏实战(InputSearchBarPage.ets)

核心掌握点

  1. 搜索栏标准化布局实现;
  2. Search图标、按钮、输入类型完整配置;
  3. 实时联想词过滤与列表渲染;
  4. onChange+onSubmit+onBlur事件组合;
  5. 焦点控制与交互优化;
  6. 粘贴内容长度校验。
import router from '@ohos.router';

@Entry
@Component
struct InputSearchBarPage {
  // 搜索关键词状态
  @State searchKey: string = '';
  // 联想词列表状态(空数组初始值)
  @State suggestList: string[] = [];
  // 预设联想词库
  private allSuggestWords = [
    'ArkTS基础教程',
    '鸿蒙组件开发',
    '鸿蒙基础入门',
    'TextInput用法',
    'Search组件实战',
    '鸿蒙布局规范',
    'ArkUI开发指南'
  ];

  // 基础提示
  private showToast(message: string) {
    try {
      this.getUIContext().getPromptAction().showToast({ message: message });
    } catch (error) {
      // TODO: Implement error handling.
    }
  }

  build() {
    Column({ space: 0 }) {
      // 顶部搜索栏布局
      Row({ space: 20 }) {

        Image($r('app.media.icon_back'))
          .width(25)
          .height(25)
          .objectFit(ImageFit.Contain)
          .onClick(()=>{
            router.back()
          })
        // 搜索框(Search专属能力配置)
        Search({ placeholder: '搜索本页内容...', value: this.searchKey })
          .id('searchInput')
          .type(SearchType.NORMAL)
          .height(36)
          .placeholderFont({ size: 14 })
          .enterKeyType(EnterKeyType.Search)
          .backgroundColor('#F5F5F5')
          .layoutWeight(1)
          .constraintSize({maxWidth:375*1.5})
          .searchIcon({ color: '#999', size: 18,src:$r('app.media.search')}) // 自定义搜索图标
          .cancelButton({
            style: CancelButtonStyle.INPUT,
            icon: { src: $r('app.media.icon_clear'), size: 16, color: '#666' } // 自定义清除图标
          })
          .searchButton('搜索', {
            fontSize: 15,
            fontColor: '#007DFF',
            autoDisable: true // 无内容时按钮置灰不可点击
          })
          // 输入内容变化时,生成联想词
          .onChange((value: string) => {
            this.searchKey = value;
            this.getSearchSuggest(value);
          })
          // 失去焦点时,延迟清空联想词
          .onBlur(() => {
            setTimeout(() => {
              this.suggestList = [];
            }, 200);
          })
          // 回车/点击搜索按钮提交
          .onSubmit((searchContent: string) => {
            this.doSearch(searchContent);
            this.suggestList = [];
            this.getUIContext().getFocusController().clearFocus(); // 搜索完成全局失焦
          })
          // 粘贴事件:校验粘贴内容格式
          .onPaste((value) => {
            if (value.length > 50) {
              this.showToast('搜索内容不能超过50字');
            }
          });
      }
      .width('100%')
      .height(60)
      .padding({left:15,right:15})
      .justifyContent(FlexAlign.SpaceBetween)
      .backgroundColor(Color.White);

      // 联想词列表
      List() {
        ForEach(this.suggestList, (item: string) => {
          ListItem() {
            Text(item)
              .fontSize(14)
              .fontColor('#333')
              .padding({ left: 20, top: 12, bottom: 12 })
              .width('100%')
          }
          .backgroundColor(Color.White)
          // 点击联想词:填充+搜索+失焦
          .onClick(() => {
            this.searchKey = item;
            this.doSearch(item);
            this.suggestList = [];
            this.getUIContext().getFocusController().clearFocus();
          });
        },
          (item: string) => item
        )
      }
      .divider({strokeWidth:1,startMargin:20,endMargin:20})
      .width('100%')
      .height('calc(100% - 60vp)')
      .backgroundColor($r('sys.color.comp_background_list_card'));

    }
    .width('100%')
    .height('100%')
    .backgroundColor('#F5F5F5');
  }

  // 生成联想词方法(根据输入关键词过滤预设词库)
  private getSearchSuggest(keyword: string) {
    if (!keyword || keyword.trim() === '') {
      this.suggestList = [];
      return;
    }
    // 不区分大小写过滤
    this.suggestList = this.allSuggestWords.filter(item =>
    item.toLowerCase().includes(keyword.toLowerCase())
    );
  }

  // 通用搜索方法(可扩展为接口请求、内容检索等业务逻辑)
  private doSearch(keyword: string) {
    if (!keyword || keyword.trim() === '') {
      this.showToast("请输入搜索关键词");
      return;
    }
    this.showToast(`执行搜索:${keyword}`);
    console.log(`执行搜索:${keyword}`);
  }
}
运行效果
搜索框自定义图标 回车键显示-搜索

输入组件搜索页面

输入组件搜索页面_1

九、核心知识点总结

(一)组件选型核心原则

  1. 单行短文本(账号、密码、手机号、验证码)→ TextInput:单行不折行,输入模式与控制器控制能力丰富;
  2. 多行长文本(评论、留言、文章编辑)→ TextArea:自动折行、支持滚动,行数与排版配置完善;
  3. 搜索专属场景(全局/页面内搜索)→ Search:内置图标与搜索语义,减少自定义开发;
  4. 富文本编辑 → 选用鸿蒙RichEditor,不适用常规输入组件(单独设计一节内容针对富文本讲解)

(二)枚举与绑定规范

  1. 输入类型强绑定:InputType→TextInput、TextAreaType→TextArea、SearchType→Search,禁止混用;
  2. 数据绑定区分:TextInput/TextArea使用text,Search使用value
  3. 回车键类型EnterKeyType全组件通用,按业务语义选择。

(三)通用开发规范

  1. 键盘避让:输入页面外层嵌套Scroll,避免软键盘遮挡;
  2. 输入过滤:简单字符规则用inputFilter,复杂业务规则用onWillChange,可组合使用;
  3. 校验分层:onChange清错、onBlur格式校验、submit全量校验;
  4. 控制器:与组件一一对应,禁止跨组件复用,用于光标与选框精细控制;
  5. 焦点管理:用getUIContext().getFocusController()做全局聚焦/失焦,组件需绑定唯一id。

(四)事件与交互规范

  1. onChange:负责数据实时同步与基础过滤;
  2. onSubmit:Search直接取searchContent,TextInput/TextArea从event.text取值;
  3. onPaste:用于粘贴内容长度、格式校验;
  4. onWillChange:内容变更前置拦截,支持自动修正,复杂过滤首选方案。

(五)组件专属能力要点

  1. TextInput:聚焦表单与密码场景,核心使用下划线、错误提示、密码显隐相关API;
  2. TextArea:聚焦长文本,核心配置行数、行间距、高度自适应、溢出策略;
  3. Search:聚焦搜索场景,核心使用图标定制、搜索按钮、清除按钮、空内容禁用等交互配置。
Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐