MessageInput

概述

MessageInput 是一个功能完整的消息输入组件,提供了文本编辑、表情选择、文件附件、发送按钮等核心聊天输入功能。该组件支持丰富的自定义选项,包括输入行为配置、工具栏定制、组件替换和插槽扩展,能够满足不同聊天场景的个性化需求。

Props 属性

字段
类型
默认值
描述
autoFocus
boolean
true
是否自动聚焦到输入框
disabled
boolean
false
是否禁用输入组件
boolean
false
是否隐藏发送按钮
string
''
输入框占位符文本
className
string
undefined
根容器自定义 CSS 类名
style
React.CSSProperties
undefined
根容器自定义内联样式
'collapsed' | 'expanded'
'collapsed'
附件选择器显示模式
actions
MessageInputActions
['EmojiPicker', 'AttachmentPicker']
工具栏操作按钮配置
slots
MessageInputSlots
undefined
插槽配置对象
JSX.Element
undefined
自定义文本编辑器组件
JSX.Element
undefined
自定义表情选择器组件
JSX.Element
undefined
自定义附件选择器组件
JSX.Element
undefined
自定义文件选择器组件
JSX.Element
undefined
自定义图片选择器组件
JSX.Element
undefined
自定义视频选择器组件

属性详解

autoFocus

参数类型: boolean
autoFocus 用于设置是否在组件挂载时自动聚焦到输入框,默认值为 true

disabled

参数类型: boolean
disabled 用于设置是否禁用整个输入组件,包括文本输入和所有操作按钮,默认值为 false

hideSendButton

参数类型: boolean
hideSendButton 用于设置是否隐藏发送按钮,适用于需要自定义发送触发方式的场景,默认值为 false

placeholder

参数类型: string
placeholder 用于设置输入框的占位符文本,默认值为空字符串。

className

参数类型: string
className 用于设置根容器自定义 CSS 类名,默认值为 undefined

style

参数类型: React.CSSProperties
style 用于设置根容器自定义内联样式,默认值为 undefined

attachmentPickerMode

参数类型: 'collapsed' | 'expanded'
attachmentPickerMode 用于设置附件选择器的显示模式,默认值为 'collapsed'
collapsed: 收起模式,点击后展开选项
expanded: 展开模式,直接显示所有选项
说明:
默认的 AttachmentPicker 意为附件选择器,包括文件选择、图片选择和视频选择。
1. 当 attachmentPickerMode 为 "collapsed" 时,点击附件选择器会弹出一个 popup 菜单展示文件选择、图片选择、视频选择。
2. 当 attachmentPickerMode 为 "expanded" 时,附件选择器会默认展开,平铺展示文件选择、图片选择、视频选择。

actions

参数类型: MessageInputActions
actions 用于配置工具栏中显示的操作按钮,默认值为 ['EmojiPicker', 'AttachmentPicker']
type BuiltInAction =
| 'EmojiPicker'
| 'ImagePicker'
| 'FilePicker'
| 'VideoPicker'
| 'AttachmentPicker';

type CustomAction = {
key: string;
label?: string | undefined;
component?: React.ComponentType<any> | undefined;
className?: string | undefined;
style?: React.CSSProperties | undefined;
iconSize?: number | undefined;
};

type MessageInputActions = Array<BuiltInAction | CustomAction>;

示例1: 自定义工具栏按钮顺序

import { Chat, MessageInput } from '@tencentcloud/chat-uikit-react';

function ChatWithCustomActions() {
// 自定义按钮顺序:文件、图片、视频、表情
const customActions = ['FilePicker', 'ImagePicker', 'VideoPicker', 'EmojiPicker'];
return (
<Chat>
<MessageInput actions={customActions} />
</Chat>
);
}
效果图如下图所示:


示例2: 添加自定义操作按钮 - 客服系统快捷回复

import { Chat, MessageInput, useMessageInputState } from '@tencentcloud/chat-uikit-react';

