IMKit 事件与回调挂载点

IMKit 的事件分三层:IMKitFacade 的 ready/error(挂载生命周期)、组件的 on/off/emit(交互与发送结果)、IMLib 的 RIM.addEventListener(网络/消息/回执等底层事件)。理解三层边界,才能把“UI 反馈”和“业务副作用”放在正确的位置。

概念​

层入口典型事件
门面IMKit.on/off/emitready、error,以及宿主自定义事件
组件instance.on/offMessages:如 ChatView sendText/sendMedia/sendVoice/pending/sendFailed/readReceipt/streamStart/streamChunk/streamEnd
IMLibclient.addEventListenerconnected/disconnect/messages/conversation/read_receipt/kicked/typing/stream_changed 等 15 个
  • 组件事件只描述“UI 层发生了什么”,不会替代 SDK 的业务事件;例如 sendText 只表示用户提交了文本,不代表服务端已入库。
  • 门面的 ready 在 mount/update 后触发,适合做骨架屏与埋点;error 携带 {error,component}。
  • 同一个 handler 既可用于 on 也可用于 off;匿名函数无法精确移除。
  • 组件内部对 handler 异常做了 try/catch 并 console.error,不会因一个监听器抛错阻断其它监听器。
推荐分层

UI 反馈(滚动、Toast、气泡状态)订阅组件事件;业务状态(会话未读、消息入库、踢下线)订阅 IMLib 事件;页面生命周期(骨架、错误边界)订阅门面事件。

前置条件​

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

步骤​

  1. 挂载并监听门面
    IMKit.setup({container}) 后 IMKit.on("ready", handler);错误统一在 error 里上报。
  2. 监听组件交互

    对 ChatView 监听 sendText/pending/sendFailed/readReceipt;对输入区监听 send/typing/pickMention。

  3. 监听 IMLib 业务事件

    用 client.addEventListener(Events.MESSAGES, handler) 处理到达消息、Events.KICKED 处理强制下线。

  4. 清理

    卸载时 chat.destroy()(会解绑内部监听)并 client.removeEventListener;门面用 IMKit.off。

参数表​

事件所属载荷(节选)
readyIMKitFacade{container,component,instance}
errorIMKitFacade / ChatView{error,component} 或 {code,msg}
sendText / sendMedia / sendVoiceChatView{text,result} / {kind,result,file} / {result,duration}
pending / sendFailedChatView{message} / {message,result}
readReceipt / readDetailChatView{messageIds,result} / {messageId}
streamStart/Chunk/EndChatView{streamId,message,payload}
select / longpressConversationListView{conversation}
connected/disconnect/kickedIMLib连接状态载荷
messages/conversation/read_receiptIMLib消息/会话/回执

示例​

三层事件接线 + 清理​

JavaScript
import RongIMLib, { Events } from '@ni-paas/im-web/rongim';
import { IMKit, ChatView, ConversationListView } from '@ni-paas/im-web/imkit';

// 1) 门面生命周期
function onReady(payload) {
  document.getElementById('skeleton').hidden = true;
  console.log('mounted', payload.component);
}
function onError(payload) {
  console.error('imkit error', payload.error || payload);
  toast('界面加载失败,请重试');
}
IMKit.on('ready', onReady);
IMKit.on('error', onError);

// 2) 组件交互
const chat = new ChatView({ conversationType: 1, targetId: 'bob', currentUserId: 'alice' });
chat.mount(document.getElementById('chat-host'));

const onSendText = ({ text, result }) => {
  if (result && result.code === 0) scrollToBottom();
};
chat.on('sendText', onSendText);
chat.on('sendFailed', ({ message, result }) => toast('发送失败:' + (result && result.msg)));
chat.on('readReceipt', ({ messageIds }) => console.log('read sent', messageIds.length));

// 3) IMLib 业务事件
const onMessages = (payload) => {
  const list = payload && payload.messages ? payload.messages : [];
  for (const message of list) chat.appendMessage(message);
};
const onKicked = (payload) => {
  toast('账号已在其它端登录');
  location.reload();
};
client.addEventListener(Events.MESSAGES, onMessages);
client.addEventListener(Events.KICKED, onKicked);

// 4) 清理(SPA 路由卸载时)
function dispose() {
  chat.off('sendText', onSendText);
  chat.destroy();
  client.removeEventListener(Events.MESSAGES, onMessages);
  client.removeEventListener(Events.KICKED, onKicked);
  IMKit.off('ready', onReady);
  IMKit.off('error', onError);
}

门面自定义事件用于跨组件通信​

JavaScript
// 任意位置广播(例如“主题已切换”)
IMKit.emit('theme:changed', { mode: 'dark' });

// 其它组件订阅
const onTheme = ({ mode }) => document.documentElement.setAttribute('data-theme', mode);
IMKit.on('theme:changed', onTheme);
// 清理
IMKit.off('theme:changed', onTheme);

常见问题​

组件事件和 IMLib 事件该选哪个?​

UI 反馈用组件事件;消息入库、未读、连接、踢下线等业务事实用 IMLib 事件。

为什么 sendText 成功但对方没收到?​

sendText 只代表本端提交成功(含失败结果);对方是否收到看消息轨迹或 IMLib messages。

on 多次注册同一函数会重复触发吗?​

不会。组件内部用 Set 去重;但不同函数实例会各自触发。

destroy 后事件还在吗?​

组件会清理自身监听;IMLib 监听需你显式 removeEventListener。

相关链接​