UI定制相关接口
- UI 元素有关的 API
界面(interface)
js
interface ISidebarTab {
id: string // tab id
viewId: string // 连接自定义视图 id
name: string // tab 名称
icon: string // tab icon
activeIcon: string // 当前选中 tab 高亮的 icon
order: number // 排序
postCommand?: string // 自定义事件
badgeCount?: string // 角标数量
}
interface ISidebarTabProvider {
expandedTabCount?: number // 自定义展开的tab数量,超出数量自动合并到「更多」tab 里面
getTabs?(tabs: ISidebarTab[]): ISidebarTab[]
}
interface IViewDisplayer {
id: string // viewId,和 ISidebarTab.viewId 对应连接
render(node: HTMLDivElement, props: object): IDisposable | Promise<IDisposable>
renderOptions?: {
keepAlive?: boolean // 类似 vue keep-alive
keepIframeState?: boolean // 当自定义视图内部包含 iframe 时,可以保留 iframe 原有状态
}
}
export interface ITabbarAction {
// 唯一标识
id: string;
// 图标
icon: string;
// 按钮名称(tooltip提示文本)
label?: string;
// 点击触发的命令
command: string;
}
export interface ITabbarMenuItemOptions {
// 唯一标识
id: string;
// 图标
icon: string;
// 按钮名称
label: string;
// 点击触发的命令
command: string;
}
export interface IThemeConf {
// 主题背景色
"theme.bg": string;
// 侧边栏&顶栏卡片描边颜色
"theme.border.color"?: string;
// 设置面板选色预览颜色值
"theme.thumbnail.color"?: string;
// 设置面板选色预览勾选图标颜色值
"theme.thumbnail.icon.color": string;
// 侧边栏图标颜色
"sidebar.icon.color": string;
// 侧边栏图标选中状态颜色
'sidebar.icon.color.active': string
// 侧边栏导航文字颜色
"sidebar.title.color": string;
// 侧边栏企业账号文字颜色
"sidebar.account.color": string;
// 侧边栏企业账号hover状态文字颜色
"sidebar.account.color.hover": string;
// 侧边栏企业账号选中状态文字颜色
"sidebar.account.color.active": string;
// 侧边栏企业账号背景色
"sidebar.account.bg": string;
// 侧边栏企业账号hover状态背景色
"sidebar.account.bg.hover": string;
// 侧边栏企业账号选中状态背景色
"sidebar.account.bg.active": string;
// 侧边栏导航菜单hover状态背景色
"sidebar.menu.bg.hover": string;
// 侧边栏导航菜单选中状态背景色
"sidebar.menu.bg.active": string;
// 侧边栏导航菜单图标&文字透明度
"sidebar.menu.opacity": string;
// 侧边栏导航菜单选中状态图标&文字透明度
"sidebar.menu.opacity.active": string;
// 顶部导航栏tab背景色
"tabbar.tab.bg": string;
// 顶部导航栏tab hover状态背景色
"tabbar.tab.bg.hover": string;
// 顶部导航栏tab选中状态背景色
"tabbar.tab.bg.active": string;
// 顶部导航栏分割线颜色
"tabbar.divider.color": string;
// 顶部导航栏tab选中状态投影颜色
"tabbar.tab.shadow.color.active"?: string;
// 顶部导航栏tab闪烁动画投影颜色(预留)
"tabbar.tab.shadow.color.animate"?: string;
// 顶部导航栏tab标题文字颜色
"tabbar.tab.title.color": string;
// 顶部导航栏tab选中状态标题文字颜色
"tabbar.tab.title.color.active": string;
// 顶部导航栏tab默认图标颜色
"tabbar.tab.icon.color": string;
// 顶部导航栏tab关闭按钮颜色
"tabbar.tab.button.color": string;
// 顶部导航栏tab选中状态关闭按钮颜色
"tabbar.tab.button.color.active": string;
// 顶部导航栏tab关闭按钮hover背景色
"tabbar.tab.button.bg.hover": string;
// 顶部导航栏tab选中状态关闭按钮hover背景色
"tabbar.tab.button.bg.hover.active": string;
}
export interface IThemeOptions {
// 主题色唯一标识
id: string;
// 主题色名称
label: string;
// 主题色配置
conf: IThemeConf;
}
export interface IMenuItem {
id: string // 菜单项id
icon?: string // 菜单图标
label: string // 菜单项名
command?: string // commandId
viewletId: string // 视图单元 id
when?: string // 控制菜单项的显隐, 不传时默认显示该菜单项
order?: number // 排序
children?: Pick<IMenuItem, 'id' | 'icon' | 'label' | 'command' | 'when' | 'order' | 'children'>[]
}
// 消息右键菜单command参数
export interface IMsgContextmenuCommandParams {
msgid: number
chatid: number
}创建群聊(createGroupChat)
- 支持环境:web
- 调起通讯录选择器创建群聊
js
export function createGroupChat(): Promise<void>- 示例
js
ksxz.ui.createGroupChat()注册侧边栏入口(registerSidebarTab)
- 支持环境:web
- 注册侧边栏 tab 入口
export function registerSidebarTab(tab: ISidebarTab): void- 示例
js
export const VIEW_ID = 'caixin.addressbook.view'
ksxz.ui.registerSidebarTab({
id: 'caixin.addressbook.tab',
viewId: VIEW_ID,
name: '通讯录',
icon: 'caixin-icon-tab-addressbook',
activeIcon: 'caixin-icon-tab-addressbook-active',
order: 100,
postCommand: 'caixin.addressbook.tab.click'
})更新侧边栏角标数量(updateSidebarTabBadgeCount)
- 支持环境:web
- 更新侧边栏角标数量
- 示例
js
ksxz.ui.updateSidebarTabBadgeCount('caixin.addressbook.tab', 1)注册侧边栏展示行为(registerSidebarTabProvider(实验api))
- 支持环境:web
- 注册侧边栏tab展示行为 provider
js
export function registerSidebarTabProvider(provider: ISidebarTabProvider): void- 示例
js
import ksxz from 'ksxz'
// 基座内置 tab id
export enum ESidebarTabId {
MESSAGES = 'messages',
APP = 'app',
DOCS = 'docs',
ADDRESS_BOOK = 'addressBook',
PERSONAL = 'personal'
}
class SidebarTabProvider implements ksxz.ui.ISidebarTabProvider {
// 控制展开的 tab,超出数量则收纳到更多 tab 栏目里面
expandedTabCount = 4
getTabs(tabs: ksxz.ui.ISidebarTab[]) {
// 使用 filter 方式屏蔽内置的 tab
let newTabs = tabs.slice()
newTabs = newTabs.filter(
(tab) =>
// 隐藏“我的”tab
tab.id !== ESidebarTabId.PERSONAL
)
// 修改默认行为
newTabs = newTabs.map((tab) => {
if (tab.id === ESidebarTab.MESSAGES) {
// 修改 order 实现排序
tab.order = 2.1
// 修改 icon 实现自定义图标
tab.icon = 'ksxz_web_ext-xxx'
tab.activeIcon = 'ksxz_web_ext-xxx-active'
}
return tab
})
return newTabs
}
}
ksxz.ui.registerSidebarTabProvider(new SidebarTabProvider())注册自定义视图(registerMainViewDisplayer)
- 支持环境:web
- 注册自定义视图,支持 url 地址的加载
js
export function registerViewDisplayer(viewType: string, displayer: IViewDisplayer): void- 自定义侧边栏对应主视图示例
js
const VIEW_ID = 'caixin.view'
// 注册侧边栏 tab
ksxz.ui.registerSidebarTab({
id: 'caixin.addressbook.tab.a',
viewId: VIEW_ID,
name: '页面a',
icon: 'caixin-icon-tab-addressbook',
activeIcon: 'caixin-icon-tab-addressbook-active',
order: 100
})
ksxz.ui.registerMainViewDisplayer({
id: VIEW_ID,
getWebviewUrl() {
return '自定义 url 地址'
}
})- 完整示例
js
class AddressBookViewDisplayer implements ksxz.ui.IViewDisplayer {
private _comp: Vue | null = null
id = VIEW_ID
renderOptions = { keepIframeState: true }
async render(node: HTMLDivElement, props: object) {
const { default: vueComp } = await import('./View.vue')
const CompCtor = Vue.extend(vueComp)
this._comp = new CompCtor({
propsData: props
})
this._comp.$mount()
node.appendChild(this._comp.$el)
return {
dispose: () => {
this._comp && this._comp.$destroy()
this._comp = null
}
}
}
}
ksxz.ui.registerViewDisplayer('MainView', new AddressBookViewDisplayer())顶部tab注册按钮(registerTabbarAction)
- 支持环境:web
- 在主窗口顶部导航栏注册一个图标按钮
js
export function registerTabbarAction(options: ITabbarAction): void- 示例
js
ksxz.ui.registerTabbarAction({
id: 'caixin.tabbar.action1',
label: '自定义图标1',
icon: require('@/assets/logo.png'),
command: 'caixin.command.alert1'
})顶部tab栏注册下拉项(registerTabbarMenuItem)
- 支持环境web
- 在主窗口顶栏导航栏注册一个下拉菜单子项
js
export function registerTabbarMenuItem(options: ITabbarMenuItemOptions): void- 示例
js
ksxz.ui.registerTabbarMenuItem({
id: 'caixin.tabbar.menu1',
label: '创建群聊',
icon: require('@/assets/logo.png'),
command: 'caixin.command.createGroupChat'
})注册自定义主题(registerTheme)
- 支持环境:web
- 注册一个自定义主题
js
export function registerTheme(options: IThemeOptions): void- 示例
js
ksxz.ui.registerTheme({
id: 'caixin.theme.green',
label: '孔雀绿',
conf: {
'theme.thumbnail.icon.color': 'var(--kd-color-icon-white)',
'theme.bg': '#257355',
'sidebar.icon.color': 'var(--kd-color-icon-white)',
'sidebar.icon.color.active': 'var(--kd-color-icon-white)',
'sidebar.title.color': 'var(--kd-color-icon-white)',
'sidebar.account.color': 'rgba(255, 255, 255, 0.7)',
'sidebar.account.color.hover': 'var(--kd-color-text-white)',
'sidebar.account.color.active': 'var(--kd-color-text-white)',
'sidebar.account.bg': 'rgba(255, 255, 255, 0.1)',
'sidebar.account.bg.hover': 'rgba(255, 255, 255, 0.08)',
'sidebar.account.bg.active': 'rgba(255, 255, 255, 0.1)',
'sidebar.menu.bg.hover': 'rgba(255, 255, 255, 0.08)',
'sidebar.menu.bg.active': 'rgba(255, 255, 255, 0.08)',
'sidebar.menu.opacity': '0.7',
'sidebar.menu.opacity.active': '1',
'tabbar.tab.bg': 'transparent',
'tabbar.tab.bg.hover': '#367e62',
'tabbar.tab.bg.active': '#488970',
'tabbar.divider.color': 'rgba(245, 245, 245, 0.14)',
'tabbar.tab.title.color': 'var(--kd-color-text-white)',
'tabbar.tab.title.color.active': 'var(--kd-color-text-white)',
'tabbar.tab.icon.color': 'rgba(255, 255, 255, 0.6)',
'tabbar.tab.button.color': 'rgba(255, 255, 255, 0.7)',
'tabbar.tab.button.color.active': 'rgba(255, 255, 255, 0.7)',
'tabbar.tab.button.bg.hover': 'rgba(255, 255, 255, 0.08)',
'tabbar.tab.button.bg.hover.active': 'rgba(255, 255, 255, 0.16)'
}
})注册消息下拉菜单(registerMenuItem)
- 支持环境:web
- 注册菜单
js
export function registerMenuItem(menuItem: ksxz.ui.IMenuItem): void- 示例
js
const commandIdA = 'docs.msg.contextmenu.test'
// 注册消息右键菜单项
ksxz.ui.registerMenuItem({
id: 'msg-contextmenu-test',// id自定义,需要全局唯一
viewletId: 'msg-contextmenu', // 可参考下面的EViewletIds枚举
label: '菜单项A',
order: 30,
command: commandIdA
})
// 注册点击事件的command
ksxz.commands.registerCommand(
commandIdA,
async (params: ksxz.ui.IMsgContextmenuCommandParams) => {
const { msgid, chatid } = params
const message = await ksxz.im.getMessage({ msgid, chatid })
console.log('消息数据体:', message)
}
)
// 注册个人中心菜单项
ksxz.ui.registerMenuItem({
id: 'caixin-personal-center-invitation', // id自定义,需要全局唯一
viewletId: 'personal-center', // 可参考下面的EViewletIds枚举
label: '邀请',
order: 2,
command: 'ksxz.showInviteDialog' // 客户端内置的command
})说明 如果需要控制菜单项的显隐状态,可以配置when属性。when属性需要传入一个字符串,基座会解析该字符串,用于控制该菜单的显隐。语法可以参考本文档的when clause contexts说明
viewletId :视图单元 id
js
// 视图单元 id, 支持通过插件扩展UI视图
export enum EViewletIds {
// 以下视图单元id已向外部插件开放---------————
MSG_CONTEXTMENU = 'msg-contextmenu', // 消息列表消息右键菜单
PERSONAL_CENTER = 'personal-center', // 个人中心菜单
CHAT_EDITOR_TOOLBAR = 'chat-editor-toolbar' // 会话编辑框工具栏菜单
COLLECTION_CONTEXTMENU = 'collection-contextmenu', // 个人-收藏-右键菜单
SEARCH_CONTEXTMENU = 'search-contextmenu', // 搜索窗口-右键菜单
CHAT_RECORD_CONTEXTMENU = 'chat-record-contextmenu', // 聊天记录-右键菜单
}获取列表选中会话(getActiveChat)
- 支持环境:web/webview
- 获取当前会话列表选中的会话
js
export function getActiveChat(): Promise<im.IChat | undefined>- 示例
js
const chat = await ksxz.ui.getActiveChat()
console.log(chat)调起通讯录选择用户(selectUsers)
- 支持环境:web/webview
- 调起通讯录选择器选择用户
js
export interface ISelectUserOptions {
/** 选择指定会话id内的成员 */
chatid?: number
/** 是否返回第三方用户id */
isThirdUserId?: boolean
/** 最大选中人数 */
maxCount?: number
/** 默认选中用户id */
selectedUserIds?: number[]
/** 是否多选 */
isMultiple?: boolean
/** 通讯录选择器标题 */
title?: string
/** 确定按钮文案 */
confirmText?: string
/** 取消按钮文案 */
cancelText?: string
}
/** 调起通讯录选择器选择用户 */
export function selectUsers(options?: ISelectUserOptions): Promise<im.IUser[]>- 示例
js
const users = await ksxz.ui.selectUsers({
isThirdUserId: true,
maxCount: 300,
isMultiple: true,
})
console.log(users)窗口顶部通知(showToast)
- 支持环境:web
- 窗口顶部通知
js
export interface IShowToastOptions {
message: string
level?: 'info' | 'success' | 'warning' | 'error'
duration?: number
}
export function showToast(options: IShowToastOptions): void窗口确认弹窗(showConfirmDialog)
- 支持环境:web
- 版本要求:v4.13以上
js
export function showConfirmDialog(options: {
message: string
title: string
closeOnClickModal?: boolean
showCancelButton?: boolean
showClose?: boolean
}): Promise<void>- 示例
js
import ksxz from 'ksxz'
ksxz.ui.showConfirmDialog({
message: 'token过期,需返回登录页面重新登录!'
title: '提示'
}).then(() => {
console.log('确定事件')
}).catch(() => {
console.log('取消事件')
})注册自定义消息渲染器(showConfirmDialog)
- 支持环境:web
- registerMessageDisplayer接口用于注册自定义消息渲染器,通过registerCssResource接口注册自定义组的样式,并通过dependencyCssResourceIds属性关联起来,实现样式隔离。自定义消息的右键菜单通过registerMenuItem接口注册。
js
// 注册自定义消息
export interface IMessageDisplayerConfiguration {
// 自定义消息的类型,全局唯一
customizeType: string
// 自定义消息
MessageDisplayer: new () => IMessageDisplayer
// 自定义消息关联的样式,通过registerCssResource注册的css的id
dependencyCssResourceIds: string[]
options?: {
// 是否可以多选
isSelectable?: boolean
// 是否可以回复
isReplyable?: boolean
// 是否可以转发
isForwardable?: boolean
// 是否可以收藏
isCollectable?: boolean
// 是否可以表情快捷回复
isEmojiReplyEnabled?: boolean
// 是否可以快捷回复
isQuickReplyEnabled?: boolean
}
}
// 自定义消息构造函数
export interface IMessageDisplayer {
mount(root: HTMLElement, context: IMessageContext): void
update?(updateContextKey: string, newVal: unknown, oldVal: unknown): void
dispose(): void
}
// 自定义消息标准化参数
export interface IMessageContext {
message: im.IMessage
}
export function registerMessageDisplayer(configuration: IMessageDisplayerConfiguration): void- 示例:
js
export class WeatherMessageDisplayer implements ksxzApi.ui.IMessageDisplayer {
msgItemInstance: Vue | undefined
mount(root: HTMLElement, context: ksxzApi.ui.IMessageContext) {
const WeatherMessageCtor = Vue.extend(WeatherMessage)
this.msgItemInstance = new WeatherMessageCtor({
propsData: context
})
this.msgItemInstance.$mount(root)
}
update(key: string, newVal: unknown) {
if (this.msgItemInstance) {
if (key === 'message') {
;(this.msgItemInstance as any).message = newVal
}
}
}
dispose() {
this.msgItemInstance?.$destroy()
}
}
ksxz.ui.registerMessageDisplayer({
customizeType: 'weather_2',
// registerCssResource 接口注册的cssid
dependencyCssResourceIds: ['caixin'],
MessageDisplayer: WeatherMessageDisplayer,
options: {
// 是否可以多选
isSelectable: true,
// 是否可以回复
isReplyable: true,
// 是否可以转发
isForwardable: true,
// 是否可以收藏
isCollectable: true,
// 是否可以表情快捷回复
isEmojiReplyEnabled: true,
// 是否可以快捷回复
isQuickReplyEnabled: true
}
})注册CSS资源(registerCssResource)
- 支持环境:web
- 注册css资源,该css资源会与基座隔离,只影响关联的自定义组件。避免在全局直接引入css资源,可能会影响基座的样式,可以用raw-loader获取样式字符串,通过registerCssResource注册插件的样式。
js
// 注册css资源,用于关联自定义组件
export interface ICssResource {
id: string
cssContent: string
}
export function registerCssResource(cssResource: ICssResource): void- 示例: 可以通过import cssContent from '!!raw-loader!sass-loader!./caixin.scss 获取css字符串。
js
export const extensionCssId = 'caixin'
ksxz.ui.registerCssResource({
id: extensionCssId,
// css字符串
cssContent: `
.weather-container{
background: rgb(255, 255, 255);
padding: 8px;
border-radius: 10px;
}`
})
// 避免在全局直接引入css资源,可能会影响基座的样式!用raw-loader获取样式字符串,
// 通过registerCssResource注册样式。
import elementPlusCss from '!!raw-loader!element-plus/dist/index.css'
import apiCss from '!raw-loader!../../views/api.css'
import WeatherMessageCss from '!!raw-loader!../customMessage/WeatherMessage.css'
// shadow dom 内设置 :root 的样式是不生效的, 要把作用域改为:host
const regex = /:root\s*{/gm
const _elementPlusCss = elementPlusCss.replace(regex, ':host,:root {')
export const cssContent = _elementPlusCss + apiCss + WeatherMessageCss
export const extensionCssId = 'ksxz_ext_test_css'
export const registerCssResource = () => {
// id要全局唯一
ksxz.ui.registerCssResource({
id: extensionCssId,
cssContent
})
}唤起自定义弹窗(registerCssResource)
- 版本支持:v4.15及以上
- 支持环境:web
js
type closeDialog = () => void
export function showDialog(options?: IDialogConfiguration): closeDialog
export interface IDialogConfiguration {
render(root: HTMLElement): void
onDidClose?(): void
dependencyCssResourceIds?: string[] // 自定义弹框关联的样式,通过registerCssResource注册的css的id
isHeaderVisible?: boolean // 是否隐藏 Dialog 的头部
isFooterVisible?: boolean // 是否隐藏 Dialog 的脚部
isCloseIconVisible?: boolean // 是否显示关闭按钮
isMaskVisible?: boolean // 是否展示遮罩
isMaskClosable?: boolean // 点击蒙层是否允许关闭
title?: string // Dialog 的标题
width?: string // Dialog 的宽度
okText?: string // 脚部确认按钮的文案
cancelText?: string // 脚部取消按钮的文案
}- 示例:
js
import ksxz from 'ksxz'
const extensionCssId = 'temp'
ksxz.ui.registerCssResource({
id: extensionCssId,
cssContent:`.hello{color:red}`
})
ksxz.ui.showDialog({
width: '600px',
title: '弹窗title',
isMaskClosable: true,
isHeaderVisible: true,
isFooterVisible: false,
render(root) {
root.innerHTML = '<div class="hello">helloworld</div>'
},
onDidClose() {
console.log('onClose')
},
dependencyCssResourceIds: [extensionCssId]
})