☰
MateChat NG Input 输入框组件全解:从基础绑定到格式化内容编排
2026/10/14 17:22:14 网站建设 项目流程
  • 前端
  • UI组件
  • AI 应用

【免费下载链接】MateChat

前端智能化场景解决方案UI库,轻松构建你的AI应用,我们将持续完善更新,欢迎你的使用与建议。 官网地址:https://matechat.gitcode.com

项目地址:https://gitcode.com/DevCloudFE/MateChat
点击查看免费下载

MateChat 是为前端智能化场景提供 UI 解决方案的组件库,其 Angular 版本(@matechat/ng)中的 Input 组件是对话式应用的核心交互入口,负责承载用户提问、控制发送行为,并支持主题标签、格式化输入等结构化内容录入。本篇指南基于 MateChat 仓库中 Input 组件的官方文档与源码实现,完整覆盖基本用法、展示形态、提交快捷键、自动高度调整、自定义发送按钮与formatContentOptions格式化编排等全部能力,帮助你在 Angular 项目中快速搭建一个功能完整的 AI 对话输入区,并理解其背后的渲染与事件机制。

组件概览与引入

Input 组件的模板选择器为mc-input,通过InputModule按需引入:

import { InputModule } from '@matechat/ng';

在 standalone 组件中将其加入imports数组即可使用。模块定义见 input.module.ts,内部聚合了InputComponent、ButtonComponent、SendIconComponent、InputTagComponent与EditableBlockComponent等子组件。

组件主体结构(input.component.ts)定义了全部对外输入参数,默认值如下:

参数类型默认值说明
valuestring''输入框的值,纯文本展示
formatContentOptionsFormatContentOptions{}输入框中需要被格式化录入的值及其配置项,与value互斥,两者选其一
placeholderstring--输入框占位文字
disabledbooleanfalse是否禁用输入框
displayTypeDisplayType'full'输入框的展示形态
loadingbooleanfalse是否发送中,为true时点击发送按钮可暂停回答
showCountbooleanfalse是否显示字数统计
maxLengthnumber--输入框的最大字数
submitShortKeySubmitShortKey \| null'enter'发送快捷键,null表示不使用快捷键发送
variantInputVariant'bordered'输入框边框形态
sendBtnVariantSendBtnVariant'full'发送按钮的形态
autofocusbooleanfalse是否自动聚焦输入框
autosizeTextareaAutoSizefalse是否自动调整文本域高度

注意:value与formatContentOptions互斥,二者选其一。当使用formatContentOptions时,组件内部会切换到可编辑块(mc-editable-block)渲染模式。

基本用法

绑定value等基本参数即可使用,通过change/submit/cancel事件接收用户操作。仓库内置的基础示例(basic-demo.component.html)演示了带字数统计与加载态的完整用法:

<mc-input [value]="inputValue" [maxLength]="2000" [showCount]="true" [loading]="loading" (change)="onInputChange($event)" (submit)="onSubmit($event)" (cancel)="onCancel()" ></mc-input>

对应的组件逻辑(basic-demo.component.ts):

