插件擴展通常不包含具體的界面,但可以在界面初始化及關鍵事件觸發(fā)時得到通知并執(zhí)行代碼。例如可以通過監(jiān)聽用戶發(fā)送消息,并在消息發(fā)送之前修改消息的內(nèi)容。
每一個插件擴展需要提供一個入口模塊文件,在 package.json 文件中通過 main 屬性指定。如果不指定此文件則默認使用擴展包目錄的 index.js 文件作為主入口模塊文件。擴展主入口模塊文件為一個 JavaScript 模塊,當喧喧加載完畢時會逐個加載各個擴展的主入口模塊。在擴展主入口模塊中可以訪問全局擴展對象 global.Xext 。擴展主入口模塊應該返回一個對象,該對象可以包含如下生命周期函數(shù):
函數(shù) | 說明 | 參數(shù) |
onAttach(ext) | 當擴展被加載后調用,此時可以對擴展進行初始化 |
|
onReady(ext) | 當界面加載完畢時調用,此時擴展可以處理與界面相關操作。 |
|
onDetach(ext) | 當擴展被卸載時調用,此時應該將擴展使用的資源進行釋放,例如銷毀定時器等 |
|
onUserLogin(user, error) | 當用戶登錄完成時調用; |
|
onUserLoginout(user) | 當當前登錄的退出登錄時調用 |
|
onUserStatusChange(status, oldStatus, user) | 當用戶狀態(tài)發(fā)生變化時調用 |
用戶狀態(tài)代碼含義:
|
onSendChatMessages(messages, chat, user) | 當用戶發(fā)送聊天消息時調用 |
|
onReceiveChatMessages(messages, user) | 當用戶接收到聊天消息時調用 |
|
onRenderChatMessageContent(content) | 當在界面上需要轉化 markdown 格式的消息文本為 html 時會調用此回調方法 |
|
MainView | 當作為內(nèi)嵌應用時的 React 實現(xiàn)的界面主組件 |
|
replaceViews | 用于配置替換系統(tǒng)內(nèi)置界面組件 |
|
commands | 擴展支持的命令 |
|
contextMenuCreators | 為消息增加操作菜單 |
|
urlInspectors | 網(wǎng)址解釋器,可以將消息中的網(wǎng)址渲染成卡片形式 |
|
下面為一個簡單等插件擴展主入口模塊示例:
// 從全局擴展對象中引入模塊 const { app, components, utils } = global.Xext; // 用于存儲計時器標志 let timerTask = null; module.exports = { onAttach: (ext) => { // 擴展加載完畢了, 此時設置一個計時器,在加載完成 10 秒中之后在界面上顯示一個消息 timerTask = setTimeout(() => { alert('擴展加載完成已經(jīng) 10 秒鐘了,剛剛加載等擴展名稱是:' + ext.displayName); }); }, onDetach: (ext) => { // 擴展將被卸載,此時應該清理計時器 clearTimeout(timerTask); timerTask = null; }, onUserLogin: (user, error) => { // 當用戶登錄時在此處可以進行相關操作,下面以顯示當前登錄等結果和用戶名為例 if (user && !error) { // 表示登錄成功 components.Modal.alert('用戶登錄成功了,用戶名稱是:' + user.displayName); } else { components.Modal.alert('用戶登錄失敗了。'); } }, }
當一個擴展類型為 app (應用)時,同樣可以在 package.json 文件中使用 main 屬性指定一個主入口模塊文件,從而使得一個應用擴展具備插件擴展的機制。同理,也可以將此方式理解為一個包含應用界面的插件。
在主入口模塊中可以使用 replaceViews 字段指定一個對象來替換喧喧默認的界面組件,這些組件在 /app/views 目錄下。replaceViews 對象的鍵名為要替換的組件路徑,鍵值為要用來替換的 React 組件類或組件函數(shù)。通過界面替換機制,可以使用插件的形式來定制喧喧的界面,例如將官方的登錄界面替換為自己的實現(xiàn)。
下面的例子將展示使用自定義的 React 組件來替換官方的用戶頭像組件。這樣可以將官方的圓形用戶頭像替換為方形的頭像。更加詳細的代碼參考官方例子 replace-user-avatar-example。
// 主入口文件 index.js const UserAvatar = require('./user-avatar'); module.exports = { replaceViews: { 'common/user-avatar': UserAvatar, } };
// user-avatar.js 文件 // 從全局擴展對象中引入模塊 const { views, components, utils, nodeModules, } = global.Xext; const {React} = nodeModules; const {PropTypes, Component} = React; const {StatusDot} = views.common; const {Avatar, Emojione} = components; const {HtmlHelper} = utils; let todayTime = new Date(); todayTime.setHours(0, 0, 0, 0); todayTime = todayTime.getTime(); class UserAvatar extends Component { render() { const user = this.props.user; const className = this.props.className; const showStatusDot = this.props.showStatusDot; // 使用 react 形式返回新的用戶頭像 } } UserAvatar.propTypes = { user: PropTypes.object, className: PropTypes.string, showStatusDot: PropTypes.bool, }; UserAvatar.defaultProps = { className: null, showStatusDot: null, user: null, }; module.exports = UserAvatar;
更多建議: