[Ext JS 6 By Example 翻译] 第6章 - 高级组件

本文介绍了ExtJS中的高级组件treepanel和dataview的使用方法,并通过一个图片浏览器示例项目展示了如何利用这两个组件实现复杂的用户界面。

转载自:http://www.jeeboot.com/archives/1227.html


本章涵盖了高级组件,比如 tree 和 data view。它将为读者呈现一个示例项目为 图片浏览器,它使用 tree 和 data view 组件。以下是本章将要讨论的主题:

  • Trees
  • Data views
  • 拖放
  • 图片浏览器 — 一个示例项目

本章的主要目标是探索 tree panel 和 data view 并且使用他们来构建一个示例项目图片浏览器。图片浏览器的最终展示效果如下图。

这个项目中的最重要的组件是 tree panel 和 data view 。本项目中使用的组件和概念有:

  • tree panel
  • Data views
  • Model
  • store 和 rest 代理
  • 容器和布局
  • 引用
  • 事件处理
  • 过滤

除了 tree panel 和 data view 你已经在之前的章节中学习了所有的我们目前已用到的知识。所以在本章中,我们首先学习 tree panel 和 data view。


 

tree panel

这在 ExtJS 中是一个非常强大且常用的组件,你可以使用它构建任意类型的树。一个 tree panel 是一个树形结构的具有层次化数据的UI。

它和 Ext.grid.Panel 相似, Ext.tree.Panel 也继承自Ext.panel.Table 。所以,它也是支持多列的。

和 grid panel 不同的是,tree panel 需要一个 tree store (Ext.Store.TreeStore)。 tree store 具有一些 tree panel 的功能所需使用的特殊的属性。

 

基本的 tree

我们来用一个简单的例子演示。tree panel 至少需要一个 tree store 来提供数据。我们首先来创建 tree store 并硬编码内置数据:

var store = Ext.create('Ext.data.TreeStore', {
	root: {     
		expanded: true,     
		text: 'Continents',
		children: [{       
			text: 'Antarctica',       
			leaf: true
		}, {
			text: 'South America',       
			expanded: true,       
			children: [{         
				text: 'Brazil',         
				leaf: true
			}, {         
				text: 'Chile',         
				leaf: true
			}]     
		}, {       
			text: 'Asia',       
			expanded: true,       
			children: [{         
				text: 'India',         
				leaf: true
			},{         
				text: 'China',         
				leaf: true
			}]     
		}, {       
			text: 'Africa',       
			leaf: true
		}]   
	} 
});

接着继续创建 Ext.tree.Panel :

Ext.create('Ext.tree.Panel', {   
	title: 'Basic Tree',   
	width: 200,   
	height: 450,   
	store: store,
	rootVisible: true,   
	renderTo: Ext.getBody() 
});


下列截图为以上代码的输出结果:


现在,我们创建一个高级点的树,它是可以拖拽的。同时还需要用到 tree panel 和 tree store 的一些额外选项。拖拽只需要添加一个插件叫做 treeviewdragdrop 。如以下代码所示:

var store = Ext.create('Ext.data.TreeStore', {   
	root: {     
		expanded: true,     
		text: 'Continents',
		checked: false,     
		children: [{       
			text: 'Antarctica',       
			leaf: true ,       
			checked: false
		},{
			text: 'South America',       
			expanded: false,       
			checked: true,       
			children: [{         
				text: 'Chile',         
				leaf: true,
				checked: true
			}]
		},{       
			text: 'Asia',       
			expanded: true,       
			checked: true,       
			children: [{         
				text: 'India',         
				leaf: true,         
				checked: true       
			},{         
				text: 'China',         
				leaf: true,         
				checked: true
			}]
		},{       
			text: 'Africa',       
			leaf: true,       
			checked: true
		}]
	}
});
 
Ext.create('Ext.tree.Panel', {   
	title: 'Basic Tree',   
	width: 200,   
	height: 450,   
	store: store,   
	rootVisible: true,   
	useArrows: true,   
	lines: false,   
	renderTo: Ext.getBody(),   
	viewConfig: {     
		plugins: {       
			ptype: 'treeviewdragdrop',       
			containerScroll: true
		}
	}
});


如以下截图所示的输出。我把节点  South America 拖拽至  Asia 节点之下:


tree grid

