惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

酷 壳 – CoolShell
酷 壳 – CoolShell
H
Hacker News: Front Page
P
Palo Alto Networks Blog
T
ThreatConnect
Apple Machine Learning Research
Apple Machine Learning Research
博客园_首页
T
True Tiger Recordings
P
Privacy & Cybersecurity Law Blog
B
Blog
IT之家
IT之家
Last Week in AI
Last Week in AI
F
Full Disclosure
Hacker News: Ask HN
Hacker News: Ask HN
C
Comments on: Blog
Microsoft Azure Blog
Microsoft Azure Blog
C
Cybersecurity and Infrastructure Security Agency CISA
Microsoft Security Blog
Microsoft Security Blog
博客园 - 【当耐特】
N
News and Events Feed by Topic
NISL@THU
NISL@THU
腾讯CDC
雷峰网
雷峰网
Security Latest
Security Latest
李成银的技术随笔
M
Microsoft Research Blog - Microsoft Research
L
LangChain Blog
L
Lohrmann on Cybersecurity
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
C
Check Point Blog
Y
Y Combinator Blog
Recent Announcements
Recent Announcements
博客园 - Franky
N
News | PayPal Newsroom
V
V2EX
A
About on SuperTechFans
The Register - Security
The Register - Security
月光博客
月光博客
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Google Online Security Blog
Google Online Security Blog
MyScale Blog
MyScale Blog
Cisco Talos Blog
Cisco Talos Blog
Vercel News
Vercel News
WordPress大学
WordPress大学
C
Cyber Attacks, Cyber Crime and Cyber Security
The Hacker News
The Hacker News
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
爱范儿
爱范儿
A
Arctic Wolf
L
LINUX DO - 最新话题
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More

博客园 - hq5460

一个C#的语法糖 .NET Reflector,SQL Prompt各种破解方法及详细步骤 Total Commander快捷键分类整理大全 C#中HttpClient的使用小结 SQL Server日期计算(使用DATEADD和DATEDIFF函数) MongoDB Sharding 机制分析 avalonJS入门 Ext JS 6学习文档-第8章-主题和响应式设计 Ext JS 6学习文档-第7章-图表 Ext JS 6学习文档-第5章-表格组件(grid) Ext JS 6学习文档-第4章-数据包 Ext JS 6学习文档-第3章-基础组件 Ext JS 6学习文档–第2章–核心概念 Ext JS 6学习文档–第1章–ExtJS入门指南 Console命令详解,让调试js代码变得更简单 - hq5460 使用Node.js+Socket.IO搭建WebSocket实时应用 - hq5460 node.js应用--转载 Node.js 究竟是什么? - hq5460 windbg内核诊断方式--转载
Ext JS 6学习文档-第6章-高级组件
hq5460 · 2016-08-24 · via 博客园 - hq5460

高级组件

本章涵盖了高级组件,比如 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。

1

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 并硬编码内置数据:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

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 

1

2

3

4

5

6

7

8

Ext.create('Ext.tree.Panel', {  

title: 'Basic Tree',  

width: 200,  

height: 450,  

store: store,

rootVisible: true,  

renderTo: Ext.getBody()

});

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

1

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

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 节点之下:

1

tree grid

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

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

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 等等。

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

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 的输出结果:

 1

Data views

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

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

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

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 语句,如以下代码所示:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

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 文件才行:

1

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

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

1

2

3

4

5

6

7

8

9

10

11

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 ,等等,以上代码已经添加了监听,下列是输出结果:

 1

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

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

1

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

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

1

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

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 事件,这里是未处理的。额,这是你的作业啦。看看下列代码:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

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 的字段类型时,将会自动猜测类型。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

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 元素成为可拖拽的:

1

2

3

4

5

6

// 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 元素创建放置目标:

1

2

3

4

5

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 方法来实现。看一看下列代码:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

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) ,如以下代码所示:

1

2

3

4

5

6

7

8

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。最后结合所学创建了一个示例项目。