extjs-mvc结构实践(三):完善基本页面2
一般经典的后台管理系统,都是左侧菜单右侧tabs结构布局。不免俗,咱也这么实现!
定义左侧导航菜单
新建:app/luter/view/main/Navlist.js
/**
* 采用extjs6的list tree组件构建一个导航菜单
*/
Ext.define('luter.view.main.Navlist', {
extend: 'Ext.list.Tree',
alias: 'widget.navlist',
width: 240,
minWidth: 120,
frame: true,
border: true,
split: true,
expanderFirst: false,
expanderOnly: false,
highlightPath: true,
itemId: 'navigationTreeList',
ui: 'navigation',
store: 'NavTreeStore',
initComponent: function () {
this.callParent(arguments);
}
});
为了显示icon图标,引入font awsome字体图标,在app.html引入:
<!--引入fontawsome-->
<link href="https://cdn.bootcss.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
定义导航菜单数据Store:app/luter/store/NavTreeStore.js
Ext.define('luter.store.NavTreeStore', {
extend: 'Ext.data.TreeStore',
fields: ['id', 'text', 'leaf', 'module', 'tips', 'icon'],
autoLoad: true,
proxy: {
type: 'ajax',
url: 'app/testdata/menu.json',
reader: {
type: 'json',
root: 'children',
successProperty: 'success'
},
actionMethods: {
read: 'GET'
},
listeners: {
exception: function (proxy, response, operation, eOpts) {
DealAjaxResponse(response);
}
}
},
root: {
text: '功能菜单',
id: 0,
leaf: false,
expanded: false
},
listeners: {
beforeload: function (store, operation, eOpts) {
if (store.isLoading()) return false;
},
nodeappend: function (me, node, index, eOpts) {
//展开节点。
if (!node.isRoot() && !node.get('leaf')) {
node.set('expanded', true);
}
}
}
});
/**
* 解决问题:主要是因为RootTreeItem引起
* ext-all.js?v=20000000:22 Uncaught TypeError: b.getFloated is not a function
*/
Ext.define('Overrides.list.RootTreeItem', {
override: 'Ext.list.RootTreeItem',
config: {
floated: null
},
setFloated: function (floated) {
var me = this,
el = me.element,
placeholder = me.placeholder,
node, wasExpanded;
if (me.treeItemFloated !== floated) {
if (floated) {
placeholder = el.clone(false, true);
placeholder.id += '-placeholder';
me.placeholder = Ext.get(placeholder);
me.wasExpanded = me.getExpanded();
me.setExpanded(true);
el.addCls(me.floatedCls);
el.dom.parentNode.insertBefore(placeholder, el.dom);
me.floater = me.createFloater();
}
else if (placeholder) {
wasExpanded = me.wasExpanded;
node = me.getNode();
me.setExpanded(wasExpanded);
if (!wasExpanded && node.isExpanded()) {
me.preventAnimation = true;
node.collapse();
me.preventAnimation = false;
}
me.floater.remove(me, false);
el.removeCls(me.floatedCls);
placeholder.dom.parentNode.insertBefore(el.dom, placeholder.dom);
placeholder.destroy();
me.floater.destroy();
me.placeholder = me.floater = null;
}
me.treeItemFloated = floated;
}
},
getFloated: function () {
return this.treeItemFloated;
},
runAnimation: function (animation) {
return this.itemContainer.addAnimation(animation);
},
stopAnimation: function (animation) {
animation.jumpToEnd();
},
privates: {
createFloater: function () {
var me = this,
owner = me.getOwner(),
ownerTree = me.up('treelist'),
floater,
toolElement = me.getToolElement();
me.floater = floater = new Ext.container.Container({
cls: ownerTree.self.prototype.element.cls + ' ' + ownerTree.uiPrefix + ownerTree.getUi() + ' ' + Ext.baseCSSPrefix + 'treelist-floater',
floating: true,
width: Ext.isIE8 ? 200 : (ownerTree.expandedWidth - toolElement.getWidth()),
shadow: false,
renderTo: Ext.getBody(),
listeners: {
element: 'el',
click: function (e) {
return owner.onClick(e);
}
}
});
floater.add(me);
floater.show();
floater.el.alignTo(toolElement, 'tr?');
return floater;
}
}
});
写点模拟菜单数据:app/testdata/menu.json
[
{
"id": "111",
"text": "系统管理",
"href": null,
"leaf": false,
"iconCls": "fa fa-home",
"module_id": "no sign",
"qtip": "这个地方显示鼠标悬停提示",
"children": [
{
"id": "11111",
"text": "用户管理",
"href": null,
"leaf": true,
"iconCls": "fa fa-user",
"module_id": "sys.UserModule",
"qtip": "系统用户管理",
"children": []
},
]
},
{
"id": "111",
"text": "系统管理",
"href": null,
"leaf": false,
"iconCls": "fa fa-home",
"module_id": "no sign",
"qtip": "这个地方显示鼠标悬停提示",
"children": [
{
"id": "11111",
"text": "用户管理",
"href": null,
"leaf": true,
"iconCls": "fa fa-user",
"module_id": "sys.UserModule",
"qtip": "系统用户管理",
"children": []
},
]
}
]
定义中间视图展示部分tabpanel:app/luter/view/main/ContentPanel.js
/*
*系统主页面TabPanel面板
*/
Ext.define('luter.view.main.ContentPanel', {
extend: 'Ext.tab.Panel',
alias: 'widget.syscontentpanel',
border: false,
plugins: [Ext.create('luter.ux.TabCloseMenu', {//用到了一个tab右键关闭插件
closeTabText: '关闭当前页',
closeOthersTabsText: '关闭其他页',
closeAllTabsText: '关闭所有页',
closeIcon: +' fa fa-remove red-color',
closeOtherIcon: ' fa fa-remove red-color',
closeAllIcon: 'fa fa-remove red-color',
})],
items: [{
xtype: 'panel',
id: 'dashboardpanel',
title: 'DASHBOARD',
baseCls: 'home-body',
closeable: false,
glyph: 42
}]
});
在viewport中引入导航树和内容区域,编辑:app/luter/view/main/Viewport.js,内容如下:
/**
* 主视图占满全屏是个viewport
*/
Ext.define('luter.view.main.ViewPort', {
extend: 'Ext.Viewport',
alias: 'widget.viewport',//别名,与xtype对应
layout: 'border',//东南西北中布局,边界嘛
stores: [],
//动态加载相关组件定义的js,相当于java的:import com.xxx.*;
requires: ['luter.view.main.Header', 'luter.view.main.Footer', 'luter.view.main.Navlist', 'luter.view.main.ContentPanel'],
initComponent: function () {
var me = this;
Ext.apply(me, {
items: [{
region: 'north',
xtype: 'appheader'
}, {
region: 'west',
xtype: 'navlist'//引入导航菜单
}, {
region: 'center',
xtype: 'syscontentpanel'//引入内容tabpanel
}, {
region: 'south',
xtype: 'sysfooter'
}]
});
me.callParent(arguments);
}
});
最后,别忘记在主控制器里加入导航菜单的Store,
修改主控制器:app/luter/controller/MainController.js
Ext.define('luter.controller.MainController', {
extend: 'Ext.app.Controller',
views: ['main.ViewPort'],
stores: ['NavTreeStore'],//引入导航树的Store
init: function (application) {
var me = this;
this.control({
'viewport': {//监听viewport的初始化事件,可以做点其他事情在这里,如有必要,记得viewport定义里的alias么?
'beforerender': function () {
console.log('viewport begin render at:' + new Date());
},
'afterrender': function () {
console.log('viewport render finished at:' + new Date());
},
}
});
}
});
现在,整个项目结构应该如图:
打开app.html,界面应该如图:
下一篇,实现左侧菜单点击与内容区域tabpanel联动功能,并且实现控制器的动态加载。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。