日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

ExtJS 4 樹 – ExtJS4中文教程 | Show Framework

 旭龍 2013-01-22

ExtJS 4 樹 – ExtJS4中文教程

ExtJS 4 樹

Tree Panel是ExtJS中最多能的組件之一,它非常適合用于展示分層的數(shù)據(jù)。Tree PanelGrid Panel繼承自相同的基類,所以所有從Grid Panel能獲得到的特性、擴(kuò)展、插件等帶來的好處,在Tree Panel中也同樣可以獲得。列、列寬調(diào)整、拖拽、渲染器、排序、過濾等特性,在兩種組件中都是差不多的工作方式。

讓我們開始創(chuàng)建一個(gè)簡單的樹組件

Ext.create('Ext.tree.Panel', {
    renderTo: Ext.getBody(),
    title: 'Simple Tree',
    width: 150,
    height: 150,
    root: {
        text: 'Root',
        expanded: true,
        children: [
            {
                text: 'Child 1',
                leaf: true
            },
            {
                text: 'Child 2',
                leaf: true
            },
            {
                text: 'Child 3',
                expanded: true,
                children: [
                    {
                        text: 'Grandchild',
                        leaf: true
                    }
                ]
            }
        ]
    }
});

運(yùn)行效果如圖

extjs-4-tree-smiple-tree.png

這個(gè)Tree Panel直接渲染在document.body上,我們定義了一個(gè)默認(rèn)展開的根節(jié)點(diǎn),根節(jié)點(diǎn)有三個(gè)子節(jié)點(diǎn),前兩個(gè)子節(jié)點(diǎn)是葉子節(jié)點(diǎn),這意味著他們不能擁有自己的子節(jié)點(diǎn)了,第三個(gè)節(jié)點(diǎn)不是葉子節(jié)點(diǎn),它有一個(gè)子節(jié)點(diǎn)。每個(gè)節(jié)點(diǎn)的text屬性用來設(shè)置節(jié)點(diǎn)上展示的文字。

Tree Panel內(nèi)部使用Tree Store存儲數(shù)據(jù)。上面的例子中使用了root配置項(xiàng)作為使用store的捷徑。如果我們單獨(dú)指定store,代碼像這樣:

var store = Ext.create('Ext.data.TreeStore', {
    root: {
        text: 'Root',
        expanded: true,
        children: [
            {
                text: 'Child 1',
                leaf: true
            },
            {
                text: 'Child 2',
                leaf: true
            },
            ...
        ]
    }
});

Ext.create('Ext.tree.Panel', {
    title: 'Simple Tree',
    store: store,
    ...
});

The Node Interface 節(jié)點(diǎn)接口

上面的例子中我們在節(jié)點(diǎn)上設(shè)定了兩三個(gè)不同的屬性,但是節(jié)點(diǎn)到底是什么?前面提到,TreePanel綁定了一個(gè)TreeStore,Store在ExtJS中的作用是管理Model實(shí)例的集合。樹節(jié)點(diǎn)是用NodeInterface裝飾的簡單的模型實(shí)例。用NodeInterface裝飾Model使Model獲得了在樹中使用需要的方法、屬性、字段。下面是個(gè)樹節(jié)點(diǎn)對象在開發(fā)工具中打印的截圖

extjs-4-tree-node-interface.png

關(guān)于節(jié)點(diǎn)的方法、屬性等,請查看API文檔(ps. 每一個(gè)學(xué)習(xí)ExtJS的開發(fā)者都應(yīng)該仔細(xì)研讀API文檔,這是最好的教材)

Visually changing your tree 外觀定制

先嘗試一些簡單的改動。把useArrows設(shè)置為true,Tree Panel就會隱藏前導(dǎo)線使用箭頭表示節(jié)點(diǎn)的展開

extjs-4-trees-arrows.png

設(shè)置rootVisible屬性為false,根節(jié)點(diǎn)就會被隱藏起來:

extjs-4-trees-root-lines.png

Multiple columns 多列

由于Tree Panel也是從Grid Panel相同的父類繼承的,因此實(shí)現(xiàn)多列很容易。

var tree = Ext.create('Ext.tree.Panel', {
    renderTo: Ext.getBody(),
    title: 'TreeGrid',
    width: 300,
    height: 150,
    fields: ['name', 'description'], //注意這里
    columns: [{
        xtype: 'treecolumn',
        text: 'Name',
        dataIndex: 'name',
        width: 150,
        sortable: true
    }, {
        text: 'Description',
        dataIndex: 'description',
        flex: 1,
        sortable: true
    }],
    root: {
        name: 'Root',
        description: 'Root description',
        expanded: true,
        children: [{
            name: 'Child 1',
            description: 'Description 1',
            leaf: true
        }, {
            name: 'Child 2',
            description: 'Description 2',
            leaf: true
        }]
    }
});

