会话列表项自定义

ConversationListView 负责会话排序(置顶优先、更新时间倒序)、未读角标、草稿、@ 提醒、免打扰与选中态。它没有逐行 renderer 钩子;定制方式是选项开关、CSS 变量/类名覆盖、data-* 属性与 longpress 事件。需要完全自定义行结构时,应自行渲染列表并复用 Avatar/UnreadBadge/formatListTime。

概念​

能力选项 / 事件说明
置顶 / 未读 / 草稿 / @options.showPinned/showUnread/showDraft/showMention默认全开
选中行activeTargetId + activeConversationType由宿主维护
点击select({conversation})切换会话
长按/右键longpress({conversation})600ms 或 contextmenu
下拉刷新意图refresh() → refresh 事件宿主重新拉取
空态/骨架loading、conversations=[]内置空态与骨架
  • DOM:.conv-list > .conv-item[data-key][data-conversation-type][data-target-id],内部含 .conv-title/.conv-preview/.conv-time/.pin-mark/.mute-mark/.mention-badge。
  • 未读角标复用 UnreadBadge;免打扰时隐藏红点、保留 @ 角标。
  • 没有任何 renderItem/rowRenderer 参数;不要按不存在的 API 接入。
完全自定义的做法

用 SDK 的 getConversationList() 取数据,自己渲染 .conv-item,复用 Avatar/UnreadBadge/formatListTime/messagePreview 保持视觉一致,再自行处理选中与长按。

前置条件​

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

步骤​

  1. 准备会话模型

    每个会话至少包含 conversationType、targetId、targetName、updatedAt、unreadCount、lastMessage;可选 isPinned/draft/mentionedCount/notificationLevel。

  2. 挂载列表
    new ConversationListView({conversations, activeTargetId, activeConversationType});切换会话时 update() 或重建。
  3. 处理交互
    select 切聊天;longpress 弹菜单(置顶/免打扰/删除);refresh 重新拉取。
  4. 覆盖样式

    用 CSS 变量与类名覆盖间距/字号/选中背景;不要改 data-* 语义。

参数表​

Props / 方法 / 事件类型说明
conversationsArray会话数组
activeTargetId / activeConversationTypestring / number选中态
optionsobject四个 show* 开关
loading / theme / localeboolean / Theme / string骨架、主题、语言
refresh() / setActive(type,id)方法触发刷新 / 设置选中
select / longpress / refresh事件宿主交互入口

示例​

会话列表 + 选中切换 + 长按菜单​

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

ensureStyles();

const list = new ConversationListView({
  conversations: [
    { conversationType: 1, targetId: 'bob', targetName: 'Bob', updatedAt: Date.now(), unreadCount: 3 },
    { conversationType: 2, targetId: 'g_demo', targetName: '项目群', updatedAt: Date.now() - 60000, unreadCount: 128, mentionedCount: 2 },
  ],
  activeTargetId: 'bob',
  activeConversationType: 1,
  options: { showPinned: true, showUnread: true, showDraft: true, showMention: true },
  theme: Theme.light({ background: '#f8fafc' }),
});
list.mount(document.getElementById('conv-host'));

list.on('select', ({ conversation }) => {
  list.setActive(conversation.conversationType, conversation.targetId);
  openChat(conversation);
});

list.on('longpress', ({ conversation }) => {
  openContextMenu(conversation); // 置顶 / 免打扰 / 删除 / 标记已读
});

list.on('refresh', async () => {
  const result = await client.getConversationList();
  if (result.code === 0) list.update({ conversations: result.data });
});

只覆盖列表项样式​

JavaScript
/* 选中行背景与未读角标颜色 */
#conv-host .conv-item.active {
  background: color-mix(in srgb, var(--imkit-primary) 12%, transparent);
}
#conv-host .conv-item .conv-title {
  font-weight: 600;
}
#conv-host .conv-item[data-conversation-type="2"] .conv-title::after {
  content: '群';
  margin-left: 6px;
  font-size: 11px;
  color: var(--imkit-text-secondary);
}

常见问题​

能自定义每一行的 DOM 吗?​

没有行渲染器。请用 CSS/选项,或自渲染列表并复用 IMKit 的格式化与小组件。

未读 99+ 是怎么来的?​

unreadBadgeText 规则:0 隐藏,>99 显示 99+;免打扰时隐藏红点、保留 @。

置顶排序要自己做吗?​

不用。组件按 isPinned 优先、updatedAt 倒序排序。

为什么长按没触发?​

需要 600ms 按住或右键(contextmenu);触屏环境请确认没有阻止默认手势。

相关链接​