// 快捷回复组件
function QuickReplyPicker() {
const { setContent } = useMessageInputState();
const quickReplies = [
'您好,很高兴为您服务!',
'请稍等,我来为您查询...',
'感谢您的咨询,还有其他问题吗?',
'问题已为您解决,祝您生活愉快!'
];

const handleQuickReply = (text: string) => {
setContent(text);
};

return (
<div style={{ position: 'relative' }}>
<button title="快捷回复"></button>
<div style={{
position: 'absolute',
bottom: '100%',
left: 0,
background: 'white',
border: '1px solid #ccc',
borderRadius: '4px',
padding: '8px',
minWidth: '200px'
}}>
{quickReplies.map((reply, index) => (
<div
key={index}
onClick={() => handleQuickReply(reply)}
style={{
padding: '4px 8px',
cursor: 'pointer',
borderRadius: '2px'
}}
>
{reply}
</div>
))}
</div>
</div>
);
}

function CustomerServiceChat() {
const actions = [
{
key: 'quickReply',
label: '快捷回复',
component: QuickReplyPicker
},
'EmojiPicker',
'FilePicker'
];
return (
<Chat>
<MessageInput actions={actions} />
</Chat>
);
}
效果图如下图所示:


slots

参数类型: MessageInputSlots
slots 用于在输入组件的特定位置插入自定义内容,默认值为 undefined
interface MessageInputSlots {
headerToolbar?: () => React.ReactNode;
footerToolbar?: () => React.ReactNode;
leftInline?: () => React.ReactNode;
rightInline?: () => React.ReactNode;
inputPrefix?: () => React.ReactNode;
inputSuffix?: () => React.ReactNode;
}
MessageInput 结构图解
MessageInput 结构图解


示例1: 添加消息统计显示

import { Chat, MessageInput, useMessageInputState } from '@tencentcloud/chat-uikit-react';

function ChatWithMessageStats() {
const { inputRawValue } = useMessageInputState();
// 头部工具栏:显示字符统计
const HeaderToolbar = () => !inputRawValue
? null
: (
<div style={{
padding: '4px 12px',
fontSize: '12px',
color: '#666',
borderBottom: '1px solid #eee',
}}
>
Character count:
{' '}
{inputRawValue?.reduce((acc, item) => acc + (item.type === 'text' ? item.content.length : 1), 0) || 0}
/500
</div>
);

// 底部工具栏:显示发送提示
const FooterToolbar = () => (
<div style={{
padding: '4px 12px',
fontSize: '12px',
color: '#999',
textAlign: 'right'
}}>
Press Ctrl+Enter to enter a new line
</div>
);

return (
<Chat>
<MessageInput
slots={{
headerToolbar: HeaderToolbar,
footerToolbar: FooterToolbar
}}
/>
</Chat>
);
}
效果图如下图所示:


示例2: 输入框前后缀功能

import { Chat, MessageInput } from '@tencentcloud/chat-uikit-react';

function ChatWithInputPrefixSuffix() {
// 输入框前缀:@提醒功能
const InputPrefix = () => (
<button
style={{
border: 'none',
background: 'transparent',
color: '#1890ff',
cursor: 'pointer'
}}
onClick={() => {
// 触发@用户选择
console.log('打开@用户选择');
}}
>
@
</button>
);

// 输入框后缀:语音输入
const InputSuffix = () => (
<button
style={{
border: 'none',
background: 'transparent',
cursor: 'pointer'
}}
onClick={() => {
// 开始语音输入
console.log('开始语音输入');
}}
>
🎤
</button>
);

return (
<Chat>
<MessageInput
slots={{
inputPrefix: InputPrefix,
inputSuffix: InputSuffix
}}
/>
</Chat>
);
}
效果图如下图所示:


示例3: 完全自定义左右侧工具栏

import { Chat, MessageInput } from '@tencentcloud/chat-uikit-react';