extjs-4-trees-multiple-columns.png

這里面的columns配置項(xiàng)期望得到一個(gè)Ext.grid.column.Column配置,就跟GridPanel一樣的。唯一的不同就是Tree Panel需要至少一個(gè)treecolumn列,這種列是擁有tree視覺效果的,典型的Tree Panel應(yīng)該只有一列treecolumn。

fields配置項(xiàng)會傳遞給tree內(nèi)置生成的store用。dataIndex是如何跟列匹配的請仔細(xì)看上面例子中的 namedescription,其實(shí)就是和每個(gè)節(jié)點(diǎn)附帶的屬性值匹配

如果不配置column,tree會自動生成一列treecolumn,并且它的dataIndextext,并且也自動隱藏了表頭,如果想顯示表頭,可以用hideHeaders配置為false。(LZ注:看到這里extjs3和4的tree已經(jīng)有了本質(zhì)的不同,extjs4的tree本質(zhì)上就是TreeGrid,只是在只有一列的時(shí)候,展現(xiàn)形式為原來的TreePanel)

Adding nodes to the tree 添加節(jié)點(diǎn)

tree的根節(jié)點(diǎn)不是必須在初始化時(shí)設(shè)定。后續(xù)再添加也可以:

var tree = Ext.create('Ext.tree.Panel');
tree.setRootNode({
    text: 'Root',
    expanded: true,
    children: [{
        text: 'Child 1',
        leaf: true
    }, {
        text: 'Child 2',
        leaf: true
    }]
});

盡管對于很小的樹只有默認(rèn)幾個(gè)靜態(tài)節(jié)點(diǎn)的,這種直接在代碼里面配置的方式很方便,但是大多數(shù)情況tree還是有很多節(jié)點(diǎn)的。讓我們看一下如何通過程序添加節(jié)點(diǎn)。

var root = tree.getRootNode();

var parent = root.appendChild({
    text: 'Parent 1'
});

parent.appendChild({
    text: 'Child 3',
    leaf: true
});

parent.expand();

每一個(gè)不是葉節(jié)點(diǎn)的節(jié)點(diǎn)都有一個(gè)appendChild方法,這個(gè)方法接收一個(gè)Node類型,或者是Node的配置參數(shù)的參數(shù),返回值是新添加的節(jié)點(diǎn)對象。上面的例子中也調(diào)用了expand方法展開這個(gè)新的父節(jié)點(diǎn)。

extjs-4-trees-append-children.png

上面的例子利用內(nèi)聯(lián)的方式,亦可:

var parent = root.appendChild({
    text: 'Parent 1',
    expanded: true,
    children: [{
        text: 'Child 3',
        leaf: true
    }]
});

有時(shí)我們期望將節(jié)點(diǎn)插入到一個(gè)特定的位置,而不是在最末端添加。除了appendChild方法,Ext.data.NodeInterface還提供了insertBeforeinsertChild方法。

var child = parent.insertChild(0, {
    text: 'Child 2.5',
    leaf: true
});

parent.insertBefore({
    text: 'Child 2.75',
    leaf: true
}, child.nextSibling);

insertChild方法需要一個(gè)節(jié)點(diǎn)位置,新增的節(jié)點(diǎn)將會插入到這個(gè)位置。insertBefore方法需要一個(gè)節(jié)點(diǎn)的引用,新節(jié)點(diǎn)將會插入到這個(gè)節(jié)點(diǎn)之前。

extjs-4-trees-insert-children.png

NodeInterface也提供了幾個(gè)可以引用到其他節(jié)點(diǎn)的屬性

  • nextSibling
  • previousSibling
  • parentNode
  • lastChild
  • firstChild
  • childNodes

Loading and Saving Tree Data using a Proxy 加載和保存樹上的數(shù)據(jù)

加載和保存樹上的數(shù)據(jù)比處理扁平化的數(shù)據(jù)要復(fù)雜一點(diǎn),因?yàn)槊總€(gè)字段都需要展示層級關(guān)系,這一章將會解釋處理這一復(fù)雜的工作。

NodeInterface Fields

