创建 MSN 界面式的 Ext JS 布局

今天开始的几篇帖子都是关于 Ext JS 布局的。伴随这一系列开始,我打算以制作一个 MSN 式的界面展开内容,也就是一个通讯器,通讯器它有展现联系人、联系人状态的地方,还有展现回话的区域。我们的目标不是实现一个消息传递系统,只是介绍其用户界面的构建过程,并有一些教学为目的的代码完成全文。

首先介绍通讯器的“联系人”区域部分,以 Ext.Window 作为容器。位于 Window 之中我会放置若干控件,控件应符合以下需求:

  • 显示用户名称、头像和当前的状态。
  • 可以让用户改变她当前的状态,可选:“在线、忙、离开或离线”。
  • 可以让用户分享一段简洁的信息(译注:类似于 QQ 的签名功能),并告知她在听着什么的音乐/歌曲。
  • 可以让用户进入她的个人信息、联系卡片或空间。
  • 显示用户的联系列表,以“是否最爱、是否在线、是否离线”划分。

接下来的帖子我会继续增强这界面。到该贴介绍完毕之时,我们所弄的 Window 应该会是像这样子:

创建 MSN 界面式的 Ext JS 布局

样子好像有点熟悉吧?:-)

好的,马上开工!

通讯器窗体

前面已经说过了,我们采用 Window 作为容器。现在所做的只是设置窗体的标题和尺寸。

var wnd = new Ext.Window({ width: 300, height: 450, layout:'fit', title: 'Instant Messenger' });

截图如下:

创建 MSN 界面式的 Ext JS 布局

显示用户名称、头像和当前的状态

显示用户名称、头像和状态的话就使用窗体的工具条 toolbar。第一步我是第一个工具条(如代码中的 tbar ),并创建一个按钮组把工具条分为两列(columns),一列用于头像,一列用于显示用户的名称:

var wnd = new Ext.Window({ width: 300, height: 450, layout:'fit', title: 'Instant Messenger', tbar: [{ xtype: 'buttongroup', columns: 2 }] });

头像和用户名都做成为工具条中的按钮。这样做的目的是我想用户点击头像和用户名的时候,就会执行一些函数。Window现在就变为:

<pre> var wnd = new Ext.Window({ width: 300, height: 450, layout:'fit', title: 'Instant Messenger', tbar: [{ xtype: 'buttongroup', columns: 2, items: [ { xtype: 'button', scale: 'large', iconCls: 'icon-user', rowspan: 2 }, { xtype: 'splitbutton', text: 'Jorge (available)' } ] }] });</pre>

看起来还不错吧!?

创建 MSN 界面式的 Ext JS 布局

用户改变其状态

要改变某种状态,我们在用户名的按钮中插入一个菜单,如下代码:

var wnd = new Ext.Window({ width: 300, height: 450, layout:'fit', title: '即時信息', tbar: [{ xtype: 'buttongroup', columns: 2, items: [{ xtype: 'button', scale: 'large', iconCls: 'icon-user', rowspan: 2 }, { xtype: 'splitbutton', text: 'Jorge (available)', menu: [{ text: 'Available', iconCls: 'ico-sts-available' }, { text: 'Busy', iconCls: 'ico-sts-busy' }, { text: 'Away', iconCls: 'ico-sts-away' }, { text: 'Appear Offline', iconCls: 'ico-sts-offline'}] }] }] }); 结果如下:

创建 MSN 界面式的 Ext JS 布局

让用户分享一段简洁的信息,或她在听着什么的音乐/歌。

要实现该功能,我使用了split 按钮,就放在用户名按钮的下面:

