布局和容器

普通布局

Ext.create('Ext.panel.Panel', {
    renderTo: Ext.getBody(),
    width: 400,
    height: 300,
    title: 'Container Panel',
    items: [{
        xtype: 'panel',
        title: 'Child Panel 1',
        height: 100,
        width: '75%'
    }, {
        xtype: 'panel',
        title: 'Child Panel 2',
        height: 100,
        width: '75%'
    }]
});

在这里插入图片描述

列布局

Ext.create('Ext.panel.Panel', {
    renderTo: Ext.getBody(),
    width: 400,
    height: 200,
    title: 'Container Panel',
    layout: 'column',
    items: [{
        xtype: 'panel',
        title: 'Child Panel 1',
        height: 100,
        columnWidth: 0.5
    }, {
        xtype: 'panel',
        title: 'Child Panel 2',
        height: 100,
        columnWidth: 0.5
    }]
});

在这里插入图片描述

动态添加

var containerPanel = Ext.create('Ext.panel.Panel', {
    renderTo: Ext.getBody(),
    width: 400,
    height: 200,
    title: 'Container Panel',
    layout: 'column',
    suspendLayout: true // Suspend automatic layouts while we do several different things that could trigger a layout on their own
});

// Add a couple of child items.  We could add these both at the same time by passing an array to add(),
// but lets pretend we needed to add them separately for some reason.

containerPanel.add({
    xtype: 'panel',
    title: 'Child Panel 1',
    height: 100,
    columnWidth: 0.5
});

containerPanel.add({
    xtype: 'panel',
    title: 'Child Panel 2',
    height: 100,
    columnWidth: 0.5
});

// Turn the suspendLayout flag off.
containerPanel.suspendLayout = false;
// Trigger a layout.
containerPanel.updateLayout();

在这里插入图片描述

组件

var childPanel1 = Ext.create('Ext.panel.Panel', {
    title: 'Child Panel 1',
    html: 'A Panel'
});

var childPanel2 = Ext.create('Ext.panel.Panel', {
    title: 'Child Panel 2',
    html: 'Another Panel'
});

Ext.create('Ext.container.Viewport', {
    items: [childPanel1, childPanel2]
});

在这里插入图片描述

XTypes及懒加载

Ext.create('Ext.tab.Panel', {
    renderTo: Ext.getBody(),
    height: 100,
    width: 200,
    items: [{
        // Explicitly define the xtype of this Component configuration.
        // This tells the Container (the tab panel in this case)
        // to instantiate a Ext.panel.Panel when it deems necessary
        xtype: 'panel',
        title: 'Tab One',
        html: 'The first tab',
        listeners: {
            render: function() {
                Ext.MessageBox.alert('Rendered One', 'Tab One was rendered.');
            }
        }
    }, {
        // xtype for all Component configurations in a Container
        title: 'Tab Two',
        html: 'The second tab',
        listeners: {
            render: function() {
                Ext.MessageBox.alert('Rendered One', 'Tab Two was rendered.');
            }
        }
    }]
});

在这里插入图片描述

在这里插入图片描述

动态隐藏

所有Component都内置了show 和hide方法
默认CSS方法是“ display:none”,但是可以使用hideMode配置更改此方法:

var panel = Ext.create('Ext.panel.Panel', {
        renderTo: Ext.getBody(),
        title: 'Test',
        html: 'Test Panel',
        hideMode: 'visibility' // use the CSS visibility property to show and hide this component
    });
    panel.hide(); // hide the component
    panel.show(); // show the component

浮动组件

使用CSS绝对定位将浮动组件定位在文档流之外,并且不参与其容器的布局。
默认情况下,某些组件(例如Window)是浮动的,但是可以使用浮动 配置使任何组件浮动。

var panel = Ext.create('Ext.panel.Panel', {
    width: 200,
    height: 100,
    floating: true, // make this panel an absolutely-positioned floating component
    title: 'Test',
    html: 'Test Panel'
});

上面的代码实例化了Panel,但是没有渲染它。
一个Component要么具有 指定的renderTo配置,要么被添加为Container的子Component
浮动组件,则不需要这两个组件。首次调用浮动组件的show方法时,它们会自动呈现到文档主体