你可以将多个列添加到 tree ,同时也能创建 tree grid 。默认 tree 包含一列,用的是 tree store 中节点的文本字段。

在这个 store 中,你可以看到在每个节点上除了节点名称,还添加了一些其他的字段,这些字段用于在 tree panel 的列展示上。tree grid 的功能有例如 列调整,排序,过滤等等,以下是代码:

var store = Ext.create('Ext.data.TreeStore', {   
	root: {     
		expanded: true,     
		text: 'Continents',     
		children: [{       
			name: 'Antarctica',       
			population: 0,       
			area: 14,       
			leaf: true
		},{
			name: 'South America',       
			population: 385 ,       
			area: 17.84,       
			expanded: false,       
			children: [{         
				name: 'Chile',
				population: 18,         
				area: 0.7,         
				leaf: true,
			}]
		},{       
			name: 'Asia',       
			expanded: true,       
			population: 4164,       
			area: 44.57,       
			children: [{         
				name: 'India',         
				leaf: true,         
				population: 1210,         
				area: 3.2
			},{         
				name: 'China',         
				leaf: true,         
				population: 1357,         
				area: 9.5
			}]
		},{       
			name: 'Africa',       
			leaf: true,       
			population: 1110,       
			area: 30
		}]
	}
});

以下的 grid 和上面的 tree panel 差不多一样,只是添加为多列了,这个 xtyp treecolumn 提供缩进和文件夹结构。像一个正常的 grid 一样,tree grid 的列可以是任意类型的例如 checkbox,picture,button,URL 等等。

默认列大小是可调整的,如果需要你也可以固定它的宽度。看下面的代码:

Ext.create('Ext.tree.Panel', {   
	title: 'Tree Grid',   
	width: 500,   
	height: 450,   
	store: store,   
	rootVisible: false,   
	useArrows: true,
	lines: false,   
	scope: this,   
	renderTo: Ext.getBody(),   
	columns: [{     
		xtype: 'treecolumn',     
		text: 'Name',     
		flex: 1,     
		sortable: true,     
		dataIndex: 'name'
	} , {    
		text: 'Population (millons)',     
		sortable: true,     
		width: 150,     
		dataIndex: 'population'
	} , {    
		text: 'Area (millons km^2)',     
		width: 150,     
		sortable: true,     
		dataIndex: 'area'
	}]
});

这是上面 Tree Grid 的输出结果:

 

Data views

Ext.view.View (xtype:dataview) 一个现实数据的自定义模板。你需要提供自定义的模板和数据源(store)。模板应该使用 Ext.XTemplate 。

data view 提供了内置的事件,例如 click,double-click,mouseover,mouseout,等等。

首先我们创建一个简单的 model 名为 Person ,还需要创建一个 store 并持有 Person 的列表,如以下代码所示:

Ext.define('Person', {
	extend : 'Ext.data.Model',
	fields : [ {
		name : 'name',
		type : 'string'
	}, {
		name : 'age',
		type : 'int'
	}, {
		name : 'gender',
		type : 'int'
	} ]
});
 
Ext.create('Ext.data.Store', {
	id : 'employees',
	model : 'Person',
	data : [{
		name : 'Mike',
		age : 22,
		gender : 0
	},{
		name : 'Woo',
		age : 32,
		gender : 1
	},{
		name : 'John',
		age : 33,
		gender : 1
	},{
		name : 'Kalai',
		age : 25,
		gender : 0
	}]
});

然后我们要来创建这个模板。下列模板使用 HTML 的 table 元素来呈现自定义格式的数据。

在模板中使用一个 model 的字段时,你可以使用花括号包括字段名的方式来使用它,例如:{fieldname}

XTemplate 支持有条件的展现和 if 语句,如以下代码所示:

var empTpl = new Ext.XTemplate(
'<tpl for=".">',
   '<div style="margin-bottom: 10px;" class="data-view">',
   '<table style="width:100%">',
     '<tr>',
       '<td style="font-size: 100px;width:100px;" rowspan="3"><i class="fa fa-user"></i></td>',         
       '<td>Name: {name}< /td>',
     '</tr>',
     
     '<tr>',
       '<td>Age:{age}< /td>',
     '</tr>',
     
     '<tr>',
       '<td>Gender: <tpl if="gender == 1">',
         '<i class="fa fa-mars"></i>',
         '<tpl else>',
         '<i class="fa fa-venus"></i>',
         '</tpl></td>',
     '</tr></table> ',
   '</div>',
'</tpl>'
);

