输入区扩展(@ / 表情 / 引用)

MessageInput 是受控输入区:宿主通过事件接收发送/上传/typing 意图,通过 setQuote/insertMention 注入引用与 @,通过 setDisabled 表达禁言态。@ 有原生 API;表情没有专用 API,按“向 textarea 插入文本并触发 input”实现;引用由 quote 随 send 事件回传。

概念​

能力真实入口说明
发送on("send", {text,quote})Enter 发送、Shift+Enter 换行;输入法组合态不触发
引用setQuote(quote) / getQuote()引用条显示 senderId + 文本;随 send 回传
@ 提及insertMention({all,userIds})插入 @所有人/@userId 并 emit mentionChanged
表情无专用 API向 textarea 写值并 dispatchEvent(new Event("input"))
草稿saveDraft/draftChanged宿主持久化;draft prop 恢复
typingtyping 事件(debounce/idle)默认 500ms/3000ms,可配
图片/文件/语音/位置/已读pickImage/pickFile/pickLocation/readVisible由宿主上传并发送
  • mentionCandidates 只用于内部候选展示;选择成员后由宿主调用 insertMention。
  • maxLength 默认 5000;超长时发送按钮禁用并提示。
  • setDisabled(true, true) 会同时处理禁用与禁言文案。
  • send 事件只上报文本;图片/文件/语音由各自事件交给宿主。

前置条件​

  • 已按 快速开始 完成 init 与 connect,页面能收发消息。
  • 使用 @ni-paas/im-web/imkit(浏览器原生 ESM,无第三方依赖);自定义代码只调用 IMKit/IMLib 公开入口。
  • 已引入默认样式:调用 ensureStyles(),或自行加载 IMKit 样式表。
  • 自托管版无“UI 主题商店/付费皮肤”;所有自定义均为本地代码(不适用项)。

步骤​

  1. 挂载输入区

    独立使用 new MessageInput({conversationType,targetId,...}),或直接用 ChatView(内部已组合输入区)。

  2. 处理发送与引用

    监听 send,把 quote 一并写入消息 content;发送成功后 clear()。

  3. 接入 @ 选择器

    点击 pickMention 打开成员选择器;确认后调用 insertMention({userIds})。

  4. 接入表情

    在光标处插入表情字符,再触发 input 事件让组件同步高度与草稿。

  5. 保存草稿与 typing

    监听 saveDraft/draftChanged 与 typing,调用 SDK 的草稿与正在输入接口。

参数表​

Props / 方法 / 事件类型说明
draftstring初始草稿
disabled / mutedboolean禁用/禁言态
mentionCandidatesArray@ 候选成员
maxLengthnumber默认 5000
typingDebounceMs / typingIdleMsnumber默认 500/3000
draftDebounceMsnumber默认 600
setQuote(q) / getQuote()方法q={messageId,senderId,text,type}
insertMention({all,userIds})方法插入 @ 文本
setHint(text) / setDisabled(d,m)方法提示与状态
clear() / focus()方法清空/聚焦

示例​

完整输入区:引用 + @ + 表情 + 草稿​

JavaScript
import { MessageInput, ensureStyles } from '@ni-paas/im-web/imkit';

ensureStyles();

const input = new MessageInput({
  conversationType: 2,
  targetId: 'g_demo',
  placeholder: '输入消息,Enter 发送',
  mentionCandidates: [
    { userId: 'alice', name: 'Alice' },
    { userId: 'bob', name: 'Bob' },
  ],
  maxLength: 2000,
});
input.mount(document.getElementById('composer-host'));

// 1) 发送:quote 随事件回传
input.on('send', async ({ text, quote }) => {
  const content = quote
    ? { type: 'text', text, quote: { messageId: quote.messageId } }
    : { type: 'text', text };
  const result = await client.sendMessage({ conversationType: 2, targetId: 'g_demo', content });
  if (result.code === 0) input.clear();
});

// 2) 引用某条消息
function quoteMessage(message) {
  input.setQuote({
    messageId: message.messageId,
    senderId: message.senderId,
    text: message.content && message.content.text,
    type: message.content && message.content.type,
  });
}

// 3) @ 选择器确认后插入
document.getElementById('mention-picker').addEventListener('pick', (event) => {
  input.insertMention({ userIds: [event.detail.userId] }); // 或 { all: true }
});

// 4) 表情:没有专用 API,按文本插入并同步组件
function insertEmoji(emoji) {
  const textarea = document.querySelector('#composer textarea');
  const start = textarea.selectionStart;
  const end = textarea.selectionEnd;
  textarea.value = textarea.value.slice(0, start) + emoji + textarea.value.slice(end);
  textarea.selectionStart = textarea.selectionEnd = start + emoji.length;
  textarea.dispatchEvent(new Event('input', { bubbles: true }));
  textarea.focus();
}

// 5) 草稿 / typing
input.on('saveDraft', ({ draft }) => client.saveTextMessageDraft(2, 'g_demo', draft));
input.on('typing', ({ typing }) => client.sendTypingStatus(2, 'g_demo', typing));
input.on('error', (err) => console.warn('composer error', err));

用 ChatView 的快捷方法(推荐)​

JavaScript
const chat = new ChatView({ conversationType: 1, targetId: 'bob', currentUserId: 'alice' });
chat.mount(document.getElementById('chat-host'));

// 引用 / @ / 提示 / 禁言态
chat.setQuote({ messageId: 'm_1', senderId: 'bob', text: '在吗?', type: 'text' });
chat.applyMention({ userIds: ['alice'] });
chat.setHint('图片上传中…');
chat.setComposerState({ disabled: false, muted: false });

常见问题​

回车发送在中文输入法下会误发吗?​

不会。组件检查 event.isComposing;组合态下 Enter 不触发发送。

表情有内置面板吗?​

没有。IMKit 只提供输入区;表情面板与字符集由宿主实现,按上例插入文本即可。

@ 后发送的 mentionedInfo 谁负责?​

SDK/协议负责 mentionedUserIds/isMentionAll;insertMention 只负责文本与 mentionChanged,发送时请从事件或业务状态取。

引用会随消息发出去吗?​

send 事件会带 quote;需要你在 content 里写入引用字段(如 content.quote),组件不自动拼装协议字段。

禁言时输入区什么样?​

setDisabled(true, true) 会禁用发送并显示禁言提示;发送尝试会 emit error。

相关链接​