var wnd = new Ext.Window({ width: 300, height: 450, layout:'fit', title: 'Instant Messenger', tbar: [{ xtype: 'buttongroup', columns: 2, items: [{ xtype: 'button', scale: 'large', iconCls: 'icon-user', rowspan: 2 }, { xtype: 'splitbutton', text: 'Jorge (available)', menu: [{ text: 'Available', iconCls: 'ico-sts-available' }, { text: 'Busy', iconCls: 'ico-sts-busy' }, { text: 'Away', iconCls: 'ico-sts-away' }, { text: 'Appear Offline', iconCls: 'ico-sts-offline'}] },{ xtype: 'splitbutton', text: 'Share a quick message', menu: [{ text: 'Show what I am listening to'}] }] }] });创建 MSN 界面式的 Ext JS 布局

 

让用户进入她的个人信息、联系卡片或空间

我将如上的功能加到头像的那个按钮中去:

var wnd = new Ext.Window({ width: 300, height: 450, layout:'fit', title: 'Instant Messenger', tbar: [{ xtype: 'buttongroup', columns: 2, items: [{ xtype: 'button', scale: 'large', iconCls: 'icon-user', rowspan: 2, menu: [{ text: 'Show profile' }, { text: 'View contact card' }, { text: 'Go to your space'}] },{ xtype: 'splitbutton', text: 'Jorge (available)', menu: [{ text: 'Available', iconCls: 'ico-sts-available' }, { text: 'Busy', iconCls: 'ico-sts-busy' }, { text: 'Away', iconCls: 'ico-sts-away' }, { text: 'Appear Offline', iconCls: 'ico-sts-offline'}] },{ xtype: 'splitbutton', text: 'Share a quick message', menu: [{ text: 'Show what I am listening to'}] }] }] });

菜单效果如下:

创建 MSN 界面式的 Ext JS 布局

可以让用户改变她当前的状态,可选:“在线、忙、离开或离线”

联系人的列表就是一个TreeView。我会创建一个不可见的根节点(root node),拥有三个分支节点,叫做“在线”、“忙”、“离开”或“离线”。那么用户的联系列表将会加入到这些分支节点中。

首先在窗体中置入一个tree:

items: [{ xtype: 'treepanel', id: 'contacts-tree', border: false, useArrows: true, autoScroll: true, animate: true, containerScroll: true, bodyCssClass: 'tree-body', dataUrl: 'messenger.aspx', requestMethod: 'get', rootVisible: false, root: { nodeType: 'async', text: 'My Reporting Project', draggable: false, id: 'root-node' }}]

上面就是定义了一个Window窗体,里面还有根节点。这里就是加入“在线”、“忙”、“离开”或“离线”分支节点了,当然还有一些演示用途的联系人。afterrender 事件将会用来获取根节点的引用,在它身上加入子的节点。

var tree = Ext.getCmp('contacts-tree'); tree.on('afterrender', function(loader, node) { var root = tree.getRootNode(); var node = root.appendChild({ id: 'favorites', text: 'Favorites', expanded: true, iconCls: 'ico-fav' }); node.appendChild({ text: 'Susie', leaf: true, iconCls: 'ico-sts-available' }); node.appendChild({ text: 'Lara', leaf: true, iconCls: 'ico-sts-away' }); node = root.appendChild({ text: 'Available', expanded: true, iconCls: 'ico-grp-available' }); node.appendChild({ text: 'Jonh', leaf: true, iconCls: 'ico-sts-busy' }); node.appendChild({ text: 'Lara', leaf: true, iconCls: 'ico-sts-away' }); node.appendChild({ text: 'Susie', leaf: true, iconCls: 'ico-sts-available' }); node = root.appendChild({ text: 'Offline', expanded: true, iconCls: 'ico-grp-offline' }); })

出来的窗体的确如我们所料:

创建 MSN 界面式的 Ext JS 布局

差不多这样子了,接下来我们继续对联系人窗体加入更多的功能。

上述内容中,MSN式的通讯器的布局可显示用户的状态,显示用户的联系人列表,并提供修改状态的菜单、分享签名消息和进入用户个人信息或联系人的卡片。

需要重申的是,本文的目标不涵盖后台方面的实现,也就是不讨论整个IM系统的设计,只是设计关于Ext UI部分的内容。

