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>
Ext.grid.GridPanel完整代码
复制代码

~常用功能

~一些属性的枚举

属性 介绍 默认值 可选值
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>
loading
复制代码

  本地读取速度太快,所以看不到加载过程,换成远程的(随机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有序
复制代码

  只需要将需要排序的列添加上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);
        }
    }
};
中文排序createComparator()
复制代码

~日期类型数据的处理

  首先,定义一组数据:

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'
}];
randerer渲染表格(内置函数)
复制代码

  但是这样会看起来很乱,所以可以将函数分开来写:

复制代码
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'/>";
    }
}
randerer渲染表格(函数外置)
复制代码

 

 

   除了文字和图片的修饰还可以加入弹窗:

复制代码
<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>
行变色 row color
复制代码

 

 

  有行的色变,就会有列的色变,修改代码,注释掉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在线检测工具解析一下拼写的有没有问题(这也是书上后台给出的源码):

在页面输出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>
本地数据分页 pagingmemory插件
复制代码

 

   大概就是,通过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){

    }
%>
后台服务器代码,remotesort
复制代码
复制代码
<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>
前端代码,remotesort
复制代码

   额。。工作的关系还有自己的懒惰,时间过了两个月,再次看这个,发现数据其实传到了后台,不过有一些出入,在于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){

    }
%>
后台服务器代码,版本二,解析json使用到了fastjson
复制代码

  ~问题的点就在于从哪里获取到前端传递到后台的,排序关键字和升降序要求。

  这表格东西也真多,先到这里,下篇继续。。

 

posted @   无意生  阅读(64)  评论(0编辑  收藏  举报
编辑推荐:
· .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技术实操系列(六):基于图像分类模型对图像进行分类
Title

点击右上角即可分享
微信分享提示