onInputChange(e) { console.log('input change---', e); } onSubmit(e) { this.loading = true; // 进入“发送中”状态 console.log('input submit---', e); } onCancel() { this.loading = false; // 暂停回答后恢复 console.log('input cancel'); }

loading为true时,发送按钮会变为“停止回答”形态,点击触发cancel事件;showCount开启后会在底部区域显示当前字数/最大字数统计(见 input.component.html)。

展示形态

displayType参数控制输入框的布局形态,支持的值为full和simple,默认为full:

  • full形态:prefix 插槽和输入框在同一行,extra 插槽和发送按钮在下方(底部区域还可承载字数统计)。
  • simple形态:prefix 插槽、输入框和发送按钮在同一行,不支持 extra 插槽。

variant参数可设置为borderless,渲染不带边框的输入框;sendBtnVariant控制发送按钮形态,支持的值为full(圆角按钮,同时显示图标和文字)与simple(圆形按钮,仅显示图标),默认为full。

仓库示例(suffix-demo.component.html)组合了三种参数并自定义了 suffix 内容:

<mc-input [value]="inputValue" [displayType]="DisplayType.Simple" [variant]="InputVariant.BorderLess" [sendBtnVariant]="SendBtnVariant.Simple" [loading]="loading" (submit)="onSubmit($event)" > <ng-template #suffix> <div class="input-prefix-wrap"> <i class="icon-appendix"></i> </div> </ng-template> </mc-input>

相关枚举定义见 types.ts:

enum DisplayType { Simple = 'simple', // prefix插槽、输入框和发送按钮在同一行,不支持extra插槽 Full = 'full', // prefix插槽和输入框在同一行,extra插槽和发送按钮在下方 } enum InputVariant { Bordered = 'bordered', BorderLess = 'borderless', } enum SendBtnVariant { Simple = 'simple', // 圆形按钮,仅显示图标,不显示文字 Full = 'full', // 圆角按钮,同时显示图标和文字 }

从源码结构看,形态参数最终被映射为根元素上的 CSS 类:getInputClasses(foundation.ts)会根据disabled、displayType、variant生成mc-input-disabled、mc-input-simple、mc-input-borderless等类名,模板中displayType === 'full'时才渲染包含 extra 插槽与字数统计的mc-input-foot底部区域。

提交模式

submitShortKey设置提交快捷键,支持的值为enter和shiftEnter,默认为enter;设为null则完全禁用快捷键发送。两种模式下的换行行为互为镜像:

  • 提交快捷键为enter时,换行快捷键为shift+enter;
  • 提交快捷键为shiftEnter时,换行快捷键为enter。
enum SubmitShortKey { Enter = 'enter', ShiftEnter = 'shiftEnter', }

仓库示例(submit-demo.component.html)演示了shiftEnter提交模式:

<mc-input [value]="inputValue" [loading]="loading" submitShortKey="shiftEnter" (submit)="onSubmit($event)" ></mc-input>

快捷键判定逻辑集中在 foundation.ts 的 onKeydown 中:当submitShortKey为null时直接返回;Enter模式下要求!event.shiftKey,shiftEnter模式下要求event.shiftKey,命中后调用preventDefault、触发submit(inputValue)并清空输入值。此外,若未提供placeholder,组件会自动生成包含快捷键提示的默认占位文案(如“请输入您的问题,并按 Enter 发送,按 Shift + Enter 换行”),其文案通过Input.pleaseEnterPlaceholder国际化 key 生成(见 foundation.ts),因此提示文案会跟随submitShortKey配置自动切换。

在可编辑块模式下,对应的判定逻辑实现在 editable-block.component.ts 的 handleDivKeydown,且发送前会校验maxLength,超长内容不会发出(见 handleSend)。

自动聚焦

通过autofocus属性设置输入框在组件挂载后自动获得焦点,默认为false;当输入框被禁用时,自动聚焦不会生效。

<mc-input [value]="inputValue" [autofocus]="true" ...></mc-input>

源码层面(input.component.ts),聚焦动作发生在ngAfterViewInit中,并且用一个setTimeout延迟到下一个宏任务执行,以确保视图(textarea)已完全初始化后再调用focus(),同时显式判断!this.disabled以满足“禁用时不聚焦”的约束。

自动调整高度

autosize属性让文本域自动调整高度,支持布尔值和配置对象两种形式:

  • 设置为true:使用默认配置(最小 1 行,最大 5 行);
  • 设置为对象:可自定义最小和最大行数,如{ minRows: 2, maxRows: 10 };
  • 设置为false(默认):高度固定。
type TextareaAutoSize = { minRows?: number; maxRows?: number } | boolean;
  • minRows?: number:最小行数,默认为 1
  • maxRows?: number:最大行数,默认为 5

仓库示例(auto-size-demo.component.html)同时演示了三种形态:

<mc-input [value]="inputValue1" [autosize]="true" placeholder="默认自动调整(最小1行,最大5行)"></mc-input> <mc-input [value]="inputValue2" [autosize]="{ minRows: 2, maxRows: 10 }" placeholder="自定义行数范围"></mc-input> <mc-input [value]="inputValue3" [autosize]="false" placeholder="固定高度的文本域"></mc-input>

实现细节值得注意:updateTextareaStyle 在输入、value变化、autosize变化以及视图初始化时都会重新计算高度;而 computeTextareaHeight 采用“影子 textarea”方案——在页面中动态创建一个隐藏 textarea,继承line-height、font-size、padding等影响排版的全部样式,测量scrollHeight得到真实内容高度,再按minRows/maxRows计算单行高度(扣除 padding)得出minHeight/maxHeight钳制区间;超出最大高度时会设置overflowY: auto让内容可滚动,最终统一附加resize: none禁止手动拖拽。

自定义发送按钮

通过button插槽自定义发送按钮,可实现按钮的 disable、loading 等状态以及按钮图标、文案的自定义。仓库示例(button-demo.component.html):

<mc-input [value]="inputValue" [maxLength]="2000" [loading]="loading" (change)="onInputChange($event)" (submit)="onSubmit($event)" (cancel)="onCancel()"> <ng-template #button> <div class="my-button" [class.disabled]="!loading && !inputValue" (click)="onConfirm()"> <span class="mc-button-content"> <span>{{ loading ? '停止' : '发送' }}</span> </span> </div> </ng-template> </mc-input>

自定义按钮需要自行处理两种状态:loading为true时点击应触发取消(onCancel),否则发送inputValue并清空内容(见 button-demo.component.ts)。如果不提供button插槽,组件会使用默认按钮(button.component.ts),其内部已实现同样的状态机:onConfirm中判断loading则cancel.emit(),否则submit.emit(inputValue)并清空(见 button.component.ts)。按钮禁用条件为disabled || (!loading && !inputValue),即空内容且非发送中时不可发送(见 input.component.html)。

插入主题标签

通过ThemeTagItem类型配置前置主题标签,支持自定义主题标签的文本内容、pop 弹出提示内容等。约束条件:

  • 当前仅支持最多设置一个 ThemeTag,且必须放在formatContent数组的第一个位置;
  • 可通过themeTag插槽自定义主题标签的展示效果。
interface ThemeTagItem { type: 'themeTag'; // 固定type themeTagKey: string; // 主题标签的唯一标识 themeTagText: string; // 主题标签的文本内容 clearInput?: boolean; // 关闭主题标签时是否清空输入框中在其后面内容,默认为false popoverContent: string; // 主题标签的pop提示文案 }

仓库示例(theme-tag-demo.component.ts)演示了动态插入与关闭主题标签:

openThemeTag() { this.formatContentOptions = { formatContent: [ { type: 'themeTag', themeTagKey: 'themeTag', // 主题标签的唯一标识 themeTagText: '动图生成', // 主题标签的文本内容 clearInput: false, // 关闭主题标签时是否清空对应输入框内容 popoverContent: '点击退出技能', // 主题标签的pop弹出提示内容 }, ], }; } closeThemeTag() { this.formatContentOptions = { formatContent: [] }; }

展示效果通过themeTag插槽自定义(theme-tag-demo.component.html):

<mc-input [formatContentOptions]="formatContentOptions" placeholder="请输入您的问题,并按Enter发送,按Shift + Enter换行" (change)="onInputChange($event)" (submit)="onSubmit($event)"> <ng-template #themeTag let-themeTagText="themeTagText"> <span class="tip-tag-custom"> <i class="icon-code-editor-close"></i> <span class="tip-tag-icon icon-default"></span> <span class="ai-input-prefix">{{themeTagText}}</span> </span> </ng-template> </mc-input>

从源码结构看,当ngOnChanges检测到formatContentOptions变化时,组件会过滤出themeTag类型的项并调用openTipTag,其余格式化项交给setMixTags(input.component.ts);主题标签关闭时,若配置了clearInput: true,closeTipTag 会连带清空输入框内容。值得注意的是一处取值细节:getInput返回的内容会主动剔除主题标签前缀文本(见 getCurrentInputValue),因此submit/change事件拿到的是用户真正输入的部分,主题标签本身不会混入提交内容。

插入格式化 Input 标签

通过FormatInputItem类型配置一个 input 标签,实现对输入框内某些局部文本的默认填充或占位提示;input 标签可以插入多个,且插入位置不固定:

interface FormatInputItem { type: 'input'; // 固定type key: string; // 标签的唯一标识 placeholder: string; // input标签的占位提示内容 content?: string; // input标签的默认展示内容 }

仓库示例(format-input-demo.component.ts)用“text + input”交替编排出一个“论文写作”提示句:

this.formatContentOptions = { formatContent: [ { key: '', type: 'text', content: '我是', placeholder: '' }, { key: 'input1', type: 'input', placeholder: '请输入专业', content: '计算机科学' }, { key: '', type: 'text', content: '专业的本科生,帮我写一篇关于', placeholder: '' }, { key: 'input2', type: 'input', placeholder: '请输入主题', content: '' }, { key: '', type: 'text', content: '的论文。', placeholder: '' }, ], };

渲染后,content有值的 input 标签展示为可编辑的默认内容(“计算机科学”),无content的则展示placeholder(“请输入主题”),用户可直接在这些局部片段上输入,从而限定其主题、类型、范围等。

多种格式化内容自定义编排

通过FormatContentOptions.formatContent中多种格式化标签的自定义组合编排,按需实现对输入框内文本的多种格式化展示:

interface FormatContentOptions { formatContent: FormatContentItem[]; } type FormatContentItem = FormatTextItem | FormatInputItem | ThemeTagItem;
interface FormatTextItem { type: 'text'; // 固定type key: string; // 标签的唯一标识 content: string; // 文本内容 }

仓库示例(format-content-demo.component.ts)将主题标签、固定文本、两个 input 标签编排为一条完整的“宣传文案生成”指令:

const mixTags = [ { type: 'themeTag', themeTagKey: 'themeTag', themeTagText: '文章生成', clearInput: true, popoverContent: '点击关闭主题' }, { key: '', type: 'text', content: '帮我写一篇面向', placeholder: '' }, { key: 'input1', type: 'input', placeholder: '输入目标人群', content: '职场人士' }, { key: '', type: 'text', content: '关于', placeholder: '' }, { key: 'input2', type: 'input', placeholder: '输入产品', content: '' }, { key: '', type: 'text', content: '的宣传文案,需要直击痛点,吸引用户点击。', placeholder: '' }, ]; this.formatContentOptions = { formatContent: mixTags };

编排规则可归纳为:themeTag(可选,至多一个且必须位于首位)+ 任意数量、任意顺序的text与input交错排列。一旦formatContent非空,组件即切换到showEditableBlock模式,由mc-editable-block(contenteditable div)负责渲染,而非原生 textarea。

自定义插槽

Input 组件提供以下插槽,覆盖输入框的顶部、左侧、右侧、底部与按钮区域:

插槽名说明
head自定义输入框顶部的内容
prefix自定义输入框左侧的内容
suffix自定义输入框右侧的内容
extra自定义发送按钮左侧的内容,仅在displayType='full'时生效
button自定义输入框的发送按钮
themeTag自定义前置主题标签的展示效果

仓库示例(slot-demo.component.html)演示了head(顶部附件列表)与extra(底部“智能体/附件”入口)的组合:

<mc-input [value]="inputValue" [loading]="loading" (submit)="onSubmit($event)"> <ng-template #head> <div class="appendix-wrap"> <div class="appendix-item"> <span>README.md</span> <i class="icon-code-editor-close"></i> </div> </div> </ng-template> <ng-template #extra> <div class="input-foot-left"> <span><i class="icon-at"></i>智能体</span> <span><i class="icon-appendix"></i>附件</span> </div> </ng-template> </mc-input>

插槽模板通过@ContentChild声明式收集(input.component.ts),在模板中按需投影。

事件与方法

事件(均在 input.component.ts 中声明):

事件名类型说明
change(e: string) => void输入内容变化时触发,返回当前输入内容
submit(e: string) => void发送时触发,返回当前输入内容
cancel() => void状态为发送中、点击暂停回答按钮时触发
focus(e: FocusEvent) => void聚焦输入框时触发
blur(e: FocusEvent) => void输入框失焦时触发

公开方法:

方法名类型说明
clearInput() => void清空输入框的内容
getInput() => string获取输入框的内容

两者在可编辑块模式下会委托给mc-editable-block处理(input.component.ts),保证两种渲染模式下行为一致。

交互细节与实现要点

结合源码实现,还有几个影响实际集成体验的细节:

  • 中文输入法兼容:textarea 模式通过compositionstart/compositionend维护lock标志,组合输入期间不重复触发change,仅在compositionend时统一发射(input.component.ts),可编辑块模式同样用isComposing做了相同处理,避免拼音中间态污染内容。
  • 清空即还原:可编辑块模式下,当输入内容被全部删除为空时,handleDivInput会延迟一个渲染周期(TimeToViewRender = 50ms,定义于 types.ts)后切回普通 textarea 模式(input.component.ts),让空输入回到轻量渲染路径。
  • 焦点导航:可编辑块对方向键与 Backspace/Delete 做了专门处理,光标抵达相邻 input 标签边界时会把焦点移入该标签内部编辑;空标签在 Backspace/Delete 下会被整体移除(editable-block.component.ts)。
  • 禁用态守卫:setMixTags、openTipTag、closeTipTag以及EditableBlock的所有写入方法(setMixTags/setText/setInputTag)都会先判断disabled,禁用状态下任何格式化编排调用都会被忽略。
  • 国际化占位:未设置placeholder时,默认占位文案中的快捷键提示(Enter / Shift + Enter)会随submitShortKey自动切换,且经由LocaleService的Input.pleaseEnterPlaceholderkey 输出,支持中英文环境。

总结

MateChat NG 的 Input 组件围绕“对话输入”这一场景做了完整封装:value+ 事件体系覆盖常规受控输入,displayType/variant/sendBtnVariant适配不同页面形态,submitShortKey精确控制回车/Shift+Enter 的提交与换行语义,autosize提供基于影子 textarea 的高度自适应,button插槽与loading状态机支持“发送/停止”双态按钮;而formatContentOptions的 ThemeTag/Text/Input 三类标签编排能力,则让输入框能够承载“主题 + 模板化提示 + 可编辑片段”的结构化提问。以上所有能力均可在 Input 组件源码 与 内置示例 中对照验证,便于按需在自有 Angular 项目中落地。

  • 前端
  • UI组件
  • AI 应用

【免费下载链接】MateChat

前端智能化场景解决方案UI库,轻松构建你的AI应用,我们将持续完善更新,欢迎你的使用与建议。 官网地址:https://matechat.gitcode.com

项目地址:https://gitcode.com/DevCloudFE/MateChat
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询