panel.show(); // render and show the floating panel
draggable-可以在屏幕上拖动浮动组件。
shadow-自定义浮动组件阴影的外观。
alignTo() -将浮动Component对齐到特定元素。
center() -使浮动组件在其Container中居中。

创建自定义组件

创建新的UI类时,必须确定该类应拥有Component的实例还是扩展该Component。
使用Class System可以轻松扩展Ext JS框架的任何部分。
Ext.Base是所有Ext JS类的构建块,并且该类的原型和静态成员由所有其他类继承。
以下示例创建Ext.Component的子类

Ext.define('My.custom.Component', {
    extend: 'Ext.Component',
    newMethod : function() {
       //...
    }
});

本示例创建一个新类My.custom.Component,该类继承了Ext.Component定义的所有新方法或属性之外的所有功能(方法,属性等)。

模板方法

render是Component中定义的方法 。它负责启动组件生命周期的呈现阶段。
render不能被覆盖,但是它onRender在处理过程中调用以允许子类实现者添加一种onRender 方法来执行特定于类的处理。每个onRender方法都必须onRender在“贡献”其额外逻辑之前调用其“超类”方法。
这是实现该onRender方法的Component子类的示例:

 Ext.define('My.custom.Component', {
    extend: 'Ext.Component',
    onRender: function() {
        this.callParent(arguments); // call the superclass onRender method
        // perform additional rendering tasks here.
    }
});

下面是可以由Component的子类实现的模板方法:

initComponent 此方法由构造函数调用。它用于初始化数据,设置配置和附加事件处理程序。
beforeShow 在显示组件之前,将调用此方法。
onShow 允许将行为添加到show操作中。调用超类的onShow之后,该组件将可见。
afterShow 显示组件后,将调用此方法。
onShowComplete 该方法afterShow完成后将调用此方法
onHide 允许将行为添加到隐藏操作中。调用超类的onHide之后,该组件将被隐藏。
afterHide 隐藏该组件后将调用此方法
onRender 允许将行为添加到渲染阶段。
afterRender 允许在渲染完成后添加行为。在这一阶段,组件的元素将根据配置进行样式设置,将添加任何已配置的CSS类名称,并将处于已配置的可见性和已配置的启用状态。
onEnable 允许在启用操作中添加行为。调用超类的onEnable之后,将启用该组件。
onDisable 允许将行为添加到禁用操作。调用超类的onDisable之后,该组件将被禁用。
onAdded 将组件添加到容器时,允许添加行为。在此阶段,组件位于父容器的子项集合中。调用超类的onAdded之后,将显示ownerCt引用,如果配置了ref,则将设置refOwner。
onRemoved 从组件的父容器中移除组件时,允许添加行为。在此阶段,该组件已从其父容器的子项集合中移除,但尚未销毁(如果父容器的autoDestroy为true,或者如果传递了真实的第二个参数,则将其销毁)。调用超类的onRemoved之后,ownerCt和refOwner将不存在。
onResize 允许在调整大小操作中添加行为。
onPosition 允许在位置操作中添加行为。
onDestroy 允许在销毁操作中增加行为。调用超类的onDestroy后,该Component将被销毁。
beforeDestroy 在销毁组件之前调用此方法。
afterSetPosition 设置“组件”位置后,将调用此方法。
afterComponentLayout 布置组件后,将调用此方法。
beforeComponentLayout 在布局组件之前调用此方法。

扩展组件

Border
Header
Header tools
Footer
Footer buttons
Top toolbar
Bottom toolbar
Containing and managing child Components

实例Component

如果所需的UI组件不需要包含任何其他组件,即仅封装执行要求的HTML,则扩展Ext.Component是合适的。
以下类是Component,它包装HTML图像元素,并允许设置和获取图像的src属性。load加载图像时还会触发一个事件

Ext.define('Ext.ux.Image', {
    extend: 'Ext.Component', // subclass Ext.Component
    alias: 'widget.managedimage', // this component will have an xtype of 'managedimage'
    autoEl: {
        tag: 'img',
        src: Ext.BLANK_IMAGE_URL,
        cls: 'my-managed-image'
    },
    // Add custom processing to the onRender phase.
    // Add a 'load' listener to the element.
    onRender: function() {
        this.autoEl = Ext.apply({}, this.initialConfig, this.autoEl);
        this.callParent(arguments);
        this.el.on('load', this.onLoad, this);
    },
    onLoad: function() {
        this.fireEvent('load', this);
    },
    setSrc: function(src) {
        if (this.rendered) {
            this.el.dom.src = src;
        } else {
            this.src = src;
        }
    },
    getSrc: function(src) {
        return this.el.dom.src || this.src;
    }
});

