如何在extJS中将事件处理程序附加到面板?

8
我想做的就是处理对extJS面板的点击。我已经尝试了这个问题上提出的所有建议以及其他所有我能找到的建议,但是它们每一个都失败了,如下所述。 在extJS面板上添加点击事件处理程序的正确语法是什么? [编辑:为了方便后来的人理解,我将添加一些内联注释--@bmoeskau]
不执行处理程序:
var menuItem1 = new Ext.Panel({
    id: 'panelStart',
    title: 'Start',
    html: 'This is the start page.',
    cls:'menuItem',
    listeners: {
        click: function() {
            alert('ok');
        }
    }
}); 

[Ed: click不是面板事件]
不执行处理程序:
var menuItem1 = new Ext.Panel({
    id: 'panelStart',
    title: 'Start',
    html: 'This is the start page.',
    cls:'menuItem',
    listeners: {
        render: function(c) {
            c.body.on('click', function() {
                alert('ok');
            });
        }
    }
}); 

[Ed: 面板未被渲染 - 添加renderTo配置。接下来,您将遇到一个空错误,告诉您 c 不是有效变量。您是否指的是 menuItem1 ?]

无法执行处理程序:

var menuItem1 = new Ext.Panel({
    id: 'panelStart',
    title: 'Start',
    html: 'This is the start page.',
    cls:'menuItem'
}); 
Ext.getCmp('panelStart').on('click', function() {
    alert('ok');
});

[Ed: click不是Panel事件。此外,Panel尚未呈现,因此如果您将回调从组件切换为元素,则会收到空错误。]

出现错误:Ext.get('panelStart')为空:

var menuItem1 = new Ext.Panel({
    id: 'panelStart',
    title: 'Start',
    html: 'This is the start page.',
    cls:'menuItem'
}); 
Ext.get('panelStart').on('click', function() {
    alert('ok');
});
从getCmp切换到get意味着您正在从引用组件(该组件确实存在,但没有单击事件)切换到引用元素(该元素具有单击事件,但尚未呈现/有效)。 使面板消失:
var menuItem1 = new Ext.Panel({
    id: 'panelStart',
    title: 'Start',
    html: 'This is the start page.',
    cls:'menuItem',
    listeners: {
        'render': {
            fn: function() {
                this.body.on('click', this.handleClick, this);
            },
            scope: content,
            single: true
        }
    },
    handleClick: function(e, t){
        alert('ok');
    }        
}); 
< p >【编辑:传递到回调函数中的作用域(content)在此代码中不是有效的引用(这是从另一个示例中错误地复制粘贴的)。由于Panel变量被创建为menuItem1,并且回调函数旨在在面板作用域中运行,因此作用域变量应该是menuItem1。此外,此面板从未呈现,请参见先前的注释。】

导致错误"Ext.fly(menuItem1.id)为空":

var menuItem1 = new Ext.Panel({
    id: 'panelStart',
    title: 'Start',
    html: 'This is the start page.',
    cls:'menuItem'
}); 
Ext.fly(menuItem1.id).addListener('click', Ext.getCmp(menuItem1.id) , this);

[Ed: 面板未被渲染,请参见上文]

...放在Ext.onReady()之外... 出现错误:Ext.getCmp('panelStart')为null

Ext.getCmp('panelStart').on('click', function() {
    alert('okoutside');
});

[Ed: 可能在运行此代码时面板尚未呈现。此外,click不是面板事件。]

...放在Ext.onReady()之外... 出错了:Ext.get('panelStart')为null

Ext.get('panelStart').on('click', function() {
    alert('okoutside');
});

...放在Ext.onReady()之外... 出现错误:Ext.fly('panelStart')为空

Ext.fly('panelStart').on('click', function() {
    alert('okoutside');
});

过去三次,我在Firebug中检查了一下,<div id="startPanel">是存在的: alt text 它可以与JQuery一起使用:
因此,使用JQuery,我只需要这样做就可以了:
$('body').delegate(('#panelStart'), 'click', function(){
    alert('ok with jquery');
});

[Ed:这不是一个好的方法。它只是将处理程序的附加延迟到稍后,当元素实际显示在DOM中时(这也可以通过Ext完成,但仍然不是正确的方法)。我在下面的答案中详细说明了正确的方法链接。 OP的尝试都非常接近,但每个人都缺少一两个关键部分。]

如何使用extJS附加类似于这样的单击处理程序?


奇怪。我尝试了你的第三个尝试(使用“c.body.on”),它可以正常工作。你确定面板首先实际呈现了吗???一些提示,第一次尝试不起作用,因为单击不是面板上的有效事件。我也可以清楚地看到第二次尝试中的语法错误。 - Jere
4个回答

7

试试这个:

