导航滚动组件的形式参考百度百科:
http://baike.baidu.com/subview/837441/10940762.htm
它由导航条和可滚动内容两者构成。
它具有以下3个特点:
1. 导航条本身是位置固定(Dock)或浮动的;
2. 点击导航条button,内容区会滚动到相应位置;
3. 在内容区滚动,导航条会自动active当前位置对应的button;
此形式的JQuery实现有很多,比如这个Scrollit.js
http://www.bytemuse.com/scrollIt.js/
相比较常见的标签页(tab)形式,两者都能快速地定位内容,导航滚动具备的最大优势是:
它可以更好地适应不同的屏幕分辨率,更高的屏幕高度,每屏可浏览更多内容。
ExtJS官方本身没有提供这种内容组织形式,但是在ExtJS提供的丰富的基础组件和开放的扩展机制上,实现这种形式并不难。我的实现思路如下:
1. 采用tabbar作为导航条;
2.调用函数scrollIntoView实现点击按钮,滚动到指定位置;
3.响应内容区的scroll事件,active对应的导航按钮;
实现效果如下:
点击按钮“Panel2”滚动
鼠标滚动内容区,滚动到显示Panel3的位置,导航按钮自动active“Panel3”
代码如下:
/** * Demonstrates usage of navbar. */ Ext.define('DCApp.view.navpanel', { extend: 'Ext.panel.Panel', xtype: 'navpanel', layout: { type: 'fit', pack: 'start', align: 'stretch' }, bodyPadding: 10, width: 500, height: 400, items: [ { id:'panel0', listeners: { render: function(p){ p = p.getEl(); var me= this.up(); me.h0=p.getHeight(); p.on('scroll', function(e, t){ //console.log(t.scrollTop +" "+ t.clientHeight); me.onscroll(t.scrollTop,t.clientHeight); }, p); } }, title: 'Panel 0', flex: 2, frame: true, xtype: 'container', layout: 'anchor', style: { overflow: 'auto' }, defaults: { frame: true, bodyPadding: 10 }, items: [ { title: 'Panel 1', flex: 1, margin: '0 0 10 0', cls:'nav_pos', height:300, html: 'height: 300' }, { title: 'Panel 2', height: 100, margin: '0 0 10 0', cls:'nav_pos', height:400, html: 'height: 400' }, { title: 'Panel 3', flex: 2, cls:'nav_pos', height:500, html: 'height: 500' } ] } ], onscroll:function(top,h0){ var items_navpos=this.items_navpos; var offset=0; //var h0 = this.h0; for(var i=0; i<items_navpos.length; i++){ var item_navpos=items_navpos[i]; var h = item_navpos.getHeight(); //header落在移动窗口之内,或移动窗口在 两个offset之间都算 if((offset>=top && (offset<= (top+h0))) || (top>=offset && (top+h0) <= offset+h )) break; offset+=h; } this.nav(this.btns_dock.getAt(i)); }, nav:function(item,e){ if(this.item_last){ if(this.item_last==item) return false; this.item_last.removeCls('x-tab-active'); } var pnav = item.pnav; if(e){ pnav.getEl().scrollIntoView(pnav.up().getEl(),false,true); }else{ item.addCls('x-tab-active'); } this.item_last=item; }, afterRender: function(ct, position) { var items_dock=[]; var items_navpos=this.query('[cls=nav_pos]'); var me = this; for(var i=0; i<items_navpos.length; i++){ var item_navpos=items_navpos[i]; var item_dock = { closable:false, text:item_navpos.title, pnav:item_navpos, handler:me.nav, scope: me }; items_dock[items_dock.length]=item_dock; } this.items_navpos=items_navpos; this.btns_dock = this.addDocked([{ xtype: 'tabbar', dock: 'top', id:'tbar0', activeItem:1, items: items_dock }])[0].items; this.nav(this.btns_dock.getAt(0)); this.callParent(); }, initComponent: function(){ this.callParent(); } }); Ext.application({ name : 'Fiddle', launch : function() { //Ext.Msg.alert('Fiddle', 'Welcome to Sencha Fiddle!'); Ext.create('widget.navpanel', {renderTo:Ext.getBody()}); } });
在线Demo
https://fiddle.sencha.com/#fiddle/kfr