Drcus | 王亚振

Drcus | 王亚振

随便写,记录点东西

ExtJs6 核心概念

发布于:  

本文参考自出处:http://www.jeeboot.com/archives/1217.html

由于看过这篇文章感觉讲的很细, 所以此文目的是为了记录, 方便日后查询使用.

核心概念

以下知识点:

  • 类系统,创建和扩展类
  • 事件
  • Ext JS 对象的查询
  • 容器
  • 布局

以下是在 Ext JS 6 的类系统中的几大组成类:

  • Ext
  • Base
  • Class
  • ClassManager
  • Loader

Ext 类

Ext 是一个全局单例的对象,在 Sencha library 中它封装了所有的类和许多实用的方法。

Ext 类中定义的方法和属性:

application 方法

这里应用是用 Ext.application 方法初始化的。这个方法的参数是一个 Ext.app.Application 对象,这个方法会加载 Ext.app.Application 类,并在页面加载完成后开始应用给定的配置。

Ext.app.Application 这个类代表我们的整个应用

Ext.application({
    name: 'Landing',
    extend: 'Landing.Application',
    init:  function() {
    
    }
});

上面代码创建一个名为 Landing 的全局变量。我们的应用里所有的类都将归属于在这样一个命名空间下面。这将降低全局变量产生冲突的可能。

define 方法

你可以用这个方法定义或者重写一个类。 这个方法有三个参数,如以下代码所示。 在这里 name 参数是你要定义的类名,data 参数是应用于这个类的属性,callback 是可选参数,这个函数将会在这个类被创建后调用:

Ext.define(name,data, callback)

创建一个名为 Car 的类:

Ext.define('Car', {
    constructor: function(name) {
        if (name) {
            this.name = name;
        }
    },
    start: function() {     
        alert('Car started');
    }
}) ;

还可以使用 define 继承扩展一个类:

Ext.define('ElectricCar', {   
    extend: 'Car',   
    start: function() {
        alert("Electric car started");
    }
}) ;

如果替换一个父类方法的实现,你可以使用 Ext.define 来重写这个方法,如以下代码所示:

Ext.define('My.ux.field.Text', {   
    override: 'Ext.form.field.Text',   
    setValue: function(val) {     
        this.callParent(['In override']);     
        return this;
    }
});

注意: 继承我们使用 extend 而重写使用 override , 总结一下,extend 会创建一个新的类,并继承父类的属性和方法,你也可以重写父类的方法。而 override并不会创建一个新的类,而是修改这个被重写的父类。

举个例子,Test 重写了 grid panel,我在其他类中创建 grid panel 时如果不引用 Test 那么重写仍然是不生效的。只有引用了 Test 重写才会生效 grid panel 才会具有 say 方法。 say 方法是在Test中定义的, 不引用就不会覆盖, 因为代码没有执行.

如果创建单例类, 那么使用singleton 属性:

Ext.define('Logger', {   
    singleton: true,   
    log: function(msg) {     
        console.log(msg);
    }
});

create 对象

创建了一个 ElectricCar 类的实例,并传递一个值(name):

var myCar = Ext.create('ElectricCar',{     name: 'MyElectricCar' }) ;

如果 Ext.Loader 是开启的,Ext.create 执行时如果 ElectricCar 类不存在将会自动的下载对应的 JS 文件。默认 Ext.Loader 是开启的;你可以通过以下方式来关闭它。

Ext.Loader.setConfig({  
   enabled: true
});

也可以使用 new 关键字来创建一个实例,如以下代码所示;可是如果这个类不存在,使用 new 关键字创建实例并不会自动下载对应的 JS文件:

var myCar = new ElectricCar('MyElectricCar');

ps: 只需要掌握使用 Ext.create 创建实例就行了,new 关键字可能是兼容 Ext 3.x 的使用方式而继续支持的。new 关键字官方是不推荐用的。

onReady

这个函数在页面加载完成后调用:

Ext.onReady(function() {
	console.info('ready ...')
	document.getElementById('loaderMask').remove()
})

widget (部件)

当定义一个类时,你可以为这个类增加一个便于记忆的别名。例如: Ext.panel.Panel 的别名为 widget.panel 。定义别名时,如以下代码所示指定 alias 属性:

Ext.define('Ext.panel.Panel', {
    extend: 'Ext.container.Container',
    alias: 'widget.panel'//这里是定义的别名,
});