看上面的例子,我使用了 awesome 字体图标的样式。你需要添加下列代码到你的 HTML 文件才行:

<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font- awesome/4.3.0/css/font-awesome.min.css">

一下代码创建了一个 data view,并且它指定了使用的数据源 store ,template 和 itemSelector :

Ext.create('Ext.view.View', {
  store : Ext.getStore('employees'),
  tpl : empTpl,
  itemSelector : 'div.data-view',
  renderTo : Ext.getBody(),
  listeners : {
    itemclick : function(node, rec, item, index, e) {
      alert(rec.data.name);
    }
  }
});

itemSelector 是一个必须的简单 CSS 选择器。这里 itemSelector 是应用于在 template 中的 HTML ,就是使用 data-view 类的 div 标签,最终根据这个模板,你在 data view 中选择的每一个 item ,就是这样一个 div 标签,设置了 itemSelector 属性,data view 会知道如何处理这些节点,itemSelector 是用于将 DOM 节点映射到 records 。

你可以监听的事件例如 click ,double-click ,等等,以上代码已经添加了监听,下列是输出结果:

 

 

图片浏览器 – 一个示例项目

惯例,我们将用一个示例项目来回顾本章所学,下面是示例项目的最终设计效果:


通过查看这个设计,你会看到我们使用的最重要的组件就是 tree panel 和 data view 。它们如何使用和一些概念已经在本章的前面部分提及。

 

我们看看, 项目的目录结构。



下列视图代码是本项目的重要部分。这个视图呈现了应用中大部分可视组件。它使用 tree panle 和 data view :

Ext.define('PE.view.pics.Pics', {
  extend : 'Ext.panel.Panel',
  /* Marks these are required classes to be to loaded before loading this view */
  requires : [ 'PE.view.pics.PicsController' ],
  xtype : 'app-pics',
  controller : 'pics',
  items : [ {
    xtype : 'container',
    layout : 'hbox',
    cls : 'pics-list',
    items : [ {
      xtype : 'treepanel',
      width : 200,
      height : '100%',
      store : 'albums',
      border : true,
      useArrows : true,
      cls : 'tree',
      rootVisible : false,
      listeners : {
        itemdblclick : 'onNodeSelect'
      },
      dockedItems : [ {
        xtype : 'toolbar',
        dock : 'top',
        ui : 'footer',
        items : [{
          xtype : 'component',
          flex : 1
        },{
          xtype : 'button',
          text : 'Upload',
          cls : 'btn-blue'
        }]
      }]
    },{
      xtype : 'dataview',
      reference : 'picsList',
      cls : 'pics-list-content',
      store : 'pics',
      tpl : [
             '<tpl for=".">',
             '<div class="thumb"><img src="{url}" title=""></div>',
             '</tpl>'
      ],
      multiSelect : true,
      minHeight : 400,
      flex : 1,
      trackOver : true,
      overItemCls : 'x-item-over',
      itemSelector : 'div.thumb',
      emptyText : 'No images to display'
    }]
  }]
});

控制器 ViewController 里处理了 tree panel 的 itemdblclick 事件,只显示所选择节点下的图片。

还有一个 upload 按钮的 click 事件,这里是未处理的。额,这是你的作业啦。看看下列代码:

Ext.define('PE.view.pics.PicsController', {
  extend : 'Ext.app.ViewController',
  alias : 'controller.pics',
  views : [ 'PE.view.pics.Pics' ],
  requires : [ 'PE.store.Pics', 'PE.store.Albums' ],
  onNodeSelect : function(node, rec, item, index, e){
    var albums = [];
    albums.push(rec.id);
    rec.childNodes.forEach(function(item) {
      albums.push(item.id);
    });
 
    Ext.getStore('pics').filter({
      property : 'albumId',
      operator : 'in',
      value : albums
    });
  }
});


Model 和 Store 的代码在这儿。

  • 注意:当你不指定 model 的字段类型时,将会自动猜测类型。

Ext.define('Pic', {
  extend : 'Ext.data.Model',
  fields : [ 'id', 'url', 'albumId' ]
});
 