var menuItem1 = new Ext.Panel({
    id: 'panelStart',
    title: '开始',
    html: '这是启动页面。',
    cls:'menuItem',
    listeners: {
        afterrender: function (comp) {
            var element = comp.getEl();
            element.on('click', function() {
                alert('好的')
            });
        }
    }
}); 

除非通过 renderTo 或将其添加到呈现它的容器中,否则此代码将不起作用。另外,afterrender 代码并不是解决此问题的很好方法。 - Brian Moeskau
嗯,我假设这并不是完整的代码 - 只是一小部分。 我也认为显而易见的是,在渲染之后这段代码将不会起作用......“afterrender”侦听器有点暗示了这一点。 这种方法虽然有效,但我肯定会接受可能它不是一个“好方法”(只是脑海中浮现的第一件事)。 也许你可以在这里添加一个注释,说明为什么这不是一个好方法。 谢谢。 - Gerrat
我解释了渲染的问题,因为显然OP不理解这个。他的一些空指针错误显然是由于Panel从未被渲染,而在他最初的问题中发布的代码中,他在将面板添加到呈现它的容器之前附加了面板内部元素的侦听器。这段代码可以正常工作,但更好的方法是将处理程序分配为面板上的单独函数,而不是匿名函数。继续下一个评论... - Brian Moeskau
此外,与其直接处理面板(Panel)的元素上的点击事件,通常更好的做法是针对特定的子元素进行操作,比如 body。面板已经内部处理了点击事件,例如在标题栏中,所以在处理底层元素上的点击事件时可能会遇到问题(而且通常不希望在应用程序代码中响应标题/页脚的点击事件)。很可能原始问题(OP)实际上想要的是类似 myPanel.body.on('click', ...) 这样的操作,其中 myPanel 已经被渲染。请注意,这也可以在渲染/渲染后的回调函数中完成,就像你展示的那样。 - Brian Moeskau
当然可以...采用“授人以渔”的方法! :) - Gerrat
@Gerrat 这个能用,但是有一种新的更简单的方法,可以看一下我的答案。 - Ruan Mendes

6
< p > [如果有其他人阅读此内容,我已经在这里进行了相当详细的解释:这里。]

您缺少一些关键概念:

click不是一个有效的面板事件,因此在面板上添加单击处理程序将无效(这是您上面发布的大部分代码的问题)。

在此代码中:

var menuItem1 = new Ext.Panel({
   ...
}); 
content.body

您从另一个答案中复制粘贴了内容,但是有误。在其他代码中,content指的是创建的面板--它是一个变量。在此代码中,您将面板创建为menuItem1,但随后尝试引用它作为content
请重新阅读我之前给您的解释,了解渲染如何在其他答案中运作。您必须将面板添加到呈现它的容器中,或者直接呈现它(通过renderTo配置)。如果两者都不做,则面板将不会显示。
使用jQuery的委托功能不是Ext JS组件的正确方法。

非常感谢您所有的评论,我会仔细研究您的评论,以便在我的代码中找到解决方案,以便我可以替换jquery方法。不过这让我想知道:为什么面板很难附加点击事件?我已经能够快速掌握“handler…”和“listeners…”上的按钮和网格行处理程序,但是面板似乎是一个特殊情况。 - Edward Tanguay
1
面板并不是一个特殊情况——只是“click”事件对于整个面板作为组件来说没有意义(对于按钮、网格行或其他组件来说则非常有意义)。因此,它不会通过面板API公开。DOM事件始终可用于DOM节点,但只有在有意义时才通过组件事件API提供。在您的情况下,“myPanel.body.on('click', ...);”是正确的方法,只需确保在执行之前呈现面板即可。 - Brian Moeskau
现在这有意义了,我一直在得到一个 menuItem1.header is undefined 的错误,但只有当我将 menuItem1 包含在手风琴布局中时才会出现,诀窍是在手风琴布局的定义之后放置 menuItem1.header.on('click',...),因为只有在那时 menuItem1 才存在,感谢您澄清这一点。 - Edward Tanguay
@bmoeskau 现在更简单的方法是 listeners: {click:{element: 'body, fn: function(){}'}} - Ruan Mendes

3

如果你想监听面板内的Ext.Elements事件,你需要在调用addListener或传递listeners配置时使用element属性,而不是等待afterrender事件来设置监听器。

var menuItem1 = new Ext.Panel({
    id: 'panelStart',
    title: 'Start',
    html: 'This is the start page.',
    cls:'menuItem',
    listeners: {
        click: {
           element: 'el', // could be 'body', or any other Ext.Elements 
                          // that are available from the component
           fn: function() {}
        }
    }
}); 

0

或者更简单的方法:

    listeners: { 'expand': {fn: adminSelected }} 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接