Ext JS 3.4网格行长按事件实现求助:适配iPad替代右键菜单
Hey there! Let's figure out how to get that long-press-to-show-context-menu working on your iPad for your Ext JS 3.4 Grid. I know it's frustrating that Ext JS 3.x doesn't have built-in touch event support, but we can work around this with a few straightforward approaches—no jQuery plugins needed (since those can clash with Ext's own event system).
Approach 1: Listen to Native Touch Events Directly
The simplest way is to bind native touchstart, touchend, and touchcancel events to your grid's element, then use a timer to detect when a press lasts long enough (typically 500ms is a standard long-press delay). Once triggered, we can reuse your existing rowcontextmenu logic to show the menu.
Here's a code example:
// Assume your grid is already defined as `grid` grid.on('render', function() { var gridEl = grid.getEl(); var longPressTimer; // Handle touch start to start the timer gridEl.on('touchstart', function(e, target) { // Find the clicked grid row element var rowEl = Ext.fly(target).findParent('.x-grid3-row', null, true); if (rowEl) { var rowIndex = grid.getView().findRowIndex(rowEl); var record = grid.store.getAt(rowIndex); // Set timer to trigger long press action longPressTimer = setTimeout(function() { e.preventDefault(); // Block iPad's default long-press menu // Reuse your existing context menu logic here var menu = grid.contextMenu; // Your pre-defined context menu menu.showAt(e.getXY()); // Or fire the rowcontextmenu event directly to reuse existing handlers grid.fireEvent('rowcontextmenu', grid, rowIndex, e); }, 500); } }); // Clear timer if user lifts finger or touch is canceled gridEl.on('touchend', function() { clearTimeout(longPressTimer); }); gridEl.on('touchcancel', function() { clearTimeout(longPressTimer); }); });
Key Notes:
- Use
e.preventDefault()to stop the iPad's default long-press actions (like text selection or link previews). - The
.x-grid3-rowselector is specific to Ext JS 3's grid row elements—make sure it matches your grid's DOM structure.
Approach 2: Create a Reusable Long-Press Utility
If you need to use long-press functionality elsewhere in your app, wrap the touch logic into a utility class for reusability:
Ext.util.LongPress = { // Add long-press listener to any Ext.Element addListener: function(el, callback, delay) { delay = delay || 500; var timer; el.on('touchstart', function(e) { timer = setTimeout(function() { callback.call(this, e); }, delay); }); el.on('touchend touchcancel', function() { clearTimeout(timer); }); } }; // Use it on your grid grid.on('render', function() { Ext.util.LongPress.addListener(grid.getEl(), function(e) { var rowEl = Ext.fly(e.target).findParent('.x-grid3-row', null, true); if (rowEl) { var rowIndex = grid.getView().findRowIndex(rowEl); // Trigger your existing rowcontextmenu handler grid.fireEvent('rowcontextmenu', grid, rowIndex, e); } }, 500); });
Approach 3: Extend GridView for Native Touch Support
For a more "Ext JS-native" solution, extend the GridView class to include long-press handling. This keeps your touch logic encapsulated with the grid component:
Ext.ux.TouchGridView = Ext.extend(Ext.grid.GridView, { initEvents: function() { // Call parent class's event initialization first Ext.ux.TouchGridView.superclass.initEvents.call(this); var longPressTimer; this.el.on('touchstart', function(e, target) { var rowEl = Ext.fly(target).findParent('.x-grid3-row', null, true); if (rowEl) { var rowIndex = this.findRowIndex(rowEl); longPressTimer = setTimeout(function() { e.preventDefault(); // Fire the rowcontextmenu event to reuse existing code this.grid.fireEvent('rowcontextmenu', this.grid, rowIndex, e); }.bind(this), 500); } }, this); this.el.on('touchend touchcancel', function() { clearTimeout(longPressTimer); }, this); } }); // Use the custom view when creating your grid var grid = new Ext.grid.GridPanel({ view: new Ext.ux.TouchGridView(), // Your other grid configs (store, columns, contextMenu, etc.) });
Why Your jQuery Plugin Didn't Work
Ext JS 3 uses its own wrapped element system (Ext.Element) and event handling layer. When you bind events directly with jQuery, it can conflict with Ext's event propagation or timing—leading to the plugin not triggering correctly. Using Ext's native event binding ensures compatibility with the framework's lifecycle.
Pick the approach that fits your codebase best: if you need a quick fix, go with Approach 1. If you want something clean and reusable across your app, Approach 3 is the way to go. All of these should trigger your existing rowcontextmenu logic, so you don't have to rewrite your menu handling code!
内容的提问来源于stack exchange,提问作者Jaydeep

