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