使用tree數(shù)據(jù)的時(shí)候,最重要的就是理解NodeInterface是如何工作的。每個(gè)tree節(jié)點(diǎn)都是一個(gè)用NodeInterface裝飾的Model實(shí)例。假設(shè)有個(gè)Person Model,它有兩個(gè)字段idname

Ext.define('Person', {
    extend: 'Ext.data.Model',
    fields: [
        { name: 'id', type: 'int' },
        { name: 'name', type: 'string' }
    ]
});

如果只做這些,Person Model還只是普通的Model,如果取它的字段個(gè)數(shù):

console.log(Person.prototype.fields.getCount()); //輸出 '2'

但是如果將Person Model應(yīng)用到TreeStore之中后,就會有些變化:

var store = Ext.create('Ext.data.TreeStore', {
    model: 'Person',
    root: {
        name: 'Phil'
    }
});

console.log(Person.prototype.fields.getCount()); //輸出 '24'

TreeStore使用之后,Person多了22個(gè)字段。所有這些字段都是在NodeInterface中定義的,TreeStore初次實(shí)例化Person的時(shí)候,這些字段會被加入到Person的原型鏈中。

那這22個(gè)字段都是什么,有什么用處?讓我們簡要的看一下NodeInterface,它用如下字段裝飾Model,這些字段都是存儲tree相關(guān)結(jié)構(gòu)和狀態(tài)的:

{name: 'parentId',   type: idType,    defaultValue: null},
{name: 'index',      type: 'int',     defaultValue: null, persist: false},
{name: 'depth',      type: 'int',     defaultValue: 0, persist: false},
{name: 'expanded',   type: 'bool',    defaultValue: false, persist: false},
{name: 'expandable', type: 'bool',    defaultValue: true, persist: false},
{name: 'checked',    type: 'auto',    defaultValue: null, persist: false},
{name: 'leaf',       type: 'bool',    defaultValue: false},
{name: 'cls',        type: 'string',  defaultValue: null, persist: false},
{name: 'iconCls',    type: 'string',  defaultValue: null, persist: false},
{name: 'icon',       type: 'string',  defaultValue: null, persist: false},
{name: 'root',       type: 'boolean', defaultValue: false, persist: false},
{name: 'isLast',     type: 'boolean', defaultValue: false, persist: false},
{name: 'isFirst',    type: 'boolean', defaultValue: false, persist: false},
{name: 'allowDrop',  type: 'boolean', defaultValue: true, persist: false},
{name: 'allowDrag',  type: 'boolean', defaultValue: true, persist: false},
{name: 'loaded',     type: 'boolean', defaultValue: false, persist: false},
{name: 'loading',    type: 'boolean', defaultValue: false, persist: false},
{name: 'href',       type: 'string',  defaultValue: null, persist: false},
{name: 'hrefTarget', type: 'string',  defaultValue: null, persist: false},
{name: 'qtip',       type: 'string',  defaultValue: null, persist: false},
{name: 'qtitle',     type: 'string',  defaultValue: null, persist: false},
{name: 'children',   type: 'auto',   defaultValue: null, persist: false}

NodeInterface Fields are Reserved Names 節(jié)點(diǎn)接口的字段都是保留字

有一點(diǎn)非常重要,就是上面列舉的這些字段都應(yīng)該當(dāng)作保留字段。例如,Model中就不允許有一個(gè)字段叫做parentId了,因?yàn)楫?dāng)Model用在Tree上時(shí),Model的字段會覆蓋NodeInterface的字段。除非這里有個(gè)合法的需求要覆蓋NodeInterface的字段的持久化屬性。

Persistent Fields vs Non-persistent Fields and Overriding the Persistence of Fields 持久化字段和非持久化字段,如何覆蓋持久化屬性

大多數(shù)NodeInterface的字段都默認(rèn)是persist: false不持久化的。非持久化字段在TreeStore做保存操作的時(shí)候不會被保存。大多數(shù)情況默認(rèn)的配置是符合需求的,但是如果真的需要覆蓋持久化設(shè)置,下面展示了如何覆蓋持久化配置。當(dāng)覆蓋持久化配置的時(shí)候,只改變presist屬性,其他任何屬性都不要修改

// overriding the persistence of NodeInterface fields in a Model definition
Ext.define('Person', {
    extend: 'Ext.data.Model',
    fields: [
        // Person fields
        { name: 'id', type: 'int' },
        { name: 'name', type: 'string' }

        // override a non-persistent NodeInterface field to make it persistent
        { name: 'iconCls', type: 'string',  defaultValue: null, persist: true },
    ]
});

