Ext表格控件专精(碎片一)_笔记_03
开始表格控件的学习记录..
~Ext的表格控件
表格由类Ext.grid.GridPanel定义,继承自Ext.Panel,其xtype为grid。表格控件必须包含列定义信息,并指定表格的数据存储器。分别通过数组columns和Ext.data.Store定义。
~搭建一个简单的表格
表格是二维的,和数据库中新建表一样,我们要先设置表的列数、每列的名称和类型,以及显示方式。表格的 结构和数据库表的结构类似。
在Ext中,列的定义是一个JSON数组,他是整个表格的列模型应该被首先创建。
下面是一个三列表格,三列分别是编号(id)、名称(name)、描述(descn);
var columns = [{ header: '编号', dataIndex: 'id' }, { header: '名称', dataIndex: 'name' }, { header: '描述', dataIndex: 'descn' }];
columns是一个数组,每一行数据元素描述表格的一列信息,表格的列信息包含首部显示文本(header)、列对应的记录集字段(dataIndex)、列是否可排序(sortable)、列的渲染函数(renderer)、宽度(width)、格式化信息(format)等,上面的例子只用到了header和dataIndex。
这样表格的结构就确定了,之后就是数据的确定了,这里方便起见,书上使用了js定义的数据:
var data = [ ['1', 'name1', 'descn1'], ['2', 'name2', 'descn2'], ['3', 'name3', 'descn3'], ['4', 'name4', 'descn4'], ['5', 'name5', 'descn5'], ];
可以看出来,一共定义了五行数据,且顺序和表格结构是对应的。
接下来,就是转化原始数据,如下:
var store = new Ext.data.ArrayStore({ data: data, fields: [{ name: 'id' }, { name: 'name' }, { name: 'descn' }] }); store.load();
这里创建了一个数据对象,这也是表格必须配置的属性。它的作用就是将各种各样的原始数据(如二维数组、JSON对象数组、XML文本等)转换为Ext.data.Record类型的对象。通过Ext.data.ArrayStore,我们可以将任何格式的数据转换为表格可以使用的形式,这样就不需要为每一种数据都写一种对应的实现方式了。
store包括了proxy和reader。分别是指获得数据的方式,和如何解析这些数据。这里使用的Ext.data.ArrayStore内部会默认通过内存加载JSON数组作为元数据。
数组的解析会按照定义的框架规范进行,与columns对应,这样,grid就知道columns是如何与store中的数据相对应的。 最后,需要使用store.load()来进行初始化数据。若是打乱顺序的话,就需要使用mapping来指定位置了,不过为了方便没必要。
最后的步骤是将前面的零散的配件装配到一起:
var grid1 = new Ext.grid.GridPanel({ autoHeight: true, renderTo: 'grid', store: store, columns: columns });
这里renderTo是渲染的位置,所以在body中要为其指定一个id为grid的容器;

<script> Ext.onReady(function() { var columns = [{ header: '编号', dataIndex: 'id' }, { header: '名称', dataIndex: 'name' }, { header: '描述', dataIndex: 'descn' }]; var data = [ ['1', 'name1', 'descn1'], ['2', 'name2', 'descn2'], ['3', 'name3', 'descn3'], ['4', 'name4', 'descn4'], ['5', 'name5', 'descn5'], ]; var store = new Ext.data.ArrayStore({ data: data, fields: [{ name: 'id' }, { name: 'name' }, { name: 'descn' }] }); store.load(); var grid1 = new Ext.grid.GridPanel({ autoHeight: true, renderTo: 'grid', store: store, columns: columns }); }) </script> <div id="grid"></div>
~常用功能
~一些属性的枚举
属性 | 介绍 | 默认值 | 可选值 |
enableColumnMove | 表格列的拖放,默认是可以拖放的 | true | false |
enableColumnResize | 改变表格的列宽,默认是可以改变的 | true | false |
stripeRows | 斑马线效果,写在viewConfig中,默认是使用 | true | false |
loadMask | 在store.load()过程中为用户显示“Loading”,写在vieConfig中,默认是显示 | true | false |