function ChatWithCustomToolbars() {
// 左侧工具栏:仅保留表情和图片
const LeftInline = () => (
<div style={{ display: 'flex', gap: '8px' }}>
<button>😊</button>
<button>📷</button>
</div>
);

// 右侧工具栏:自定义发送区域
const RightInline = () => (
<div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
<span style={{ fontSize: '12px', color: '#666' }}>
Enter
</span>
<button
style={{
padding: '6px 12px',
background: '#1890ff',
color: 'white',
border: 'none',
borderRadius: '4px',
cursor: 'pointer'
}}
>
发送
</button>
</div>
);

return (
<Chat>
<MessageInput
slots={{
leftInline: LeftInline,
rightInline: RightInline
}}
/>
</Chat>
);
}
效果图如下图所示:


TextEditor

参数类型: JSX.Element
TextEditor 用于替换默认的文本编辑器组件,默认值为 undefined

示例: 集成富文本编辑器

import { Chat, MessageInput, useMessageInputState } from '@tencentcloud/chat-uikit-react';

// 自定义富文本编辑器
function RichTextEditor() {
const { sendMessage } = useMessageInputState();
const [inputValue, setInputValue] = useState('');

const handleContentChange = (content: string) => {
setInputValue(content);
};

const handleKeyDown = (e: React.KeyboardEvent) => {
// Enter 发送消息
if (e.key === 'Enter') {
// 触发发送逻辑
e.preventDefault();
sendMessage(inputValue);
// 清空 editable div 的输入内容
const editableDiv = document.querySelector('.editable-div');
if (editableDiv) {
editableDiv.textContent = '';
}
}
};

return (
<div style={{
flex: 1,
border: '1px solid #d9d9d9',
borderRadius: '6px',
padding: '8px 12px',
minHeight: '32px',
maxHeight: '120px',
overflow: 'auto',
}}
>
<div
contentEditable
className="editable-div"
style={{
outline: 'none',
minHeight: '20px',
lineHeight: '20px',
}}
onInput={(e) => {
handleContentChange(e.currentTarget.textContent || '');
}}
onKeyDown={handleKeyDown}
/>
</div>
);
}

function ChatWithRichTextEditor() {
return (
<Chat>
<MessageInput TextEditor={<RichTextEditor />} />
</Chat>
);
}
效果图如下图所示:


EmojiPicker

参数类型: JSX.Element
EmojiPicker 用于替换默认的表情选择器组件,默认值为 undefined

示例: 自定义表情面板

import { Chat, MessageInput, useMessageInputState } from '@tencentcloud/chat-uikit-react';

// 自定义表情选择器
function CustomEmojiPicker() {
const { insertContent } = useMessageInputState();

const emojiCategories = {
common: ['😀', '😂', '🥰', '😍', '🤔', '😭', '😡', '👍'],
hands: ['👋', '🤝', '👏', '🙏', '✌️', '🤞', '🤟', '👌'],
animals: ['🐶', '🐱', '🐭', '🐹', '🐰', '🦊', '🐻', '🐼'],
};

const [activeCategory, setActiveCategory] = useState('common');
const [showPicker, setShowPicker] = useState(false);

const insertEmoji = (emoji: string) => {
insertContent(emoji);
setShowPicker(false);
};

return (
<div style={{ position: 'relative' }}>
<button
onClick={() => setShowPicker(!showPicker)}
style={{ border: 'none', background: 'transparent', cursor: 'pointer' }}
>
😊
</button>

{showPicker && (
<div style={{
position: 'absolute',
bottom: '100%',
left: 0,
background: 'white',
border: '1px solid #ccc',
borderRadius: '8px',
padding: '12px',
width: '280px',
boxShadow: '0 4px 12px rgba(0,0,0,0.1)',
}}
>
{/* 分类标签 */}
<div style={{ display: 'flex', marginBottom: '8px' }}>
{Object.keys(emojiCategories).map(category => (
<button
key={category}
onClick={() => setActiveCategory(category)}
style={{
padding: '4px 8px',
border: 'none',
background: activeCategory === category ? '#1890ff' : 'transparent',
color: activeCategory === category ? 'white' : '#666',
borderRadius: '4px',
cursor: 'pointer',
fontSize: '12px',
}}
>
{category}
</button>
))}
</div>

{/* 表情网格 */}
<div style={{
display: 'grid',
gridTemplateColumns: 'repeat(8, 1fr)',
gap: '4px',
}}
>
{emojiCategories[activeCategory].map(emoji => (
<button
key={emoji}
onClick={() => insertEmoji(emoji)}
style={{
border: 'none',
background: 'transparent',
fontSize: '20px',
cursor: 'pointer',
padding: '4px',
borderRadius: '4px',
}}
>
{emoji}
</button>
))}
</div>
</div>
)}
</div>
);
}

function ChatWithCustomEmoji() {
return (
<Chat>
<MessageInput EmojiPicker={<CustomEmojiPicker />} />
</Chat>
);
}
效果图如下图所示:


AttachmentPicker

参数类型: JSX.Element
AttachmentPicker 用于替换默认的附件选择器组件,默认值为 undefined

示例: 云存储集成的附件选择器

import { Chat, MessageInput } from '@tencentcloud/chat-uikit-react';

// 集成云存储的附件选择器
function CloudAttachmentPicker() {
const [showPicker, setShowPicker] = useState(false);
const attachmentTypes = [
{ key: 'local', label: '本地文件', icon: '📁' },
{ key: 'cloud', label: '云端文件', icon: '☁️' },
{ key: 'recent', label: '最近文件', icon: '🕒' },
{ key: 'screenshot', label: '截图', icon: '📷' }
];

const handleAttachmentSelect = async (type: string) => {
switch (type) {
case 'local':
// 打开本地文件选择
const input = document.createElement('input');
input.type = 'file';
input.multiple = true;
input.onchange = (e) => {
const files = (e.target as HTMLInputElement).files;
console.log('选择的本地文件:', files);
};
input.click();
break;
case 'cloud':
// 打开云端文件选择
console.log('打开云端文件选择');
break;
case 'recent':
// 显示最近文件
console.log('显示最近文件');
break;
case 'screenshot':
// 开始截图
console.log('开始截图');
break;
}
setShowPicker(false);
};

return (
<div style={{ position: 'relative' }}>
<button
onClick={() => setShowPicker(!showPicker)}
style={{ border: 'none', background: 'transparent', cursor: 'pointer' }}
>
📎
</button>
{showPicker && (
<div style={{
position: 'absolute',
bottom: '100%',
left: 0,
background: 'white',
border: '1px solid #ccc',
borderRadius: '8px',
padding: '8px',
minWidth: '160px',
boxShadow: '0 4px 12px rgba(0,0,0,0.1)'
}}>
{attachmentTypes.map(type => (
<div
key={type.key}
onClick={() => handleAttachmentSelect(type.key)}
style={{
display: 'flex',
alignItems: 'center',
gap: '8px',
padding: '8px 12px',
cursor: 'pointer',
borderRadius: '4px',
fontSize: '14px'
}}
>
<span>{type.icon}</span>
<span>{type.label}</span>
</div>
))}
</div>
)}
</div>
);
}

function ChatWithCloudAttachment() {
return (
<Chat>
<MessageInput AttachmentPicker={<CloudAttachmentPicker />} />
</Chat>
);
}
效果图如下图所示:


总结

MessageInput 组件提供了完整的消息输入功能和丰富的自定义选项。通过合理配置 Props 和使用插槽系统,您可以创建出符合特定业务需求的输入界面。建议根据实际使用场景选择合适的自定义方案,并注意保持良好的用户体验和性能表现。