You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ExtJS类作用域问题:组件销毁指向错误

解决ExtJS Grid中作用域导致的组件销毁错误问题

这个问题的核心是作用域绑定错误:你在各个回调里用var me = this,但这些回调的scope被设置为Grid面板(比如Ext.MessageBox.confirm的最后一个参数是me,也就是Grid),所以this始终指向Grid,调用me.destroy()自然会删掉Grid本身,而不是目标组件。

下面分两个场景给出具体的修复方案:

1. 修复Window的Cancel按钮销毁错误

当你点击"Yes"创建Window后,Cancel按钮的回调里需要获取当前Window实例,而不是Grid。有两种简单的方式:

方式一:直接引用Window实例

创建Window时把它赋值给一个变量,然后在Cancel按钮的点击回调里调用这个变量的destroy():

if (button === "yes") {
    // 把Window实例存到变量里
    var updateWin = new Ext.window.Window({
        alias: 'updateWin',
        autoShow: true,
        title: translations.update,
        modal: true,
        width: 350,
        height: 200,
        items: [
            // ... 你的items代码不变
        ],
        dockedItems: [
            {
                xtype: 'toolbar',
                dock: 'bottom',
                items: [
                    { xtype: 'tbfill' },
                    {
                        xtype: 'button',
                        text: translations.cancel,
                        listeners: {
                            click: function () {
                                // 销毁当前Window实例,而不是Grid
                                updateWin.destroy();
                            }
                        }
                    },
                    // ... 保存按钮代码不变
                ]
            }
        ]
    });
    return updateWin;
}

方式二:通过组件向上查找

利用ExtJS的组件查询方法up(),从按钮本身向上找到父级Window:

{
    xtype: 'button',
    text: translations.cancel,
    listeners: {
        click: function (btn) {
            // 从按钮向上查找最近的Window组件并销毁
            btn.up('window').destroy();
        }
    }
}

这种方式更灵活,不需要额外保存Window变量,尤其适合动态创建组件的场景。

2. 修复MessageBox的No按钮销毁错误

Ext.MessageBox是一个单例组件,你不需要(也不应该)销毁它,通常用hide()方法隐藏即可。如果一定要销毁,直接调用Ext.MessageBox.destroy(),而不是用me(因为me是Grid):

} else {
    console.log('this is no!');
    // 隐藏或销毁MessageBox,而不是Grid
    Ext.MessageBox.hide();
    // 如果确实需要销毁:Ext.MessageBox.destroy();
}

另外,这里还有一个小优化点:你在change函数里调用me.onUpdate()会再次触发选择模型的获取,还可能重复弹出MessageBox。其实可以把选中的记录作为参数传递给change函数,避免重复执行逻辑:

onUpdate: function () {
    var me = this;
    var gridRec = me.getSelectionModel().getSelection();
    // 把选中的记录作为参数传给change函数
    Ext.MessageBox.confirm(translations.confirm, translations.confirmChange, function(button) {
        me.change(button, gridRec);
    }, me);
    return gridRec;
},
// 修改change函数,接收选中的记录参数
change: function (button, selectedRec) {
    var me = this;
    // 不需要再调用me.onUpdate()
    var selectedRecEmail = selectedRec[0].data.email;
    
    // ... 后续逻辑不变
}

完整修改后的代码片段

Ext.define('MyApp.FooGrid', {
    extend: 'Ext.grid.Panel',
    reference: 'fooGrid',
    getGridMenu: function () {
        var me = this;
        var ret = [
            {
                text: 'Update',
                listeners: {
                    click: me.onUpdate,
                    scope: me
                }
            }
        ];
        return me.callParent().concat(ret);
    },
    onUpdate: function () {
        var me = this;
        var gridRec = me.getSelectionModel().getSelection();
        // 传递选中记录到change回调
        Ext.MessageBox.confirm(translations.confirm, translations.confirmChange, function(button) {
            me.change(button, gridRec);
        }, me);
        return gridRec;
    },
    change: function (button, selectedRec) {
        var me = this;
        var selectedRecEmail = selectedRec[0].data.email;

        if (button === "yes") {
            return new Ext.window.Window({
                alias: 'updateWin',
                autoShow: true,
                title: translations.update,
                modal: true,
                width: 350,
                height: 200,
                items: [
                    { xtype: 'container', height: 10 },
                    {
                        xtype: 'textfield',
                        width: 300,
                        readOnly: true,
                        value: selectedRecEmail
                    },
                    {
                        xtype: 'textfield',
                        width: 300,
                        fieldLabel: translations.newPassword
                    }
                ],
                dockedItems: [
                    {
                        xtype: 'toolbar',
                        dock: 'bottom',
                        items: [
                            { xtype: 'tbfill' },
                            {
                                xtype: 'button',
                                text: translations.cancel,
                                listeners: {
                                    click: function (btn) {
                                        btn.up('window').destroy();
                                    }
                                }
                            },
                            {
                                xtype: 'button',
                                text: translations.save,
                                listeners: {
                                    click: function () {
                                        console.log("I'll save you!");
                                    }
                                }
                            }
                        ]
                    }
                ]
            });
        } else {
            console.log('this is no!');
            Ext.MessageBox.hide();
        }
    }
});

总结一下,关键是要明确每个回调函数里this的指向,不要盲目用me = this,而是通过组件引用或者查询方法获取目标组件,这样就能避免误销毁Grid面板的问题啦。

内容的提问来源于stack exchange,提问作者Nuri Engin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:50:55