也可以使用 xtype 为这个类给定一个别名。这个 xtype 是非常有用的,当你以指定 xtype 的方式应用部件时,并不会创建实例,而是在真正调用展示的时候才会创建这个类的实例。

Ext.widget 方法是通过类的 xtype 快速创建部件的。 不使用 widget 方法,你可以通过下列代码创建 Ext.panel.Panel 的实例:

Ext.create('Ext.panel.Panel', {     
    renderTo: Ext.getBody(),     
    title: 'Panel'   
});

快速创建 panel 的实例:

Ext.widget('panel', {
	renderTo: Ext.getBody(),     
    title: 'Panel'
})

也可以

Ext.create('widget.panel', {     
    renderTo: Ext.getBody(),     
    title: 'Panel'   
});

注意: 这里推荐一个在线extjs 编辑器 供测试使用 simple-online-extjs-code-editor

getClass

如果创建的实例是用 Ext.define 定义的,那么返回这个给定对象的类,否则返回 null

var button = new Ext.Button(); 
Ext.getClass(button); // returns Ext.Button

getClassName

过它的引用或实例返回类名称:

Ext.getClassName(Ext.Button); //returns "Ext.Button"

Ext.Base

这是所有 Ext 类的基础。所有的 Ext 类都继承自 Ext.Base。该类所有的原型和静态成员都会传递给继承它的类。

Ext.Class

这是一个低级别的工厂类,用于通过 Ext.ClassManager 定义一个类。所以不应该在你的代码中直接访问;你应该使用 Ext.define

Ext.ClassManager

它管理所有的类同时处理类反射。通常通过下面几个方法访问:

  • define
  • create
  • widget
  • getClass
  • getClassName

Ext.Loader

用于动态的加载依赖。通常使用 Ext.require 来指定依赖。当你定义一个类时,这样指定组件的依赖列表是一个很好的做法,如以下代码所示:

Ext.require(['widget.window', 'layout.border','Ext.data.Connection']);

如果你需要引入一个指定命名空间下所有的 组件/类 时,使用通配符,如以下代码所示:

Ext.require(['widget.*', 'layout.*', 'Ext.data.*');

使用以下语法排除掉不需要的类:

Ext.exclude('Ext.data.*').require('*');

用这种方式,依赖的类是异步加载的。如果在你定义的类中没有指定依赖的类,那么当使用 Ext.Create创建实例时,如果它是未加载的,这时将会同步加载这些类文件。这对性能有一定的影响,所以当你定义类时,使用 Ext.require 指定所需的类总是更好的。

  • requires 属性加载需要的类时,当前类初始化之前被加载。
  • uses 属性加载需要的类时,当前类初始化之后被加载。
  • singleton:true 属性当前类初始化时,该实例是一个单例对象。

注意: 定位类的文件路径是基于类名的。例如:MyApp.view.About 类的路径应该是 \myapp\view\ about.js

Events(事件)

Adding listeners

当创建对象或者创建以后都可以为这个对象添加监听器。

Ext.create('Ext.Button', {   
    renderTo: Ext.getBody(),   
    listeners: {     
        click: function() {
            Ext.Msg.alert('Button clicked!');
        }
    }
}) ;

添加多个事件监听

Ext.create('Ext.Button', {   
    renderTo: Ext.getBody(),   
    listeners: {     
        mouseout: function() {
            //Do something
        },     
        click: function() {       
            // Do something
        }   
    } 
});

也可以在对象创建之后,使用 on 方法为对象添加事件监听

var button = Ext.create('Ext.Button');
button.on('click', function() {
   //Do something
});

同样的,也可以使用 on 方法一次添加多个事件的监听

var button = Ext.create('Ext.Button');
button.on({
    mouseover: function() {
        //Do something
    },
    mouseover: function() {
        //Do something
    }
}) ;

Removing listeners

删除不必要的事件, 释放内存

var HandleClick= function() {
    Ext.Msg.alert('My button clicked!');
}
 
Ext.create('Ext.Button', {   
    listeners: {
       click: HandleClick
    } 
}) ; 
 
button.un('click', HandleClick);

页面 DOM 元素的事件处理

假设在你的 HTML 代码中,有一个 div 元素 id=mydiv

<div id="mydiv"></div>

为它添加事件监听

var div = Ext.get('mydiv');
div.on('click', function(e, t, eOpts) {
    // Do something 
});

访问 DOM

有三种方法来访问 DOM 元素:get,query,和 select 。

Ext.get

get 方法是根据这个 DOM 元素的 ID 检索获取并封装为 Ext.dom.Element 对象:

var mydiv = Ext.get('myDivId');

Ext.query

这种方式基于传入的 CSS 选择器 从给定的根节点开始查找。它返回一个匹配选择器的元素 (HTMLElement[]/Ext.dom.Element[])数组。如果没有匹配的,返回一个空值的数组对象。

下面示例中,myCustomComponent.getEl().dom 是传递的根节点。Ext.query 将检索这个节点内的子元素,并返回一个数组包含 CSS class'oddRow' 的的元素:

var someNodes = Ext.query('.oddRow', myCustomComponent.getEl().dom);

Ext.select

给出一些 CSS/XPath 选择器,Ext.select方法返回一个 CompositeElement 类型的对象,代表一个元素的集合。

这个 CompositeElement 对象可以进行过滤,迭代,和对整个集合执行整体操作等等:

var rows = Ext.select('div.row'); ////Matches all divs with class
row rows.setWidth(100); // 这是设置所有元素的宽度为 100

也可以用一行代码

Ext.select('div.row').setWidth(100);

多重选择器

通过指定多个搜索条件可以用来匹配多个元素:

Ext.select('div.row, span.title'); //匹配所有的 class 用 .row 的 div 元素,和匹配所有 class 用 .title 的 span 元素

选择器 根

当你使用 select ,它默认取 HTML body 作为根并从默认的 body 开始检索整个 DOM 树。你可以通过制定一个根元素来避免这种情况,这样它将只搜索给定的根的子节点。

Ext.get('myEl').select('div.row');

这儿使用了 'myEl' 作为根节点。这将首先找到 id‘myEl’ 的元素,然后将在根元素(myEl)下面搜索出 class‘row’div 标签。

Ext.select('div.row', true, 'myEl');// This is equivalent to the previous line.

链式选择器

下列的查询方式会匹配 classrow 并且 title 属性值为 bardiv ,这个 div 属于其父元素的首个子元素:

Ext.select('div.row[title=bar]:first')

Ext.ComponentQuery

这允许你用 IDxtype,和属性查找一个组件。你可以全局搜索或者指定一个根组件。

下列查询将返回所有的 xtypebutton 的组件:

Ext.ComponentQuery.query('button');

得到一个 idfoo 的组件,用以下代码:

Ext.ComponentQuery.query('#foo');

下列代码将返回所有的 xtypebutton 并且 title 属性值为 my button 的组件:

Ext.ComponentQuery.query("button[title='my button']");; //or parent.query('textfield[title=my button]');

嵌套选择器

Ext.ComponentQuery.query('formpanel numberfield'); // 这里获取 xtype 为 frompanel 下面的 xtype 为 numberfield 的组件

下列代码返回这个 parent 容器内匹配传递进来的选择器的第一个直接子组件,如果没有匹配上,返回 null

parent.child('button[itemId=save]');

也可以使用其他的方法,例如 nextNode, up, down, previousSibling 等等

组件,容器,和布局

Ext JS 提供了一组丰富的组件和布局

组件

从简单的组件说起,例如 buttonlabel ,到复杂的组件,例如 Tree PanelGrids 等等,Ext JS 有大量的内置组件。所有的组件都派生自 Ext.Component 类,它提供支持创建,重绘,渲染和处理组件。

所有的组件都有一个属性叫做 xtype。它是非常有用的,它用在当你不想马上实例化这个组件时,而是想让这个组件在实际被应用时才创建,就是我们俗称的懒加载。

容器

容器是一个特殊的组件类型,它能够持有其他组件。在 Ext JS 中 Ext.container.Container 类是所有的容器的基础类。

Ext.toolbar.Toolbar, Ext.panel.Panel, 和 Ext.Editor 是一些内置组件。这些组件都是可以包含其他组件。而像 Ext.button.Button 类就不是派生自 Ext.container.Container ,所以它不能够包含其他组件。

Ext.create('Ext.panel.Panel', {   
    renderTo:Ext.getBody(),   
    width:700,
    height:400,
    items:[{     
        xtype: 'panel',     
        title: 'Panel 1',
    },{     
        xtype: 'panel',     
        title: 'Panel 2',     
        height: 200,     
        items: [{
            xtype: 'button',       
            text: 'Click Me'
        }]
    },{     
        xtype: 'panel',     
        title: 'Panel 3',     
        width: 150,     
        height: 100
    }]
});

这是嵌套的组件,结构如下图所示

布局

布局定义了包含的组件是如何定位的以及设定组件的尺寸大小。每一个容器都有一个布局。默认布局是 auto。这将不会为子组件指定任何关于位置和大小的规则。

在上面的图中,你可能已经注意到这些子组件只是一个接一个嵌套在父级容器中。这是在代码中因为我们还没有为这些组件制定任何布局,默认情况下使用的是 auto 布局。

现在,让我们在相同的代码里使用一些布局。下列示例中,我们将使用 column 布局和 center 布局。

当你使用 column 布局,你可以指定 columnWidth 。所有的列的 columnWidth 的值的总和必须等于 1 。你也可以为一些列指定固定宽度,如以下代码所示。这里,Panel3 取了一个 150 的固定宽度,然后剩下的两列按照 columnWidth 的值分配剩下的宽度:

Ext.create('Ext.panel.Panel', {   
    renderTo:Ext.getBody(),   
    width:700,   
    height:400,   
    layout:'column',   
    items: [{     
        xtype: 'panel',     
        title: 'Panel 1',     
        columnWidth: 0.4,     
        height: 400,
    },{     
        xtype: 'panel',     
        title: 'Panel 2',     
        columnWidth: 0.6,     
        layout: 'center',     
        height: 400,     
        items: [{
            xtype: 'button',       
            text: 'Click Me'
        }]
    },{     
        xtype: 'panel',     
        title: 'Panel 3',     
        width: 150,     
        height: 400
    }]
});

updateLayout

updateLayoutExt.container.Container对象里的一个方法。这可以用来根据布局规则重新定位子组件。例如你修改了布局方式,需要动态的更新布局时。

suspendLayout

大多数时候你不会用到这个 updateLayout 方法,然而有些时候你必须调用它。

这个 updateLayout 方法是在你重绘和当你添加或删除了一个组件时自动调用。有时候你可能需要它暂停一下,不是马上就调用,特别是当你添加或删除多个子组件时。所以在这种情况下,你可以设置 suspendLayout 属性为 true ,一旦你完成添加或删除组件的操作,你可以设置 suspendLayoutfalse 并在你的代码中手动调用 updateLayout 方法。

同样的如果你想对整个框架停止更新布局,你可以调用 Ext.suspendLayouts() ,然后在你的操作完成后你可以通过调用 Ext.resumeLayouts(true) 恢复它。


Ext JS 中可用的布局:

  • absolute
  • accordion
  • anchor
  • border
  • card
  • center
  • column
  • fit
  • hbox
  • table
  • vbox

absolute 绝对布局

这个布局使用 xy 属性来指定组件的绝对定位:

Ext.create('Ext.panel.Panel', {   
    renderTo:Ext.getBody(),   
    width:700,   
    height:400,   
    layout:'absolute',   
    items: [{     
        xtype: 'panel',     
        title: 'Panel 1',     
        x: 12,     
        y: 20,     
        height: 250
    },{     
        xtype: 'panel',     
        title: 'Panel 2',     
        x: 200,     
        y: 150,     
        height: 200
    },{     
        xtype: 'panel',     
        title: 'Panel 3',     
        x: 400,     
        y: 250,     
        width: 150,     
        height: 100
    }]
});

accordion 手风琴(可折叠)布局

这个布局展示了在一个时间里只有一个内置的可支持折叠和展开的子级 panel

Ext.create('Ext.panel.Panel', {   
    renderTo: Ext.getBody(),   
    width: 700,   
    height: 400,   
    layout: 'accordion',   
    items: [{
        title: 'Item 1',
        html: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum'
    },{
        title: 'Item 2',     
        html: 'some content here'
    },{
        title: 'Item 3',     
        html: 'empty'
    }] 
});

anchor 锚点布局

这个布局使你能够指定子级组件的大小,而这是相对于布局容器的。首先容器根据指定的锚点规则调整然后所有的子级组件再作调整:

border 布局

这个布局允许你为子组件指定一个区域位置,例如 centernorthsouthwesteast。当你使用 border布局时,在其内的组件必须有一个指定区域为 center,如下列代码所示:

Ext.create('Ext.panel.Panel', {   
    renderTo: Ext.getBody(),   
    width: 700,   
    height: 400,   
    layout: 'border',
    items: [{     
        title: 'Item 1',     
        html: 'Item 1',     
        region: 'center'
    },{     
        title: 'Item 2',     
        html: 'Item 2',     
        region: 'east',     
        width: 200
    },{     
        title: 'Item 3',     
        html: 'Item 3',     
        region: 'south',     
        height: 100
    }] 
}) ;

card 卡片布局

在此布局中,只有一个子组件是可见的,这个组件基本上充满整个容器。卡片布局一般应用在向导或者 tabs

Ext.create('Ext.panel.Panel', {   
    renderTo: Ext.getBody(),   
    width: 700,   
    height: 400,   
    layout: 'card',   
    defaultListenerScope: true,   
    bbar: ['->',{
        itemId: 'btn-prev',     
        text: 'Previous',     
        handler: 'showPrevious',     
        disabled: true
    },{
        itemId: 'btn-next',     
        text: 'Next',     
        handler: 'showNext'
    }],   
    items: [{     
        index: 0,     
        title: 'Item 1',     
        html: 'Item 1'
    },{     
        index: 1,     
        title: 'Item 2',     
        html: 'Item 2'
    },{     
        index:2,     
        title: 'Item 3',     
        html: 'Item 3'
    }],
    showNext: function () {     
        this.navigate(1);
    },
    showPrevious: function () {     
        this.navigate(-1);
    },
    navigate: function (incr) {     
        var layout = this.getLayout();     
        var index = layout.activeItem.index + incr;     
        layout.setActiveItem(index);
        this.down('#btn-prev').setDisabled(index===0);     
        this.down('#btn-next').setDisabled(index===2);
    }
});

center 中心布局

容器的子组件在中间

column 列布局

你可以将容器划分为指定数量的列并指定每列所占的大小

fit 适配布局

子组件将会自适应容器的尺寸

Ext.create('Ext.panel.Panel', {   
    renderTo: Ext.getBody(),   
    width: 700,
    height: 400,   
    layout: 'fit',   
    bodyPadding: 20,   
    items: [{
        title: 'Item 1',
        html: 'Fills the container',
    }]
});

hbox 布局

这种布局与 column 布局几乎是一样的,但是这种布局允许你拉伸列的高度。这里使用 flex 选项为子组件设置水平的相对值:

Ext.create('Ext.panel.Panel', {   
    renderTo: Ext.getBody(),   
    width: 700,   
    height: 400,   
    layout:{     
        type: 'hbox',     
        pack: 'start',     
        align: 'stretch',
    },
    items: [{
        title: 'Item 1',
        html: 'Item 1',    
        flex: 1
    },{
        title: 'Item 2',     
        html: 'Item 2',     
        width: 100
    },{
        title: 'Item 3',     
        html: 'Item 3',     
        flex: 2
    }] 
});

VBox 布局

子组件是垂直向下一个接一个排列。

Ext.create('Ext.panel.Panel', {   
    renderTo: Ext.getBody(),   
    width: 700,   
    height: 400,   
    layout:{     
        type: 'vbox',     
        pack: 'start',     
        align: 'stretch',
    },   
    items: [{
        title: 'Item 1',     
        html: 'Item 1',     
        flex: 1
    },{
        title: 'Item 2',     
        html: 'Item 2',     
        height: 100
    },{
        title: 'Item 3',     
        html: 'Item 3',
        flex: 2
    }]
});

table 表格布局

这个布局允许你渲染一个表格出来。你可以指定列数和行数,使用 rowspancolspan 创建复杂布局:

Ext.create('Ext.panel.Panel', {   
    renderTo: Ext.getBody(),   
    width: 700,
    height: 400,   
    layout:{     
        type: 'table',     
        columns: 3,     
        tableAttrs: {       
            style: {         
                width: '100%'
            }
        }
    },   
    items: [{     
        rowspan: 3,     
        title: 'Item 1',     
        html: 'Item 1'
    },{     
        title: 'Item 2',     
        html: 'Item 2'
    },{     
        title: 'Item 3',     
        rowspan: 2,     
        html: 'Item 3'
    },{     
        title: 'Item 4',     
        html: 'Item 4'
    },{     
        title: 'Item 5',     
        html: 'Item 5'
    },{     
        title: 'Item 6',     
        html: 'Item 6'
    },{     
        title: 'Item 7',     
        html: 'Item 7'
    }]
});

总结

了解了 Ext JS 中的基础类和这些类中常用的方法,你还学习了如何创建和扩展一个类。 还有如何使用 事件 和 查询元素及组件的功能。

一个ExtJS的网站 http://ext4all.com/

厚颜一下 ~^_^~

赏赐