使用

var image = Ext.create('Ext.ux.Image');
Ext.create('Ext.panel.Panel', {
    title: 'Image Panel',
    height: 200,
    renderTo: Ext.getBody(),
    items: [ image ]
});
image.on('load', function() {
    console.log('image loaded: ', image.getSrc());
});
image.setSrc('http://www.sencha.com/img/sencha-large.png');

实例二Container

如果所需的UI组件包含其他组件,但不需要Panel的任何先前提到的其他功能,则Ext.container.Container是要扩展的适当类

onBeforeAdd 在添加新的子组件之前,将调用此方法。它被传递给新组件,并且可以用于修改组件或以某种方式准备容器。返回false会中止添加操作。
onAdd 添加新的组件后,将调用此方法。传递已添加的组件。此方法可用于更新可能取决于子项状态的任何内部结构。
onRemove 删除新的组件后,将调用此方法。将已删除的组件传递给它。此方法可用于更新可能取决于子项状态的任何内部结构。
beforeLayout 在Container布置(并在必要时呈现)其子组件之前,将调用此方法。
afterLayout 容器布局(并在必要时呈现)其子组件之后,将调用此方法。

实例三Panel

所需的UI组件必须具有页眉,页脚或工具栏,则Ext.panel.Panel是要扩展的适当类。

afterCollapse 折叠面板后,将调用此方法。
afterExpand 扩展面板后调用此方法
onDockedAdd 将停靠的项目添加到面板后,将调用此方法
onDockedRemove 从面板中删除停靠的项目后,将调用此方法

基础数据包(Model Store Proxy)

Ext.data.Model

Fields
Proxies
Validations
Associations

在这里插入图片描述

Model建立

最好从一个公共基类开始定义模型
这个基础类使您可以轻松地在一个地方为所有模型配置某些方面
最有用的两个配置选项Proxies Schema

Ext.define('MyApp.model.Base', {
    extend: 'Ext.data.Model',
    fields: [{
        name: 'id',
        type: 'int'
    }],
    schema: {
        namespace: 'MyApp.model',  // generate auto entityName
        proxy: {     // Ext.util.ObjectTemplate
            type: 'ajax',
            url: '{entityName}.json',
            reader: {
                type: 'json',
                rootProperty: '{entityName:lowercase}'
            }
        }
    }
});

您的模型基类的适当内容,尤其是其“字段”,在应用程序之间可能会有所不同。
Proxies
模型和 存储使用代理来处理模型数据的加载和保存。有两种类型的代理:客户端和服务器。
可以直接在模型的基类的架构上定义代理(如上所示schema)。
Client Proxy
客户端代理的示例包括“内存”和“ 本地存储”,它们使用HTML5 localstorage功能。尽管较旧的浏览器不支持这些新的HTML5 API。
Server Proxy
服务器代理处理将数据编组到远程服务器的问题。此类代理的示例包括AJAX,JSONPREST
Schema
一个模式是有彼此关联实体的集合。当模型指定“模式”配置时,所有派生模型都将继承该架构。在上面的示例中,已为架构配置了两个值,这些值为该架构中的所有模型建立默认值。
命名空间 这些配置中的第一个是“命名空间”。通过指定此命名空间,所有模型都会获得简称,称为“ entityName”。该短名称在定义模型之间的关联时起作用。
架构示例架构还定义了“代理”配置。这是一个对象模板,类似于基于Ext.XTemplate的文本模板。不同之处在于,对象模板在获得其数据后会生成对象。在这种情况下,该数据用于为所有未明确定义代理的模型自动定义“代理”配置。

Stores

model通常与store一起使用,store基本上是记录的集合(模型派生的类的实例)。创建store并加载其数据很简单:

var store = new Ext.data.Store ({
    model: 'MyApp.model.User'
});
store.load({
    callback:function(){
        var first_name = this.first().get('name');
         console.log(first_name);
    }
});