讓我們深入的看一下NodeInterface的字段,列舉一下可能需要覆蓋persist屬性的情景。下面的每個(gè)例子都假設(shè)使用了Server Proxy除非提示不使用。(注:這需要有一些server端編程的知識)

默認(rèn)持久化的:

  • parentId – 用來指定父節(jié)點(diǎn)的id,這個(gè)字段應(yīng)該總是持久化,不要覆蓋它
  • leaf – 用來指出這個(gè)節(jié)點(diǎn)是不是葉子節(jié)點(diǎn),因此決定了節(jié)點(diǎn)是不是可以有子節(jié)點(diǎn),最好不要改變它的持久化設(shè)置

默認(rèn)不持久化的:

  • index – 用來指出當(dāng)前節(jié)點(diǎn)在父節(jié)點(diǎn)的所有子節(jié)點(diǎn)中的位置,當(dāng)有節(jié)點(diǎn)插入或者移除,它的所有鄰居節(jié)點(diǎn)的位置都會更新,如果需要,可以用這個(gè)屬性去持久化樹節(jié)點(diǎn)的排列順序。然而如果服務(wù)器端使用另外的排序方法,最好把這個(gè)字段保留為非持久化的,當(dāng)使用WebStorage Proxy作為存儲,且需要保留節(jié)點(diǎn)順序,那一定要設(shè)置為持久化的。如果使用了本地排序,建議設(shè)置非持久化,因?yàn)楸镜嘏判驎淖児?jié)點(diǎn)的index屬性
  • depth 用來存儲節(jié)點(diǎn)在樹中的層級,如果server需要保存節(jié)點(diǎn)層級請開啟持久化。使用WebStorage Proxy的時(shí)候建議不要持久化,會多占用存儲空間。
  • checked 如果在tree使用checkbox特性,看業(yè)務(wù)需求來開啟持久化
  • expanded 存儲節(jié)點(diǎn)的展開收起狀態(tài),要不要持久化看業(yè)務(wù)需求
  • expandable 內(nèi)部使用,不要變更持久化配置
  • cls 用來給節(jié)點(diǎn)增加css類,看業(yè)務(wù)需求
  • iconCls 用來給節(jié)點(diǎn)icon增加css類,看業(yè)務(wù)需求
  • icon 用來自定義節(jié)點(diǎn),看業(yè)務(wù)需求
  • root 對根節(jié)點(diǎn)的引用,不要變動配置
  • isLast 標(biāo)識最后一個(gè)節(jié)點(diǎn),此配置一般不需要變動
  • isFirst 標(biāo)識第一個(gè)節(jié)點(diǎn),此配置一般不需要變動
  • allowDrop 用來標(biāo)識可放的節(jié)點(diǎn),此配置不要?jiǎng)?/li>
  • allowDrag 用來標(biāo)識可拖的節(jié)點(diǎn),此配置不要?jiǎng)?/li>
  • loaded 用來標(biāo)識子節(jié)點(diǎn)是否加載完成,此配置不要?jiǎng)?/li>
  • loading 用來標(biāo)識子節(jié)點(diǎn)是否正在加載中,此配置不要?jiǎng)?/li>
  • href 用來指定節(jié)點(diǎn)鏈接,此配置看業(yè)務(wù)需求變動
  • hrefTarget 節(jié)點(diǎn)鏈接的target,此配置看業(yè)務(wù)需求變動
  • qtip 指定tooltip文字,此配置看業(yè)務(wù)需求變動
  • qtitle指定tooltip的title,此配置看業(yè)務(wù)需求變動
  • children 內(nèi)部使用,不要?jiǎng)?/li>

Loading Data 加載數(shù)據(jù)

有兩種加載數(shù)據(jù)的方式。一次性加載全部節(jié)點(diǎn)和分步加載,當(dāng)節(jié)點(diǎn)過多時(shí),一次加載會有性能問題,而且不一定每個(gè)節(jié)點(diǎn)都用到。動態(tài)分步加載是指在父節(jié)點(diǎn)展開的時(shí)候加載子節(jié)點(diǎn)。

Loading the Entire Tree 一次加載

Tree的內(nèi)部實(shí)現(xiàn)是只有節(jié)點(diǎn)展開的時(shí)候加載數(shù)據(jù)。然而全部的層級關(guān)系可以通過一個(gè)嵌套的數(shù)據(jù)結(jié)構(gòu)一次全部加載,只要配置root節(jié)點(diǎn)是展開的即可