<script> Ext.onReady(function() { var columns = [{ header: '编号', dataIndex: 'id' }, { header: '名称', dataIndex: 'name' }, { header: '描述', dataIndex: 'descn' }]; var data = [ ['1', 'name1', 'descn1'], ['2', 'name2', 'descn2'], ['3', 'name3', 'descn3'], ['4', 'name4', 'descn4'], ['5', 'name5', 'descn5'], ]; var store = new Ext.data.Store({ proxy: new Ext.data.ScriptTagProxy({ url: 'https://www.cnblogs.com/vegechick/' }), render: new Ext.data.ArrayReader({}, [{ name: 'id' }, { name: 'name' }, { name: 'descn' }]), fields: [{ name: 'id' }, { name: 'name' }, { name: 'descn' }] }); var grid = new Ext.grid.GridPanel({ renderTo: 'grid', width: 350, height: 150, loadMask: true, store: store, columns: columns }); store.load(); }) </script> <div id="grid"></div>
本地读取速度太快,所以看不到加载过程,换成远程的(随机URL)
~自定义列宽
默认情况下columns值为100px。需要自定义宽度可以在columns中加上width属性:
var columns = [{ header: '编号', dataIndex: 'id', width:40 }, { header: '名称', dataIndex: 'name', width:80 }, { header: '描述', dataIndex: 'descn', width:200 }];
使用width手动计算有些麻烦,这时可以使用forceFit属性即可,他将会自动延申。
var grid = new Ext.grid.GridPanel({ renderTo: 'grid', store: store, columns: columns, forceFit: true //在这里设置就好 });
(表格右边有一段空白区,这是为纵向滚动条准备的)
~表格按列排序
在定义模型的时候增加sortable属性即可(默认为true):

<script> Ext.onReady(function() { var columns = [{ header: '编号', dataIndex: 'id', sortable: true //按照序号排列 }, { header: '名称', dataIndex: 'name' }, { header: '描述', dataIndex: 'descn' }]; var data = [ ['1', 'name1', 'descn1'], ['3', 'name3', 'descn3'], ['2', 'name2', 'descn2'], ['4', 'name4', 'descn4'], ['5', 'name5', 'descn5'], ]; var store = new Ext.data.ArrayStore({ data: data, fields: [{ name: 'id' }, { name: 'name' }, { name: 'descn' }] }); var grid = new Ext.grid.GridPanel({ renderTo: 'grid', forceFit: true, store: store, columns: columns }); store.load(); }) </script> <div id="grid"></div>
只需要将需要排序的列添加上sortable就可以了;
对中文进行排序的问题:解决方案是重写Ext.data.Store的createComparator()函数并且将下束代码放在html最上面或者ext-all.js文件的最后,总之就是要确保这段代码要在Ext初始化之后,在实际代码调用之前执行:

Ext.data.Store.prototype.applySort = function() { // 重写函数方法,实现中文排序 if (this.sortInfo && !this.remoteSort) { var s = this.sortInfo, f = s.field; var st = this.fields.get(f).sortType; var fn = function(r1, r2) { var v1 = st(r1.data[f]), v2 = st(r2.data[f]); if (typeof(v1) == "string") { return v1.localeCompare(v2); } return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0); }; this.data.sort(s.direction, fn); if (this.snapshot && this.snapshot != this.data) { this.snapshot.sort(s.direction, fn); } } };
~日期类型数据的处理
首先,定义一组数据:
var data = [ ['1', 'name1', 'descn1', '1970-01-15T02:58:04'], ['3', 'name3', 'descn3', '1970-01-15T02:58:04'], ['2', 'name2', 'descn2', '1970-01-15T02:58:04'], ['4', 'name4', 'descn4', '1970-01-15T02:58:04'], ['5', 'name5', 'descn5', '1970-01-15T02:58:04'], ];
其次,在fields中增加日期的配置,类型type设置为date,按照Ext约定年Y,月m,日d,小时H,分钟i,秒s,来描述得到的日期数据的格式:
var store = new Ext.data.ArrayStore({ data: data, fields: [{ name: 'id' }, { name: 'name' }, { name: 'descn' }, { name: 'date', type: 'date', dateFormat: 'Y-m-dTH:i:s' //读取数据的格式 }] });
最后,在columns中增加一行,renderer属性用来格式化日期数据:
var columns = [{ header: '编号', dataIndex: 'id', sortable: true //按照序号排列 }, { header: '名称', dataIndex: 'name' }, { header: '描述', dataIndex: 'descn' }, { header: '日期', dataIndex: 'date', renderer: Ext.util.Format.dateRenderer('Y-m-d') //想要展示的数据格式 }];
拼起来:

<script> Ext.onReady(function() { var columns = [{ header: '编号', dataIndex: 'id', sortable: true //按照序号排列 }, { header: '名称', dataIndex: 'name' }, { header: '描述', dataIndex: 'descn' }, { header: '日期', dataIndex: 'date', renderer: Ext.util.Format.dateRenderer('Y-m-d') //想要展示的数据格式 }]; var data = [ ['1', 'name1', 'descn1', '1970-01-15T02:58:04'], ['3', 'name3', 'descn3', '1970-01-15T02:58:04'], ['2', 'name2', 'descn2', '1970-01-15T02:58:04'], ['4', 'name4', 'descn4', '1970-01-15T02:58:04'], ['5', 'name5', 'descn5', '1970-01-15T02:58:04'], ]; var store = new Ext.data.ArrayStore({ data: data, fields: [{ name: 'id' }, { name: 'name' }, { name: 'descn' }, { name: 'date', type: 'date', dateFormat: 'Y-m-dTH:i:s' //读取数据的格式 }] }); var grid = new Ext.grid.GridPanel({ renderTo: 'grid', forceFit: true, store: store, columns: columns }); store.load(); }) </script> <div id="grid"></div>
~表格的渲染
一般来说我们可以直接在columns中添加randerer属性,randerer的值是一个自定义函数:

var columns = [{ header: '编号', dataIndex: 'id' }, { header: '性别', dataIndex: 'sex', renderer: function(value) { if (value == 'male') { return "<span style='color:red;font-weight:bold;'>红男</span><img src='../img/male.png' height='20'/>"; } else { return "<span style='color:green;font-weight:bold;'>绿女</span><img src='../img/female.png' height='20'/>"; } } }, { header: '名称', dataIndex: 'name' }, { header: '描述', dataIndex: 'descn' }];
但是这样会看起来很乱,所以可以将函数分开来写:

var columns = [{ header: '编号', dataIndex: 'id' }, { header: '性别', dataIndex: 'sex', renderer: renderSex }, { header: '名称', dataIndex: 'name' }, { header: '描述', dataIndex: 'descn' }]; function renderSex(value) { if (value == 'male') { return "<span style='color:red;font-weight:bold;'>红男</span><img src='../img/male.png' height='20'/>"; } else { return "<span style='color:green;font-weight:bold;'>绿女</span><img src='../img/female.png' height='20'/>"; } }
除了文字和图片的修饰还可以加入弹窗:

<script> Ext.onReady(function() { var columns = [{ header: '编号', dataIndex: 'id' }, { header: '性别', dataIndex: 'sex', renderer: renderSex }, { header: '名称', dataIndex: 'name' }, { header: '描述', dataIndex: 'descn', renderer: renderDescn }]; var data = [ ['1', 'male', 'name1', 'descn1'], ['2', 'female', 'name2', 'descn2'], ['3', 'female', 'name3', 'descn3'], ['4', 'male', 'name4', 'descn4'], ['5', 'male', 'name5', 'descn5'], ]; var store = new Ext.data.ArrayStore({ data: data, fields: [{ name: 'id' }, { name: 'sex' }, { name: 'name' }, { name: 'descn' }] }); store.load(); var grid1 = new Ext.grid.GridPanel({ autoHeight: true, renderTo: 'grid', store: store, columns: columns, forceFit: true }); }) function renderSex(value) { if (value == 'male') { return "<span style='color:red;font-weight:bold;'>红男</span><img src='../img/male.png' height='20'/>"; } else { return "<span style='color:green;font-weight:bold;'>绿女</span><img src='../img/female.png' height='20'/>"; } } function renderDescn(value, cellmeta, record, rowIndex, columnIndex, store) { var str = "<input type='button' value='查看详细信息' onclick='alert(\"" + "这个单元格的值是:" + value + "\\n" + "这个单元格的配置是:{cellId:" + cellmeta.cellId + ",id:" + cellmeta.id + ",css:" + cellmeta.css + "}\\n" + "这个单元格对应行的record是:" + record + ",一行的数据都在里边\\n" + "这是第" + rowIndex + "行\\n" + "这是第" + columnIndex + "列\\n" + "这个表格对应的Ext.data.Store在这里:" + store + ", 随便用吧。" + "\")'>"; return str; } </script> <div id="grid"></div>
函数中有多个参数,意义如下:
value | 将要显示在单元格中的值 |
cellmeta | 单元格相关属性,主要有id和CSS |
record | 这行的数据对象,如果需要其他列的值,可以通过record.data["id"]的方式得到 |
rowIndex | 行号,这里行号就是当前页中所有记录的顺序 |
columnIndex | 当前的列号 |
store | 构造表格时传递的数据源,表格中的所有数据都来自这里 |
~给表格行和列上色
给行添加颜色(这里书上的代码也是有问题的,找了很久~~):
首先,需要在数据源中添加color字段:
var store = new Ext.data.ArrayStore({ data: data, fields: [{ name: 'id' }, { name: 'name' }, { name: 'descn' }, { name: 'color' //添加color字段 }] }); var data = [ ['1', 'name1', 'descn1', '#FBF8BF'],//这里的color的值可以是随便取的,不过需要和grid中对应 ['2', 'name2', 'descn2'],//不写就是'' ['3', 'name3', 'descn3', '#FBF8BF'], ['4', 'name4', 'descn4', '#F5C0C0'], ['5', 'name5', 'descn5', '#99CC99'], ];
接着,就是在grid中添加viewConfig字段:
var grid = new Ext.grid.GridPanel({ autoHeight: true, renderTo: 'grid', store: store, columns: columns, forceFit: true, viewConfig: { stripeRows: false,//关掉斑马线 enableRowBody: true,//开启行体包含 getRowClass: function(record, rowIndex, rowParams, store) { var cls = 'white-row'; console.log(store); switch (record.data.color) { case '#FBF8BF': cls = 'yellow-row' break; case '#99CC99': cls = 'green-row' break; case '#F5C0C0': cls = 'red-row' break; } return cls; }//不管是ext3还是ext4都是在这里通过返回值来改变行色,差异就在于css代码 } });
最后,css代码,使用的是指定类名方式修改,关键点是必须在每一个后面添加.x-grid-cell,否则就不会生效:
.red-row .x-grid-cell { background-color: #F5C0C0 !important; } .yellow-row .x-grid-cell { background-color: #FBF8BF !important; } .green-row .x-grid-cell { background-color: #99CC99 !important; }
完整代码:

//内置css <style type="text/css"> .red-row .x-grid-cell { background-color: #F5C0C0 !important; } .yellow-row .x-grid-cell { background-color: #FBF8BF !important; } .green-row .x-grid-cell { background-color: #99CC99 !important; } </style> //主体 <script> Ext.onReady(function() { var columns = [{ header: '编号', dataIndex: 'id' }, { header: '名称', dataIndex: 'name' }, { header: '描述', dataIndex: 'descn' }]; var data = [ ['1', 'name1', 'descn1', '#FBF8BF'], //这里的color的值可以是随便取的,不过需要和grid中对应 ['2', 'name2', 'descn2'], //不写就是'' ['3', 'name3', 'descn3', '#FBF8BF'], ['4', 'name4', 'descn4', '#F5C0C0'], ['5', 'name5', 'descn5', '#99CC99'], ]; var store = new Ext.data.ArrayStore({ data: data, fields: [{ name: 'id' }, { name: 'name' }, { name: 'descn' }, { name: 'color' //添加color字段 }] }); store.load(); var grid = new Ext.grid.GridPanel({ autoHeight: true, renderTo: 'grid', store: store, columns: columns, forceFit: true, viewConfig: { stripeRows: false, //关掉斑马线 enableRowBody: true, //开启行体包含 getRowClass: function(record, rowIndex, rowParams, store) { var cls = 'white-row'; console.log(store); switch (record.data.color) { case '#FBF8BF': cls = 'yellow-row' break; case '#99CC99': cls = 'green-row' break; case '#F5C0C0': cls = 'red-row' break; } return cls; } //不管是ext3还是ext4都是在这里通过返回值来改变行色,差异就在于css代码 } }); }) </script> <div id="grid"></div>
有行的色变,就会有列的色变,修改代码,注释掉viewConfig,添加一个函数用来控制,列上单元格的色变:
function renderMotif(data, cell, record, rowIndex, columnIndex, store) { var value = record.get('color') cell.style = "background-color:" + value; return data; }
使用renderer显然到任意一列就会显示颜色(我渲染在描述页):
var columns = [{ header: '编号', dataIndex: 'id' }, { header: '名称', dataIndex: 'name' }, { header: '描述', dataIndex: 'descn', renderer: renderMotif }, { header: '颜色', dataIndex: 'color', }];
~显示行号和复选框
显示行号很简单,就是在columns的第一列添加RowNumberer对象,这样最左边就会出现行号:
var columns = [ new Ext.grid.RowNumberer(), { header: '编号', dataIndex: 'id' }, { header: '名称', dataIndex: 'name' }, { header: '描述', dataIndex: 'descn' } ];
crud是经常要处理的操作,这里在进行删除操作的时候,若不进行刷新,就会出现序号的断层,解决方法是(书上的还是不行,想要重置序号,就要在RowNumberer中添加逻辑):
var columns = [ new Ext.grid.RowNumberer({ align: "center", header: '序号', width: 50, renderer: function(value, metaData, record, rowIdx, colIdx, store) { return rowIdx + 1; } }), { header: '编号', align: "center", dataIndex: 'id' }, { header: '名称', align: "center", dataIndex: 'name' }, { header: '描述', align: "center", dataIndex: 'descn' } ];
同时,刷新view视图:
Ext.get('remove').on('click', function() { store.remove(store.getAt(1)); //刷新数据 grid.view.refresh(); });
~添加复选框
创建一个SelectionModel对象,并赋值给grid中的selModel属性;
//创建对象,并配置属性 var sm = new Ext.selection.CheckboxModel({ checkOnly: true, injectCheckbox: 1, //位于哪一列 }); //添加到selModel中 grid = new Ext.grid.GridPanel({ selModel: sm, autoHeight: true, renderTo: 'grid', store: store, columns: columns, forceFit: true, viewConfig: { stripeRows: false }, });
属性中checkOnly赋值为true,可以避免在全选情况下,点击了任一个按钮影响其他按钮从而变为单选的情况。
~选择模型
关于这一节就有点尴尬了,浪费了好多时间,书上的解决方案是将Ext.grid.RowModel()对象直接赋值给sm属性且取消默认的复选是内嵌singleSelect并设置为true,,但是,这样是不行的,首先就是会报错:没有这个对象的构造,其次,sm也没有这个属性,再来就是singleSelect也不对...
书中的代码还是有问题的,Ext4还是要多去看官方文档,经过查看,发现RowModel()不是在grid下,而是在selection下,而sm属性应该是前面使用过的selModel属性,还有里面有一个model可以设置为(single,simple,multi)....
grid = new Ext.grid.GridPanel({ // selModel: sm, autoHeight: true, renderTo: 'grid', store: store, columns: columns, forceFit: true, viewConfig: { stripeRows: false }, selModel: new Ext.selection.RowModel({ //这里使用的这个,在官方文档中查到的 mode: "MULTI" }), });
顺便提一句,书上说默认情况下可以使用Ctrl或者Shift进行多选操作,但是,通过实操会发现默认情况下恰恰相反...
以上就是通过Ctrl 或者Shift进行的多选啦(其实Ctrl和Shift也有点区别,动手就发现了,simple和multi的区别也是一样)

<script> Ext.onReady(function() { // var sm = new Ext.selection.CheckboxModel({ // checkOnly: true, // injectCheckbox: 1, //位于哪一列 // }); var columns = [ new Ext.grid.RowNumberer({ align: "center", header: '序号', width: 50, renderer: function(value, metaData, record, rowIdx, colIdx, store) { return rowIdx + 1; } }), { header: '编号', align: "center", dataIndex: 'id' }, { header: '名称', align: "center", dataIndex: 'name' }, { header: '描述', align: "center", dataIndex: 'descn' } ]; var data = [ ['1', 'name1', 'descn1', '#eba367'], // ['2', 'name2', 'descn2'], ['3', 'name3', 'descn3', '#FBF6EE'], ['4', 'name4', 'descn4', '#67b0eb'], ['5', 'name5', 'descn5', '#b0eb67'], ]; var store = new Ext.data.ArrayStore({ data: data, fields: [{ name: 'id' }, { name: 'name' }, { name: 'descn' }, { name: 'color' //添加color字段 }] }); store.load(); grid = new Ext.grid.GridPanel({ // selModel: sm, autoHeight: true, renderTo: 'grid', store: store, columns: columns, forceFit: true, viewConfig: { stripeRows: false }, selModel: new Ext.selection.RowModel({ //这里使用的这个,在官方文档中查到的 mode: "multi" }), }); Ext.get('remove').on('click', function() { store.remove(store.getAt(1)); // console.log(grid.getView()) //grid.store.reload(); //刷新数据 grid.view.refresh(); }); }) </script> <div id="grid"></div> <button id="remove">删除第二行</button>
同样使用单元格选中就将new Ext.selection.RowModel()更改为new Ext.selection.CellModel()即可;
模型可以配合剪辑时间进行监听和数据读取操作,添加函数如下:
grid.on('itemclick', function() { var selected = grid.getSelectionModel().selected; for (var i = 0; i < selected.getCount(); i++) { var record = selected.get(i); Ext.Msg.alert('提示', record.get('id') + "," + record.get("name") + "," + record.get("descn")); } });
其中,selected.getCount()是选中的记录条数,selected中每一个元素都是一条记录,所有的数据都存储在其中。判断有没有数据只需要看selected.getCount()是否等于0即可。
~表格视图
Ext的表格控件都遵循MVC模型,Ext.data.Store可看作模型(Model),Ext.grid.GridPanel中设置的各种监听器可以看作控制器(Controller),而Ext.grid.GridView对应的就是视图(View)。通常情况下,不需要自行创建Ext.grid.GridView实例,因为Ext.grid.GridPanel会自动生成对应的实例,并使用默认的样式在页面显示出来。操作Ext.grid.GridView可以通过Ext.grid.GridPanel的getView()函数来获取当前表格使用的视图案例。
与GridView相关的操作都集中在视图部分。如果要将表格显示效果进行调整,可以通过GridView进行设置,不过必须要在建立了Ext.grid.GridPanel之后调用,他只能获得Ext.grid.GridPanel中创建好的GridView实例,初始参数参考文档配置,书中是viewConfig这个可能和版本有关系,在4.2中配置仿佛没有生效。
~表格分页
一次性将成千上万的数据显示在表格中,不是好主意,严重影响效率。而表格控件对性能的要求较高,在一个页面中放三个表格就会感觉到响应明显变慢,那么子啊一个表格中显示上千条数据,效率可想而知。
添加分页工具条:
bbar: new Ext.PagingToolbar({ store: store, //分页的数据源 // pageSize: 2, //每页显示数据为2条,这里也应该是版本的问题,4.2版本中pageSize在store中 displayInfo: true, //是否显示数据信息 displayMsg: '显示第{0}条到{1}条记录,一共{2}条', //只有当displayInfo 为true 的时候才有效,用来显示数据的提示信息,{}内的数字将会被替换为对应的数据,不过取值只能是0,1,2 emptyMsg: "没有记录" //没有数据显示的信息 })
这里就是在表格尾部的位置添加分页控件的代码了。

<script> Ext.onReady(function() { var itemsPerPage = 2; store = new Ext.data.ArrayStore({ data: [ ['1', 'name1', 'descn1'], ['2', 'name2', 'descn2'], ['3', 'name3', 'descn3'], ['4', 'name4', 'descn4'], ['5', 'name5', 'descn5'] ], fields: [{ name: 'id' }, { name: 'name' }, { name: 'descn' }], autoLoad: true, pageSize: itemsPerPage, }), store.load({ params: { start: 0, limit: itemsPerPage } }); grid = new Ext.grid.GridPanel({ autoHeight: true, renderTo: 'grid', store: store, columns: [{ header: '编号', dataIndex: 'id', sortable: true //按照序号排列 }, { header: '名称', dataIndex: 'name' }, { header: '描述', dataIndex: 'descn' }], forceFit: true, bbar: new Ext.PagingToolbar({ store: store, //分页的数据源 // pageSize: 2, //每页显示数据为2条,这里也应该是版本的问题,4.2版本中pageSize在store中 displayInfo: true, //是否显示数据信息 displayMsg: '显示第{0}条到{1}条记录,一共{2}条', //只有当displayInfo 为true 的时候才有效,用来显示数据的提示信息,{}内的数字将会被替换为对应的数据,不过取值只能是0,1,2 emptyMsg: "没有记录" //没有数据显示的信息 }) }); }) </script> <div id="grid"></div>
这段代码有点问题,不知道和内置数据有没有关系,基本上找不到内置数据的分页,都是从数据库中拿的,还有就是ext4中将pageSize属性从pageToolbar中移除了,而是将数据添加到了store中,所以书上的配置也没用...
~注意:
1、如果需要配置分页工具条,store.load()就必须在构造表格之后执行,否则,工具条就不会起作用。应该将分页工具条和store相关联,从而实现和表格共享数据模型(store是必填项...)。
2、此处的store不能使用Ext.data.SimpleStore,分页时需要调用的load()函数,而load(()函数和proxy有关。SimpleStore不但没有设置proxy,而且没有重写load()函数,所以会出现错误,从而导致无法显示分页信息。
~通过后台脚本获得分页数据
尴尬,这里给出解释。
表格无法显示store中所有的数据,我们无法利用静态数据很好的显示分页,所以,必须写后台脚本,让Ext与后台数据进行交互,这样才能看到真实的分页效果。
以下是对100条数据进行分页,在获得了start和limit之后生成数据。
推荐可以先使用下面这个测试一下,利用json在线检测工具解析一下拼写的有没有问题(这也是书上后台给出的源码):

代码中先接收前端传递的两个参数:start和limit。start是从第几个数据开始显示,limit是从start开始一共有多少条数据。之后,利用循环生成数据并包装为json格式返回前端。
在IDEA上弄一下服务器,我这里的是Tomcat,发请求(这一步会给自己挖坑):
http://localhost:8080/Extjs4Test_war/ext01.jsp?start=1&limit=201
返回数据如下:
以下才是经历了九九八十一难后获得的可用的后台源码...
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <% String start = request.getParameter("start"); String limit = request.getParameter("limit"); boolean jsonP = false; String cb = request.getParameter("callback"); if (cb != null) { jsonP = true; response.setContentType("text/javascript"); } else { response.setContentType("application/x-json"); } if(jsonP){ response.getWriter().write(cb+"("); } try{ int index = Integer.parseInt(start); int pageSize = Integer.parseInt(limit); String json = "{\"totalProperty\":100,\"root\":["; for(int i = index; i < pageSize+index; i++){ json += "{\"id\":"+i + ",\"name\":\"name"+ i +"\",\"descn\":\"descn"+i+"\"}"; if(i != pageSize+index - 1){ json += ","; } } json+= "]}"; response.getWriter().write(json); if(jsonP){ response.getWriter().write(");"); } }catch(Exception ex){ } %>
(代码来之不易,说白了就是换成jsonp格式,在数据的前后用callback()包裹住,大概方便Ext自动解析吧...,找了好多资料,因为我的和书上不一样,使用了IDEA和VSCode涉及到了跨域,所以就不能按照书上的来了,总之,官方文档才是yyds。)
ext不用关心后台是啥,只要返回格式是json就可以处理。
接下来对前端代码进行修改:
<script> Ext.onReady(function() { Ext.define("goods", { extend: 'Ext.data.Model', fields: [{ name: 'id' }, { name: 'name' }, { name: 'descn' }], }); //每页条数 var itemsPerPage = 10; store = Ext.create('Ext.data.Store', { //这里换一个,换成新的创建对象的方式 model: 'goods', proxy: { type: 'jsonp', //Ajax,jsonP,Rest,Direct //浏览器禁止了ajax的跨域请求(官方文档) url: 'http://localhost:8080/Extjs4Test_war/ext01.jsp', //解码服务器相应的数据 reader: { type: 'json', totalProperty: 'totalProperty', //对应着json中的totalProperty,就是数据总数的属性名称,在需要分页时才会用到 root: 'root', //对应着json中的root数组,就是数据项的属性名称 idProperty: 'id', //就是标识符行对象的属性名称,默认值是id,也可以指定 callbackKey: 'callback' } }, // autoLoad: true, pageSize: itemsPerPage, }), store.load({ params: { start: 1, limit: itemsPerPage } }); console.log(store.proxy.reader); grid = Ext.create('Ext.grid.Panel', { autoHeight: true, renderTo: 'grid', store: store, columns: [{ header: '编号', dataIndex: 'id', sortable: true //按照序号排列 }, { header: '名称', dataIndex: 'name' }, { header: '描述', dataIndex: 'descn' }], forceFit: true, bbar: new Ext.PagingToolbar({ store: store, //分页的数据源 // pageSize: 2, //每页显示数据为2条,这里也应该是版本的问题,4.2版本中pageSize在store中 displayInfo: true, //是否显示数据信息 displayMsg: '显示第{0}条到{1}条记录,一共{2}条', //只有当displayInfo 为true 的时候才有效,用来显示数据的提示信息,{}内的数字将会被替换为对应的数据,不过取值只能是0,1,2 emptyMsg: "没有记录" //没有数据显示的信息 }) }); }) </script>
ajax是不满足跨域的,书上的就不行..Ext提供了专门的jsonp格式满足跨域需求,大致的都可以从官方文档中找到解释。
好的,继续...
~分页工具条显示在表格的顶部
额。。
将bbar换成tbar就是显示在表格的顶部。
~让Ext支持前台分页
这里明确给出了前面的问题的解释:前台分页一次性会将所有的数据都读取到客户端,有利于小数据量的分页,不过Ext没有这种功能,他只会一次性将所有的数据都显示到表格中,无论pageSize设置为多少都没有用。
但是,凡事无绝对,虽然不能直接为我们提供这样的内存分页功能,不过我们可以使用Ext2的examoles/ux/data/目录下提供的一个PagingMemoryProxy.js的扩展,让他从本地数组中读取数据,并实现内存分页。
PagingMemoryProxy.js在源代码的examples\ux\data目录下,本来书中给的是使用Ext.loader和require来引入依赖,但是我没有成功,这里还是用script标签引入:

<script> Ext.onReady(function() { //引入PagingMemoryProxy // Ext.Loader.setConfig({ // enabled: true, // paths: { // //类名前缀:所在路径 // 'Ext.ux.data': '../emamples/ux/data' // } // }); // Ext.require(['Ext.ux.data.PagingMemoryProxy']); Ext.define('Msg', { extend: 'Ext.data.Model', fields: [{ name: 'id', type: 'int' }, { name: 'name', type: 'string' }, { name: 'descn', type: 'string' }] }); // var itemsPerPage = 2; var store = Ext.create('Ext.data.Store', { model: 'Msg', fields: ['id', 'name', 'descn'], proxy: { type: 'pagingmemory', //修改为pagingmemory data: [{ id: 1, name: "name1", descn: "descn1" }, { id: 2, name: "name2", descn: "descn2" }, { id: 3, name: "name3", descn: "descn3" }, { id: 4, name: "name4", descn: "descn4" }, { id: 5, name: "name5", descn: "descn5" }, { id: 6, name: "name6", descn: "descn6" }], reader: { type: 'json' //数据是json格式的 } }, autoLoad: true, pageSize: 2, }); store.load({ params: { start: 0, limit: 2 } }); grid = new Ext.grid.GridPanel({ autoHeight: true, renderTo: 'grid', store: store, columns: [{ header: '编号', dataIndex: 'id', sortable: true //按照序号排列 }, { header: '名称', dataIndex: 'name' }, { header: '描述', dataIndex: 'descn' }], forceFit: true, bbar: new Ext.PagingToolbar({ store: store, //分页的数据源 // pageSize: 2, //每页显示数据为2条,这里也应该是版本的问题,4.2版本中pageSize在store中 displayInfo: true, //是否显示数据信息 displayMsg: '显示第{0}条到{1}条记录,一共{2}条', //只有当displayInfo 为true 的时候才有效,用来显示数据的提示信息,{}内的数字将会被替换为对应的数据,不过取值只能是0,1,2 emptyMsg: "没有记录" //没有数据显示的信息 }) }); }); </script> <body> <div id="grid"></div>
大概就是,通过script标签引入插件,之后将store中的proxy类型换成pagingmemory类型,读取的数据类型要和提供的数据一致,我这里是json类型 ,最后通过store.load加载数据。
~后台排序
表格排序一般只对当前页的数据进行排序。如果想要对所有数据进行排序,就需要将数据提交给后台,后台将排序信息写道sql中,处理后在返回前台。
前后台交互就是将后台数据处理好之后显示到表格中,后台只需要返回格式正确的数据,前后台交互之前就已经完成了,这里就是在其之上加上排序。
数据需要提交到服务端,所以,就需要将Ext.data.Store的remoteSort属性设置为true,这个属性是指能否允许远程排序,默认值为false。
尴尬的是一直都没有成功,说是把remote设置为true就会自动向后台提交数据(包括了排序字段sort和升降序dir),但是后台一个也没收到,全是null,下面是大概的代码,大家可以康康

<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <% String start = request.getParameter("start"); String limit = request.getParameter("limit"); //获取参数 String sort = request.getParameter("sort");//sort是需要排序的字段 String dir = request.getParameter("dir");//升序还是降序 System.out.println(dir); System.out.println(sort); if(dir == null){ dir="ASC"; } boolean jsonP = false; String cb = request.getParameter("callback"); if (cb != null) { jsonP = true; response.setContentType("text/javascript"); } else { response.setContentType("application/x-json"); } if(jsonP){ response.getWriter().write(cb+"("); } try{ int index = Integer.parseInt(start); int pageSize = Integer.parseInt(limit); String json = "{\"totalProperty\":100,\"root\":["; if(dir.equals("ASC")){ for(int i = index; i < pageSize+index; i++){ json += "{\"id\":"+i + ",\"name\":\"name"+ i +"\",\"descn\":\"descn"+i+"\"}"; if(i != pageSize+index - 1){ json += ","; } } }else{ for(int i = pageSize+index; i > index; i--){ json += "{\"id\":"+i + ",\"name\":\"name"+ i +"\",\"descn\":\"descn"+i+"\"}"; if(i != index - 1){ json += ","; } } } json+= "]}"; response.getWriter().write(json); if(jsonP){ response.getWriter().write(");"); } }catch(Exception ex){ } %>

<script> Ext.onReady(function() { Ext.define('Msg', { extend: 'Ext.grid.ColumnModel', fields: [{ name: 'id', type: 'int', remoteSort: true }, { name: 'name', type: 'string' }, { name: 'descn', type: 'string' }] }); var itemsPerPage = 10; var store = Ext.create('Ext.data.Store', { model: 'Msg', fields: ['id', 'name', 'descn'], proxy: { type: 'jsonp', //修改为pagingmemory url: 'http://localhost:8080/Extjs4Test_war/ext01.jsp', reader: { type: 'json', //数据是json格式的 totalProperty: 'totalProperty', root: 'root', idProperty: 'id' }, }, //远程数据排序,传递两个参数,sort和dir remoteSort: true, autoLoad: true, pageSize: itemsPerPage, }); store.load({ params: { start: 0, limit: itemsPerPage } }); grid = new Ext.grid.GridPanel({ autoHeight: true, renderTo: 'grid', store: store, columns: [{ header: '编号', dataIndex: 'id', // sortable: true //按照序号排列 }, { header: '名称', dataIndex: 'name' }, { header: '描述', dataIndex: 'descn' }], forceFit: true, bbar: new Ext.PagingToolbar({ store: store, //分页的数据源 // pageSize: 2, //每页显示数据为2条,这里也应该是版本的问题,4.2版本中pageSize在store中 displayInfo: true, //是否显示数据信息 displayMsg: '显示第{0}条到{1}条记录,一共{2}条', //只有当displayInfo 为true 的时候才有效,用来显示数据的提示信息,{}内的数字将会被替换为对应的数据,不过取值只能是0,1,2 emptyMsg: "没有记录" //没有数据显示的信息 }) }); }); </script> <body> <div id="grid"></div> <!-- <button id="remove">删除第二行</button> --> </body>
额。。工作的关系还有自己的懒惰,时间过了两个月,再次看这个,发现数据其实传到了后台,不过有一些出入,在于dir没有用,排序字段和升降序都是存在sort中的,并且以json的格式传递到后台,在初次请求的时候,是没有传递的,只有在需要排序的时候,才会将参数传递到后台,点击表格中的排序符号(上,下三角)。完整代码如下,前端不变:

<%@ page import="com.fasterxml.jackson.databind.ObjectMapper" %> <%@ page import="com.fasterxml.jackson.databind.JsonNode" %> <%@ page import="com.fasterxml.jackson.core.JsonProcessingException" %> <%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <% String start = request.getParameter("start"); String limit = request.getParameter("limit"); //获取参数 String sort = request.getParameter("sort");//sort是需要排序的字段 String dir = request.getParameter("dir");//升序还是降序 // System.out.println(dir); // System.out.println(sort); String direction = null; if(sort != null){ sort = sort.substring(1,sort.length()-1); ObjectMapper objectMapper = new ObjectMapper(); try { JsonNode jsonNode = objectMapper.readTree(sort); //获取property字段值,这是需要排序的字段那列 JsonNode name = jsonNode.get("property"); String property = name.asText(); System.out.println(property); //获取dir字段下数组第二个对象的direction,升序或者降序 JsonNode name2 = jsonNode.get("direction"); direction = name2.asText(); System.out.println(direction); } catch (JsonProcessingException e) { e.printStackTrace(); } } if(direction == null){ direction="ASC"; } boolean jsonP = false; String cb = request.getParameter("callback"); if (cb != null) { jsonP = true; response.setContentType("text/javascript"); } else { response.setContentType("application/x-json"); } if(jsonP){ response.getWriter().write(cb+"("); } try{ int index = Integer.parseInt(start); int pageSize = Integer.parseInt(limit); String json = "{\"totalProperty\":100,\"root\":["; if(direction.equals("ASC")){ for(int i = index; i < pageSize+index; i++){ json += "{\"id\":"+i + ",\"name\":\"name"+ i +"\",\"descn\":\"descn"+i+"\"}"; if(i != pageSize+index - 1){ json += ","; } } }else{ for(int i = pageSize+index; i > index; i--){ json += "{\"id\":"+i + ",\"name\":\"name"+ i +"\",\"descn\":\"descn"+i+"\"}"; if(i != index - 1){ json += ","; } } } json+= "]}"; response.getWriter().write(json); if(jsonP){ response.getWriter().write(");"); } }catch(Exception ex){ } %>
~问题的点就在于从哪里获取到前端传递到后台的,排序关键字和升降序要求。
这表格东西也真多,先到这里,下篇继续。。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· AI与.NET技术实操系列(六):基于图像分类模型对图像进行分类