我们正在手动加载store以接收一组MyApp.model.User记录。然后,在store加载的回调函数被触发时(完成时)记录这些记录。

内联数据

store还可以在线加载数据。在内部,Store将我们作为数据传递的每个对象转换为适当的Model类型的记录 :

new Ext.data.Store({
    model: 'MyApp.model.User',
    data: [{
        id: 1,
        name: "Philip J. Fry"
    },{
        id: 2,
        name: "Hubert Farnsworth"
    },{
        id: 3,
        name: "Turanga Leela"
    },{
        id: 4,
        name: "Amy Wong"
    }]
});

排序和分组

new Ext.data.Store({
    model: 'MyApp.model.User',
    sorters: ['name','id'],
    filters: {
        property: 'name',
        value   : 'Philip J. Fry'
    }
});

在此存储中,数据将首先按名称排序,然后按ID排序。
数据将被过滤,仅包括名称为“ Philip J. Fry”的用户。

Associations

可以使用Associations API将模型链接在一起。大多数应用程序处理许多不同的模型,并且这些模型几乎总是相关的。
博客创作应用程序可能具有“用户”和“帖子”的模型。每个用户创建帖子。因此,在这种情况下,一个用户可以有多个帖子,但是一个帖子只能由一个用户创建。这被称为ManyToOne关系。我们可以这样表达这种关系:

Ext.define('MyApp.model.User', {
    extend: 'MyApp.model.Base',
    fields: [{
        name: 'name',
        type: 'string'
    }]
});
Ext.define('MyApp.model.Post', {
    extend: 'MyApp.model.Base',
    fields: [{
        name: 'userId',
        reference: 'User', // the entityName for MyApp.model.User
        type: 'int'
    }, {
        name: 'title',
        type: 'string'
    }]
});

表达应用程序中不同模型之间的丰富关系很容易。每个模型可以与其他模型具有任意数量的关联。此外,您的模型可以按任何顺序定义。有了此Model类型的记录后,就可以轻松遍历关联的数据。例如,如果您想获取某个用户的所有帖子,则可以执行以下操作:

// Loads User with ID 1 and related posts and comments
// using User's Proxy
MyApp.model.User.load(1, {
    callback: function(user) {
        console.log('User: ' + user.get('name'));
        user.posts(function(posts){
            posts.each(function(post) {
                console.log('Post: ' + post.get('title'));
            });
        });
    }
});

上述关联导致将新功能添加到模型中。每个用户模型都有很多帖子,这些帖子增加了user.posts()我们使用的功能。调用user.posts() 将返回配置有Post模型的store
关联不仅对加载数据有帮助。它们对于创建新记录也非常有用:

user.posts().add({
    userId: 1,
    title: 'Post 10'
});
user.posts().sync();

事件

监听

Ext.create('Ext.Panel', {
    html: 'My Panel',
    renderTo: Ext.getBody(),
    listeners: {
        afterrender: function() {
            Ext.Msg.alert('Success!', 'We have been rendered');
        }
    }
});

在这里插入图片描述
按钮点击监听

Ext.create('Ext.Button', {
    text: 'Click Me',
    renderTo: Ext.getBody(),
    listeners: {
        click: function() {
            Ext.Msg.alert('Success!', 'I was clicked!');
        }
    }
});

在这里插入图片描述
组件可以包含所需的任意数量的事件侦听器
在下面的示例中,我们通过this.hide()在鼠标悬停侦听器内部调用以隐藏Button来混淆用户。然后,我们稍后再显示一次按钮。
当this.hide()被调用时,该按钮被隐藏和hide 事件触发。hide事件触发我们的hide侦听器,该侦听器等待一秒钟并再次显示Button:

Ext.create('Ext.Button', {
    renderTo: Ext.getBody(),
    text: 'My Button',
    listeners: {
        mouseover: function() {
            this.hide();
        },
        hide: function() {
            // Waits 1 second (1000ms), then shows the button again
            Ext.defer(function() {
                this.show();
            }, 1000, this);
        }
    }
});

在这里插入图片描述
每次触发事件时都会调用事件侦听器,因此您可以根据需要继续隐藏和显示按钮。

动态添加监听