本文的目标是在我构建的窗体上加入几项视觉任务:

  • 当右击联系人TreeView的“熟人”节点时,出现“编辑熟人列表"和“改变布局”。
  • 当任何联系人节点被右击时,出现“发送即时讯息”、“发送邮件讯息”和“加入熟人列表几项”。

完成的时候应该会是这样的:

 创建 MSN 界面式的 Ext JS 布局   创建 MSN 界面式的 Ext JS 布局

用Ext.Action类代替菜单的处理函数

“编辑熟人列表 Edit favorites” 和“改变布局 Change favorites layout ”这两项功能,对应的功能就是在它们的 Ext.Action实例中。我定义其 tex 以及 handler 两个配置项在对应设置菜单项的 text 文本和 handler 函数。

var editFavAction = new Ext.Action({ text: 'Edit favorites', handler: function() { Ext.Msg.alert('Action executed', 'Edit favorites...'); } }); var changeFavAction = new Ext.Action({ text: 'Change favorites layout', handler: function() { Ext.Msg.alert('Action executed', 'Change favorites layout...'); } }); var favMenu = new Ext.menu.Menu({ items: [editFavAction, changeFavAction] });

favMenu 菜单就会像这样:

创建 MSN 界面式的 Ext JS 布局

同样的套路,Action 的实例也的实例也可执行“发送即时讯息 Send instant message ”、“发送邮件讯息 Send instant message ”和“加入熟人列表 Send instant message ”的功能:

var sendImAction = new Ext.Action({ text: 'Send instant message', handler: function() { Ext.Msg.alert('Action executed', 'Send instant message...'); } }); var sendMailAction = new Ext.Action({ text: 'Send email message', handler: function() { Ext.Msg.alert('Action executed', 'Send email message...'); } }); var addToFavesAction = new Ext.Action({ text: 'Add to favorites', handler: function() { Ext.Msg.alert('Action executed', 'Add to favorites...'); } }); var contactMenu = new Ext.menu.Menu({ items: [sendImAction, sendMailAction, '-', addToFavesAction] });

contactMenu 菜单就会这样:

创建 MSN 界面式的 Ext JS 布局

Action 之目的在于允许不同的组件之间均使用同一个 Action,共享这个 Action 的各项功能。尽管在这个例子中不是太明显,但在以后的例子就不一定用不上。假设一个例子,全局菜单有某一菜单项,右键菜单中又会有同样的菜单项,那么就可以把这菜单项的功能独立出来,甚至在其他的地方不断复用。

var globalMenu = new Ext.menu.Menu({ items: [editFavAction, changeFavAction,'-', sendImAction, sendMailAction,'-', addToFavesAction] });

创建 Ext.tree.TreePanel 实例的右键菜单

树面板为我们提供了 contextmenu 事件,触发该事件换言之是出现“编辑熟人列表 Edit favorites "和“改变布局 Change favorites layout ”的菜单。要决定哪一种菜单会被显示,我们只需要检查一下所选节点的 id:

listeners: { contextmenu: function(node, e) { node.select(); var contextMenu; if (node.id == 'favorites') { contextMenu = favMenu; } else if (node.id != 'available' && node.id != 'offline') { contextMenu = contactMenu; } if (contextMenu) { contextMenu.contextNode = node; contextMenu.showAt(e.getXY()); } } }

请注意Available Offline 分支被选取的时候,哪个菜单的不活动的。

 

最后,下面给出网友制作的聊天 Session “对话框”,作为 UI 的补充。

 

创建 MSN 界面式的 Ext JS 布局

完整的代码下载:

http://miamicoder.com/file.axd?file=ExtJs_Messenger_Layout_1.zip

http://miamicoder.com/file.axd?file=ExtJs_Messenger_Layout_2.zip

上一篇:Ext 3.0新增内容系列文章之三:DWR的替代品Ext.Direct


下一篇:【推荐】Nginx基础知识之————多模块(非覆盖安装、RTMP在线人数实例安装测试)