Ext.define('Person', {
    extend: 'Ext.data.Model',
    fields: [
        { name: 'id', type: 'int' },
        { name: 'name', type: 'string' }
    ],
    proxy: {
        type: 'ajax',
        api: {
            create: 'createPersons',
            read: 'readPersons',
            update: 'updatePersons',
            destroy: 'destroyPersons'
        }
    }

});

var store = Ext.create('Ext.data.TreeStore', {
    model: 'Person',
    root: {
        name: 'People',
        expanded: true
    }
});

Ext.create('Ext.tree.Panel', {
    renderTo: Ext.getBody(),
    width: 300,
    height: 200,
    title: 'People',
    store: store,
    columns: [
        { xtype: 'treecolumn', header: 'Name', dataIndex: 'name', flex: 1 }
    ]
});

假設(shè)readPersons返回?cái)?shù)據(jù)如下

{
    "success": true,
    "children": [
        { "id": 1, "name": "Phil", "leaf": true },
        { "id": 2, "name": "Nico", "expanded": true, "children": [
            { "id": 3, "name": "Mitchell", "leaf": true }
        ]},
        { "id": 4, "name": "Sue", "loaded": true }
    ]
}

最終形成的樹就是這樣

extjs-4-trees-bulk-load.png

需要注意的是:

  • 所有非葉子節(jié)點(diǎn),但是又沒有子節(jié)點(diǎn)的,例如上面圖中的Sue,服務(wù)器端返回的數(shù)據(jù)必須loaded屬性設(shè)置為true,否則這個(gè)節(jié)點(diǎn)會變成可展開的,并且會嘗試向服務(wù)器請求它的子節(jié)點(diǎn)數(shù)據(jù)
  • 另外一個(gè)問題,既然loaded是個(gè)默認(rèn)不持久化的屬性,上面一條說了服務(wù)器端要返回loaded為true,那么服務(wù)器端的其他返回內(nèi)容也會影響tree的其他屬性,比如expanded,這就需要注意了,服務(wù)器返回的有些數(shù)據(jù)可能會導(dǎo)致錯(cuò)誤,比如如果服務(wù)器返回的數(shù)據(jù)帶有root,和可能會導(dǎo)致錯(cuò)誤。通常建議除了loadedexpanded,服務(wù)器端不要返回其他會被樹利用的屬性。

Dynamically Loading Children When a Node is Expanded 節(jié)點(diǎn)展開時(shí)動態(tài)加載

對于節(jié)點(diǎn)非常多的樹,通常期望動態(tài)加載,當(dāng)點(diǎn)擊父節(jié)點(diǎn)的展開icon時(shí)再向服務(wù)器請求子節(jié)點(diǎn)數(shù)據(jù)。例如上面的例子中假設(shè)Sue沒有被服務(wù)器端返回的數(shù)據(jù)設(shè)置為loaded true,那么當(dāng)它的展開icon點(diǎn)擊時(shí),樹的proxy會嘗試向讀取api readPersons請求一個(gè)這樣的url

/readPersons?node=4

這意思是告訴服務(wù)器取得id為4的節(jié)點(diǎn)的子節(jié)點(diǎn),返回的數(shù)據(jù)格式跟一次加載相同:

{
    "success": true,
    "children": [
        { "id": 5, "name": "Evan", "leaf": true }
    ]
}

現(xiàn)在樹會變成這樣:

extjs-4-trees-dynamic-load.png

Saving Data 保存數(shù)據(jù)

創(chuàng)建、更新、刪除節(jié)點(diǎn)都由Proxy自動無縫的處理了。

Creating a New Node 創(chuàng)建新節(jié)點(diǎn)

// Create a new node and append it to the tree:
var newPerson = Ext.create('Person', { name: 'Nige', leaf: true });
store.getNodeById(2).appendChild(newPerson);

由于Model中定義過proxy,Model的save方法可以用來持久化節(jié)點(diǎn)數(shù)據(jù):

newPerson.save();

Updating an Existing Node 更新節(jié)點(diǎn)

store.getNodeById(1).set('name', 'Philip');

Removing a Node 刪除節(jié)點(diǎn)

store.getRootNode().lastChild.remove();

Bulk Operations 批處理

也可以等創(chuàng)建、更新、刪除了若干個(gè)節(jié)點(diǎn)之后,由TreeStore的sync方法一次保存全部

store.sync();

更多教程

    本站是提供個(gè)人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多