var button = Ext.create('Ext.Button', {
    renderTo: Ext.getBody(),
    text: 'My Button'
});

button.on('click', function() {
    Ext.Msg.alert('Success!', 'Event listener attached by .on');
});

在这里插入图片描述
也可以使用.on方法指定多个侦听器,类似于使用侦听器配置。以下内容回顾了前面的示例,该示例通过mouseover事件设置按钮的可见性:

var button = Ext.create('Ext.Button', {
    renderTo: Ext.getBody(),
    text: 'My Button'
});

button.on({
    mouseover: function() {
        this.hide();
    },
    hide: function() {
        Ext.defer(function() {
            this.show();
        }, 1000, this);
    }
});

在这里插入图片描述

取消监听

我们更早地创建了该函数,并将其链接到一个名为的变量中doSomething,该变量包含我们的自定义函数。由于我们最初将新doSomething功能传递给我们的侦听器对象,因此代码像以前一样开始。最终添加了Ext#method-defer函数,在开始的3秒钟内单击该按钮将产生一条警报消息。但是,三秒钟后,监听器被删除,因此没有任何反应:

var doSomething = function() {
    Ext.Msg.alert('listener called');
};

var button = Ext.create('Ext.Button', {
    renderTo: Ext.getBody(),
    text: 'My Button',
    listeners: {
        click: doSomething,
    }
});

Ext.defer(function() {
    button.un('click', doSomething);
}, 3000);

在这里插入图片描述

范围侦听器选项

在下面的示例中,我们创建一个Button和一个Panel。然后,在处理程序在Panel范围内运行的情况下,我们侦听Button的click事件。为了做到这一点,我们需要传入一个对象而不是一个处理函数。该对象包含函数AND范围

var panel = Ext.create('Ext.Panel', {
    html: 'Panel HTML'
});
var button = Ext.create('Ext.Button', {
    renderTo: Ext.getBody(),
    text: 'Click Me'
});
button.on({
    click: function() {
        Ext.Msg.alert('Success!', this.getXType());
    },
    scope: panel
});

在这里插入图片描述

单次监听

var button = Ext.create('Ext.Button', {
    renderTo: Ext.getBody(),
    text: 'Click Me',
    listeners: {
        click: {
            single: true,
            fn: function() {
                Ext.Msg.alert('Success!','I will say this only once');
            }
        }
    }
});

在这里插入图片描述

使用缓冲区配置

对于短时间连续触发多次的事件,我们可以减少次数
通过使用缓冲区配置来调用侦听器。在这种情况下,无论您单击多少次,按钮的单击侦听器仅每2秒调用一次,做了延迟处理

var button = Ext.create('Ext.Button', {
    renderTo: Ext.getBody(),
    text: 'Click Me',
    listeners: {
        click: {
            buffer: 2000,
            fn: function() {
                Ext.Msg.alert('Success!','I say this only once every 2 seconds');
            }
        }
    }
});

在这里插入图片描述

自定义事件

通过fireEvent使用事件名称进行调用来触发自己的事件。在以下示例中,我们触发一个名为myEvent的事件,该事件传递两个参数-按钮本身以及介于1到100之间的随机数

var button = Ext.create('Ext.Button', {
    renderTo: Ext.getBody(),
    text: "Just wait 2 seconds",
    listeners: {
        myEvent: function(button, points) {
            Ext.Msg.alert('Success!', 'myEvent fired! You score ' + points + ' points');
        }
    }
});
Ext.defer(function() {
    var number = Math.ceil(Math.random() * 100);
    button.fireEvent('myEvent', button, number);
}, 2000);

在这里插入图片描述

监听DOM

并非每个ExtJS组件都有监听事件。但是,通过定位容器的元素,我们可以附加给DOM元素监听事件,然后组件可以对其进行侦听。在此示例中,我们以Ext.container.Container为目标。容器没有点击事件。让我们给一个!

var container = Ext.create('Ext.Container', {
    renderTo: Ext.getBody(),
    html: 'Click Me!',
    listeners: {
        click: function() {
            Ext.Msg.alert('Success!', 'I have been clicked!')
        }
    }
});

container.getEl().on('click', function() {
    this.fireEvent('click', container);
}, container);

在这里插入图片描述

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