Ext.define('PE.store.Pics', {
  extend : 'Ext.data.Store',
  storeId : 'pics',
  model : 'Pic',
  proxy : {
    type : 'rest',
    url : 'pics', // URL that will load data with respect to start and limit params
    reader : {
      type : 'json'
    }
  }
});
 
Ext.create('PE.store.Pics').load();
 
Ext.define('PE.store.Albums', {
  extend : 'Ext.data.TreeStore',
  storeId : 'albums',
  root : {
    expanded : true,
    children : [ {
      id : 100,
      text : ' California',
      expanded : true,
      children : [ {
        id : 600,
        text : ' Big Sur',
        leaf : true
      }, {
        id : 500,
        text : ' Yosemite',
        leaf : true
      }]
    }, {
      id : 400,
      text : ' Arizona',
      expanded : true,
      children : [ {
        id : 300,
        text : ' Horseshoe bend',
        leaf : true
      }]
    }, {
      id : 200,
      text : ' Home',
      leaf : true
    }, {
      id : 700,
      text : ' India',
      expanded : true,
      children : [ {
        id : 800,
        text : ' Ooty',
        leaf : true
      }, {
        id : 900,
        text : ' Chennai',
        leaf : true
      }, {
        id : 1000,
        text : ' Munnar',
        leaf : true
      } ]
    } ]
  }
});
 
Ext.create('PE.store.Albums');

我是用的 Go 语言为此项目写的 REST API 。完整可用的代码在这里 https://github.com/ananddayalan/extjs-byexample-picture-explorer

图片浏览器这个示例是一个非常简单并用来学习 tree panel 和 data view 使用是很合适的。也可以通过添加更多功能来改进这个例子。例如如何通过拖拽将图片从一个相册移动到另一个相册中。 我会留给你作为一个编码的练习,但在这里,我给你简要的概述一下拖拽功能,这将帮助你在此项目中添加拖拽功能。

拖拽

任意元素或组件都能支持拖拽。使用拖拽有三个重要的事情:

  • 配置 item 为可拖拽的Configure the items as draggable
  • 创建放置目标
  • 完成放置目标

配置 item 为可拖拽的

想要拖拽一个 item ,你需要为每一个元素创建 Ext.dd.DD 实例。

查看下列代码,通过创建 Ext.dd.DD 让所有使用 pics 类的 div 元素成为可拖拽的:

// Configure the pics as draggable var pics = Ext.get('pics').select('div');
Ext.each(pics.elements, function(el) {
  var dd = Ext.create('Ext.dd.DD', el, ' picsDDGroup', {
    isTarget : false
  });
});

创建放置目标

使用 Ext.dd.DDTarget 创建放置容器。以下代码为所有的使用 album 类的 div 元素创建放置目标:

var albums = Ext.get('album').select('div');
Ext.each(albums.elements, function(el) {
  var albumDDTarget = Ext.create('Ext.dd.DDTarget', el,
  'picsDDGroup');
});

完成放置目标

当一个可拖拽项放置到一个放置容器,我们需要从这个 item 的源位置将它移动到目标位置。这通过覆盖 DD 的 onDragDrop 方法来实现。看一看下列代码:

var overrides = {
  onDragDrop : function(evtObj, targetElId) {
    var dropEl = Ext.get(targetElId);
    if (this.el.dom.parentNode.id != targetElId) {
      dropEl.appendChild(this.el);
      this.onDragOut(evtObj, targetElId);
      this.el.dom.style.position = '';
      this.el.dom.style.top = '';
      this.el.dom.style.left = '';
    } else {
      this.onInvalidDrop();
    }
  },
  onInvalidDrop : function() {
    this.invalidDrop = true;
  }
};

因为 DD 元素已经是实例了,重写的方法需要应用 Ext.apply(dd, overrides) ,如以下代码所示:

var albums = Ext.get('album').select('div');
var pics = Ext.get('pics').select('div');
Ext.each(pics.elements, function(el) {
  var dd = Ext.create('Ext.dd.DD', el, ' picsDDGroup', {
    isTarget : false
  });
  Ext.apply(dd, overrides);
});


总结

在本章中,你学习到如何使用拖拽功能。我们也看了几个高级组件:tree panel 和 data view。最后结合所学创建了一个示例项目。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值