资讯详情

Ext JS 7.8 入门实战:环境搭建到 Grid、图表与表单落地

📅 2026/10/28 4:12:58 | 华诺云谱 👁 阅读
Ext JS 7.8 入门实战:环境搭建到 Grid、图表与表单落地
简介《Sencha Ext JS 7.8入门指南》是一份面向具备JavaScript基础、希望构建企业级复杂前端应用开发者的PDF教程聚焦Ext JS 7.8的安装、项目创建与组件实践。内容从框架特点与工具包讲起覆盖试用与商业许可证、Sencha Command安装、npm环境管理、IDE选择及项目文件结构并延伸到基础模板中的导航编辑、视图和组件使用。读者可借助数据网格、柱状图、表单捕获等示例理解MVC架构下的组件组织与数据可视化实现文档还提供代码示例、操作步骤以及官方文档、视频教程和社区资源指引便于结合实际项目调试优化。资源包共1个PDF文件约2.65MB结构紧凑便于查阅目前已有196人学习适合前端开发者快速上手并系统梳理Ext JS核心概念也为团队评估企业级前端方案提供入门参考。1. 从装到跑通一份 60 页的 Ext JS 7.8 入门手册能省掉哪些试错做前端开发的人第一次碰到 Sencha Ext JS十有八九会先问一句这东西还用 JavaScript 写吗。答案是不光用而且是用类的方式写视图靠声明式配置堆出来跟现在流行的函数组件思路几乎是两个方向。这份《First Steps with Sencha Ext JS 7.8》入门手册六十来页从装 Sencha Command、跑 generate 命令一路写到数据网格、柱状图和录入表单三个能点的视图中间夹着 MVC 分层怎么落、Ext.define和Ext.create什么时候用哪个。适合有一定 JavaScript 底子、要接手或新建企业级后台的开发者如果手上的活只是一个活动页或者轻量管理台扛这套框架反而是负担。2. 环境与 toolkit 选型Classic 和 Modern 到底该选哪个Ext JS 7.8 最容易让人在第一步就卡住的地方不是安装包而是选错 toolkit。两个 toolkit 共享同一套核心类系统但渲染机制和组件成熟度差别不小一旦在项目跑到一半才发现表格能力不够用改起来是全量返工。这一章先把选型判据讲清楚再把安装环节里几个容易被忽略的勾选项说透。2.1 两个 toolkit 的渲染差异与选型判据官方的定位是Modern Toolkit 主要以 CSS 渲染视图针对平板、手机这类触摸设备做了优化Classic Toolkit 主要以 JavaScript 构建组件针对桌面浏览器上的 Web 应用做了优化。这句描述里最容易被误读的是针对两个字——两者都能跨平台跑Classic 不是只能跑桌面Modern 也不是只能跑手机真正的分水岭是你项目里最重的那个页面长什么样。我一般按下面这张表做初判重点看第三行和第四行维度Classic ToolkitModern Toolkit渲染方式以 JavaScript 构建组件 DOM桌面端事件模型成熟以 CSS 为主渲染视图触摸手势与响应式更顺典型场景桌面后台、密集表格、多窗口、树形权限平板/手机端、卡片式布局、触屏操作Grid 能力锁定列、分组、行编辑、拖拽列等能力更完整复杂表格需要自己组合扩展部分特性缺失组件命名类名与 xtype 与 Modern 存在差异核心类共享同上跨 toolkit 迁移不是零成本学习曲线配置项多组件文档厚排查靠文档和源码更接近现代响应式思维但社区示例相对少判断逻辑很直接项目里有没有超过 30 列、需要锁定列或者行内编辑的表格。如果有直接上 Classic不要在 Modern 上折腾替代方案。反过来如果交付目标是移动端优先、页面以卡片和列表为主Classic 的组件堆出来会显得笨重包体积也不划算。这份手册本身也是以 Classic Toolkit 为主线写的作者在前言里明确说了部分类名在两个 toolkit 之间有差异但底层逻辑一致。这句话的意思是你在 Classic 里学到的 MVC 分层、Store 数据流、视图声明方式换到 Modern 依然成立只是xtype和个别配置项要查一下对应的类。所以入门阶段跟着一条线走通比两边都浅尝一遍更划算。还有一个实操层面的细节生成项目时 toolkit 是作为第一个位置参数传进去的写死了就定了后期想换基本等于新建项目。所以sencha generate app classic -ext MyApp ./这条命令敲下去之前选型应该已经拍板了而不是边写边试。2.2 Sencha Command 安装安装器里哪些组件不用勾Sencha Command 是整套工具链的入口创建、构建、压缩、测试全靠它。安装流程本身不复杂但有三个地方容易出问题。第一步是拿到安装包。试用版走评估页填信息后下载下载区里通常还会列出 Architect、Themer、Rapid Ext JS 这些配套工具入门阶段只需要 Command 一个其余的先放着等真需要可视化编辑或者主题定制再回来拿。第二步是解压并运行安装器。Windows 上大概率会弹 Microsoft Defender 的拦截提示原因是安装包没有大规模签名分发点仍要运行继续就行这是常态不是异常。第三步是安装组件选择界面。这里有一个明确的坑Compass 扩展不用勾。Compass 是早期版本用来编译 Sass 的扩展7.8 的构建链已经不需要它勾上之后反而可能因为找不到 Ruby 环境而在构建阶段报一堆无关错误。第一次装的人看到扩展两个字总觉得多勾点没坏处实际是给自己埋雷。装完之后必须新开一个终端窗口再验证因为 PATH 是在安装时写入系统环境变量的已经开着的 PowerShell 读不到更新后的值# 新开一个 PowerShell 窗口执行别在旧窗口里试 sencha -v # 如果上面报不是内部或外部命令先确认 PATH 里有没有 Cmd 的 bin 目录 echo $env:Path # 实在不行就用绝对路径调用先让流程跑起来再回头修 PATH C:\Program Files\Sencha\Cmd\7.x\sencha.exe -v这三行命令的逻辑是先用最轻的方式确认命令可用不可用时打印 PATH 看安装路径有没有进去最后用绝对路径兜底保证不影响后续的项目生成。参数上没有什么需要调的-v就是打印版本号。如果版本号能出来但sencha generate app报错那问题就不在安装而在后面的项目路径或者授权状态。2.3 npm 管理环境的适用边界除了装全局 Cmd7.8 也支持用 npm 来管理环境。这条路适合两类团队一是构建机是容器化的不希望镜像里塞一个全局安装器二是项目要锁版本希望 Cmd 的版本跟着仓库走而不是跟着开发机走。常见做法是在项目根目录初始化包管理把 Cmd 和框架依赖写进devDependencies然后通过npx调用本地版本避免和全局版本打架# 1. 确认 Node 版本7.8 的构建链在 12.x 以上比较稳 node -v npm -v # 2. 初始化包管理生成 package.json npm init -y # 3. 把发布渠道给出的 Cmd 包写进 devDependencies 后安装 npm install # 4. 用 npx 调本地版本验证是否可用 npx sencha -v逻辑说明npx会优先在node_modules/.bin里找可执行文件找不到才回落到全局所以只要本地装了团队里所有人跑的都是同一个版本。参数上唯一要注意的是不要把包名凭记忆手敲不同发布渠道的包名可能有出入照着渠道页面上的写法抄不然会卡在404 Not Found上浪费时间。需要提醒的是npm 方式并不改变 Cmd 的行为它只是换了个安装位置。项目生成、构建、watch 的命令完全一致所以入门阶段先用全局安装把流程跑通等团队要上 CI 了再切 npm 也不迟不用一上来就两条路都折腾。2.4 试用与商业两条授权路径对生成命令的影响手册把项目创建拆成了两章试用授权项目和商业授权项目。这两条路径在生成项目这一步的差别主要落在可用模板的数量上。试用版走默认模板就够跑通后续所有示例生成命令很朴素一个 toolkit 参数加应用名和输出目录就完事。商业版在激活之后sencha generate app会多出若干预置模板可选适合快速起一个带侧边导航和仪表盘骨架的项目。模板清单别靠猜直接用帮助命令看当前环境里到底注册了哪些# 打印 generate app 的全部参数与可用模板比翻文档快 sencha generate app --help # 指定模板生成模板名以上面命令的输出为准 sencha generate app -t 模板名 -ext MyApp ./这里的关键是--help的输出就是当前这台机器上的真实状态它同时反映了 Cmd 版本、授权状态和已安装的模板包。很多人对着旧文档里的模板名敲命令报模板不存在其实不是命令写错了是授权方式或者版本对不上。养成先看 help 再敲命令的习惯能省掉一半的无效搜索。3. 项目骨架sencha generate app 一条命令产出的目录怎么读生成项目这条命令只有一行但它产出的目录结构决定了后面所有代码往哪放。我见过不少人把视图写在app/view下把 store 写在classic/src里最后构建时一部分类加载不到控制台报Unable to load class排查半天才发现是路径和命名空间对不上。这一章把生成命令的参数、目录职责和导航改造讲清楚。3.1 生成命令的参数拆解手册里给的示例命令是# 在项目文件夹内执行生成一个使用 Classic Toolkit 的应用 sencha generate app classic -ext MyApp ./拆开看四个部分。classic是 toolkit 类型决定用哪套组件库另一可选值是modern。-ext表示使用已安装的 Ext JS SDK 来生成应用而不是从 workspace 里的本地包解析入门阶段没有多项目共享的需求加这个参数最省事。MyApp是应用名必须符合 JavaScript 标识符规则不能带空格、不能以数字开头而且它会同时作为顶层命名空间后面所有类都长成MyApp.view.xxx这个样子。./是输出目录相对当前路径。一个反直觉的点应用名一旦定下来改名成本很高。它不只是个标签会出现在app.json、类名前缀、构建产物目录名里。所以敲命令之前先把名字想好别用test、demo这种临时名字后面要么忍着要么重建。命令执行完之后还不能直接打开页面必须先构建一次因为generate只生成源码骨架编译后的 CSS 和 bootstrap 文件要构建阶段才产出# 进入应用目录 cd MyApp # 首次构建产出开发环境可用的资源和 bootstrap sencha app build development # 开发期用 watch改完源码刷新浏览器即可不用反复 build sencha app watchsencha app build接受三个环境参数development保留可读源码带 source map适合日常开发testing会做压缩但保留一定的调试信息production做完整压缩和混淆产物直接可部署。刚生成完的项目如果跳过 build 直接开浏览器看到的是一片白这不是代码写错了是资源还没生成——这个坑在第 5 章还会再展开。3.2 目录结构与构建产物位置生成之后的项目结构大致如下重点是搞清楚哪些目录是手写的、哪些是构建出来的、哪些绝对不该手改路径作用要不要手改app/跨 toolkit 共享的模型、store、工具类要业务逻辑放这app/view/共享视图类不依赖特定 toolkit 的部分要classic/src/view/Classic 专属视图如主框架、导航要示例里的视图多在这里classic/sass/主题变量与自定义样式要但先改变量别直接覆盖resources/图片、字体等静态资源要build/构建产物按环境分子目录不要每次构建会覆盖index.html入口页引用构建后的 bootstrap一般不动app.json应用级配置包依赖、构建选项都在这要加 charts、filters 等包时改这里bootstrap.js类加载器引导文件构建生成不要手改这张表里最值得记住的是app.json。后面要加图表功能得在这里的requires里显式声明charts包否则图表类加载不到。同理表格的筛选特性也要在这里引入。很多人习惯在代码里Ext.require临时解决能跑起来但构建时会被摇树逻辑漏掉还是得回到app.json里补。build/目录下的产物按环境分build/development/MyApp/、build/testing/MyApp/、build/production/MyApp/。排查线上空白但本地正常这类问题时第一件事就是去对应的产物目录里看index.html引用的 JS 文件是不是存在、路径是不是对得上比在源码里瞎猜快得多。3.3 改导航在 Main 视图里加菜单项生成出来的默认模板带一个侧边导航加中央内容区的骨架三个示例视图要挂进去改的就是这个骨架。典型写法是在主视图里用一个treelist做导航内容区放一个tabpanel两者通过reference和lookup建立联系// classic/src/view/main/Main.js Ext.define(MyApp.view.main.Main, { extend: Ext.panel.Panel, xtype: app-main, controller: main, layout: border, // 边界布局西侧导航 中央内容 items: [{ region: west, xtype: treelist, width: 200, reference: navigation, // 控制器里用 lookup(navigation) 拿到 store: { root: { expanded: true, children: [ { text: 数据网格, leaf: true, xtype: gridview }, { text: 柱状图, leaf: true, xtype: examplechart }, { text: 录入表单, leaf: true, xtype: captureform } ] } } }, { region: center, xtype: tabpanel, reference: mainCardPanel, items: [] }] });这段配置的逻辑是layout: border把面板切成东西南北中五块这里只用了西和中央两块treelist的每个叶子节点上挂了一个xtype作为点这个节点该打开哪个视图的元数据reference是给控制器用的句柄不用自己维护组件 ID。配套的控制器负责在节点被选中时往中央区域加标签页// classic/src/view/main/MainController.js Ext.define(MyApp.view.main.MainController, { extend: Ext.app.ViewController, alias: controller.main, onNavigationSelect: function (tree, node) { var xtype node.get(xtype); // 从节点上取元数据 if (!xtype) { return; } // 非叶子节点直接忽略 var cardPanel this.lookup(mainCardPanel); var existing cardPanel.down(component[xtype xtype ]); if (existing) { // 已打开过就切过去避免重复创建 cardPanel.setActiveTab(existing); return; } cardPanel.add({ xtype: xtype, closable: true }); } });参数说明node.get(xtype)读的是节点自定义字段treelist允许在节点数据里塞任意键这里借它做路由。this.lookup(mainCardPanel)依赖前面配置的reference名字两处必须一致拼错不会报错只会返回null然后下一行就抛Cannot read property down of null这是很典型的静默失败。还有一个容易忘的收尾控制器里的方法要真正被调用得在视图上绑定事件。treelist的选中事件是selectionchange在Main.js的listeners里加上{ selectionchange: onNavigationSelect }才算接通。事件名拼错的话页面能渲染、点击没反应、控制台干净属于最难查的一类问题。4. 视图与组件Ext.define 到 Grid、Chart、Form 的三条落地链路手册的第三章到第五章是三个完整视图数据网格、柱状图、录入表单。它们分别对应 Ext JS 三条最常见的技术链路——数据展示、数据可视化、数据录入。这一章把三条链路拆开每条都落到可抄的配置上同时说清楚为什么这么配。4.1 Ext.define 与 Ext.create 的分界这两个方法经常被混着用但它们干的是完全不同的事。Ext.define是向类系统注册一个类注册本身不产生实例也不创建任何 DOMExt.create是拿一个已注册的类名去实例化每次调用返回一个新对象。手册专门用一节讲这个对比原因是 Ext JS 的类系统是懒加载的define只是登记真正加载脚本发生在第一次被引用的时候。// 声明类注册到 MyApp 命名空间下此时还没有任何 DOM Ext.define(MyApp.view.main.GridView, { extend: Ext.grid.Panel, xtype: gridview, // 给延迟创建留的别名 title: 数据网格 }); // 运行时实例化每次调用都是独立对象配置会与类默认值合并 var grid Ext.create(MyApp.view.main.GridView, { title: 运行时覆盖的标题 // 覆盖 define 里的默认配置 }); // 更常见的写法交给 xtype由容器在渲染时按需创建 var another Ext.widget(gridview);逻辑说明Ext.create的第二个参数是实例级配置会和类定义里的配置做深合并数组类型按下标覆盖对象类型递归合并。这意味着在create里传columns会整体替换掉类里定义的列而不是追加——这一点在动态改列的时候经常翻车。Ext.widget(gridview)和Ext.create(MyApp.view.main.GridView)效果一样前者靠xtype别名查找后者靠全类名写视图内部代码时用xtype更解耦。至于重复define同名类不同版本表现不一致有的覆盖有的告警稳妥做法是改配置不要改定义实在要换实现就换个类名。4.2 Data GridStore 字段与列定义对齐Grid 的核心是 Store 和列定义的字段映射写错一个dataIndex就是整列空白。先看 Store// app/store/ExampleStore.js Ext.define(MyApp.store.ExampleStore, { extend: Ext.data.Store, alias: store.examplestore, // 对应配置里的 { type: examplestore } fields: [ { name: id, type: int }, { name: name, type: string }, { name: value, type: float }, { name: date, type: date, dateFormat: Y-m-d } // Ext 的格式串 ], data: [ { id: 1, name: 条目 A, value: 12.5, date: 2025-01-08 }, { id: 2, name: 条目 B, value: 30.2, date: 2025-01-09 } ], proxy: { type: memory } // 本地数据接后端换成 ajax url });参数说明三处。fields里的type不是装饰它决定了排序、筛选、聚合的行为value写成string的话按字符串排序9会排在10后面。dateFormat用的是 Ext 自己的格式串Y是四位年、m是两位月、d是两位日和常见日期库的YYYY-MM-DD写法不同照搬会解析成Invalid Date。proxy用memory表示不请求后端接真实接口时换成ajax并配urlStore 的其余部分不用动。Grid 视图// classic/src/view/main/GridView.js Ext.define(MyApp.view.main.GridView, { extend: Ext.grid.Panel, xtype: gridview, title: 数据网格, store: { type: examplestore }, // 按别名取 store不用手动 new columnLines: true, selModel: rowmodel, // 行选择需要多选换 checkboxmodel columns: [ { text: #, dataIndex: id, width: 70 }, { text: 名称, dataIndex: name, flex: 1, filter: string }, { text: 数值, dataIndex: value, flex: 1, filter: number, renderer: function (v) { // 只影响显示不影响底层值排序仍按原始数字 return Ext.util.Format.number(v, 0,000.00); } }, { text: 日期, dataIndex: date, width: 120, xtype: datecolumn, format: Y-m-d } ] });逻辑说明store: { type: examplestore }是简写形式等价于Ext.create(MyApp.store.ExampleStore)后赋给store区别在于这种写法会在渲染时才创建。flex: 1和width同时给以flex优先建议列宽要么全用flex均分要么全用width固定混着写在不同分辨率下容易错位。renderer是纯展示层返回值只影响单元格文本filter: number走的是 Store 里的原始值这两者不能互相替代。筛选器那一列配置了filter: number但光配这个不会出现筛选图标必须在app.json的requires里引入Ext.grid.filters包。这个静默失效是新手最容易踩的一个坑配置全对、表头就是没有漏斗图标也不报错。4.3 Bar Chart坐标轴配置与菜单挂载图表在 Ext JS 7 里是独立包先确认app.json里加了依赖{ requires: [ charts, Ext.grid.filters ] }改完app.json要重新跑一次sencha app build development或者让app watch重启否则依赖不会生效。数据部分和 Grid 一样的思路单独建一个 ChartStore// app/store/ChartStore.js Ext.define(MyApp.store.ChartStore, { extend: Ext.data.Store, alias: store.chartstore, fields: [ { name: month, type: string }, // 类目轴字段 { name: value, type: float } // 数值轴字段 ], data: [ { month: 1 月, value: 120 }, { month: 2 月, value: 186 }, { month: 3 月, value: 152 }, { month: 4 月, value: 240 } ] });图表类本身// classic/src/view/chart/ExampleChart.js Ext.define(MyApp.view.chart.ExampleChart, { extend: Ext.chart.CartesianChart, xtype: examplechart, title: 月度数据, store: { type: chartstore }, insetPadding: 20, // 内边距给轴标签留空间 axes: [{ type: numeric, position: left, fields: [value], // 必须与 series 的 yField 同名 title: { text: 数量 }, grid: true // 横向网格线 }, { type: category, position: bottom, fields: [month] // 必须与 xField 同名 }], series: [{ type: bar, xField: month, yField: value, style: { fill: #3d7eff, minGapWidth: 8 }, label: { field: value, display: insideEnd } }] });参数说明axes[].fields和series里的xField/yField必须是 Store 里真实存在的字段名写错不报错只是图上什么都没有。position决定轴在哪个边类目轴一般放bottom数值轴放left。grid: true只是画网格线跟 Grid 组件没关系别混淆。往导航里挂的时候在Main.js的treelist节点上加{ text: 柱状图, leaf: true, xtype: examplechart }就行第 3 章的控制器会自动按xtype打开。必须注意容器高度图表的尺寸来自父容器如果中央区域是tabpanel且没有给layout: fit或者固定高度图表会渲染成一个 0 高度的空壳DOM 里有节点、控制台没报错、屏幕上什么都看不见。这是图表类问题里出现频率最高的一种。4.4 Capture FormView 与 Controller 的职责划分表单是三个视图里唯一强依赖控制器的。视图负责字段和校验规则控制器负责取值和提交两者通过controller配置和handler字符串绑定// classic/src/view/form/CaptureForm.js Ext.define(MyApp.view.form.CaptureForm, { extend: Ext.form.Panel, xtype: captureform, controller: captureform, // 绑定控制器别名 title: 信息录入, bodyPadding: 16, layout: { type: vbox, align: stretch }, defaults: { // 所有子字段的公共配置 xtype: textfield, labelWidth: 90, margin: 0 0 12 0 }, items: [ { fieldLabel: 名称, name: name, allowBlank: false }, { fieldLabel: 数量, name: qty, xtype: numberfield, minValue: 1, value: 1 }, { fieldLabel: 日期, name: date, xtype: datefield, format: Y-m-d }, { fieldLabel: 备注, name: remark, xtype: textareafield, grow: true } ], buttons: [ { text: 重置, handler: onReset }, { text: 提交, formBind: true, handler: onSubmit } // 校验不通过时自动禁用 ] });参数说明defaults里的配置会下发给所有items字段自己写的同名配置优先这样能省掉大量重复。每个字段的name是取值时的键不写name的字段getValues()拿不到这是表单取值为空的第一大原因。formBind: true让按钮跟随表单校验状态名称没填时提交按钮是灰的属于零成本提升体验的配置。控制器// classic/src/view/form/CaptureFormController.js Ext.define(MyApp.view.form.CaptureFormController, { extend: Ext.app.ViewController, alias: controller.captureform, onSubmit: function () { var form this.getView().getForm(); // Panel 上先 getForm 才是 Form 实例 if (!form.isValid()) { return; } // 双保险formBind 之外再挡一次 var values form.getValues(); // 一次拿全部字段别逐个 lookup console.log(values); Ext.Msg.alert(已提交, Ext.encode(values)); form.reset(); // 还原到字段的初始值 }, onReset: function () { this.getView().getForm().reset(); } });逻辑说明this.getView()返回的是Ext.form.Panel它本身没有getValues方法必须先getForm()拿到Ext.form.Basic实例再调。这一步混淆导致getValues is not a function的报错非常常见。form.getValues()返回的是纯对象键就是字段的name未渲染或隐藏的字段默认不包含在内需要包含的话传参form.getValues(true)。form.reset()是恢复到字段的初始值而不是清空value: 1的字段重置后还是 1。5. 排查清单五类高频翻车现场与定位顺序Ext JS 的报错风格是要么不说话要么一次说一堆。很多问题在控制台里连红字都没有只是页面不动所以排查顺序比排查技巧更重要。这一章按我实际踩过的顺序列五条每条都按现象、原因、解决三段写。5.1 命令不可用与首屏空白现象新开的终端里敲sencha -v提示不是内部或外部命令或者命令能用但生成完项目打开浏览器一片白。原因前者是安装时写入的 PATH 没有被当前终端读到老窗口不会自动刷新环境变量。后者是跳过了构建步骤——sencha generate app只生成源码骨架bootstrap.js和编译后的 CSS 是sencha app build阶段才产出的index.html引用的恰恰是构建产物所以直接双击打开必然是白的。解决命令问题换新终端仍不行就查 PATH 或用绝对路径调用先让流程能走。白屏问题先跑一次sencha app build development再用sencha app watch起本地服务访问不要用file://协议直接开 HTML——部分资源请求在文件协议下会被浏览器拦掉表现同样是白屏容易和构建问题混在一起。5.2 Grid 有行无值、Chart 不出图现象Grid 渲染出了表头和行数但每个单元格都是空的或者 Chart 区域有边框有标题里面什么都没有。原因Grid 这边九成是dataIndex和 Store 的fields.name对不上或者 Store 用了model配置却把字段定义在 Store 的fields里两套字段定义互相覆盖。Chart 这边通常是父容器高度塌陷图表按 100% 撑开父容器父容器本身高度是 0结果就是 0。解决Grid 先在控制台打印grid.getStore().first().getData()看拿到的是不是预期字段名再回头核对列配置字段定义只在model或fields里写一份。Chart 先给图表类加一个明确的height: 320能出来就说明是布局问题再回头给父容器加layout: fit用布局解决而不是硬写高度。还有一个连带项Chart 的axes[].fields写错不会报错图和轴都在就是柱子没有高度。核对字段名的时候三个地方一起看——Store 的fields、axes的fields、series的xField/yField。5.3 表单取值为 undefined、feature 静默失效现象表单填了内容控制器里getValues()返回的对象里没有对应键或者 Grid 列上配了filter表头就是不出现筛选图标。原因表单字段漏写namegetValues()是按name收集的没有name的字段直接被跳过。筛选图标不出现是Ext.grid.filters包没在app.json的 requires本文还有配套的精品资源点击获取
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