extjs4之合併單元格





index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
    
    <title>ExtJS Merge Cells</title>
    
    <link type="text/css" rel="stylesheet" href="../extjs4/resources/css/ext-all-neptune.css" />
	<link type="text/css" rel="stylesheet" href="../extjs4/resources/theme/ext-theme-neptune-all.css" />
    <script type="text/javascript" src="../extjs4/ext-all-debug.js"></script>
    <script type="text/javascript" src="../MergeCellTable.js"></script>
    <script type="text/javascript" src="../MergeCellPanel.js"></script>
    <script type="text/javascript" src="example.js"></script>
    <style type="text/css">
		.x-grid-td {
			border-width: 0;
			overflow: hidden;
			vertical-align: middle;
		}
	</style>
</head>
<body>
</body>
</html>

example.js

Ext.onReady(function() {

	Ext.create('Ext.data.Store', {
		storeId:'simpsonsStore',
		fields:['cat1', 'cat2', 'cat2_desc','name'],
		data:{'items':[
			{ "cat1": "分類1", "cat2": "分類21", "name": "名稱1" },
			{ "cat1": "分類1", "cat2": "分類22", "name": "名稱1" },
			{ "cat1": "分類1", "cat2": "分類22", "name": "名稱2" },
			{ "cat1": "分類1", "cat2": "分類23", "name": "名稱1" },
			{ "cat1": "分類2", "cat2": "分類21", "name": "名稱1" },
			{ "cat1": "分類2", "cat2": "分類21", "name": "名稱2" },
			{ "cat1": "分類2", "cat2": "分類22", "name": "名稱1" },
			{ "cat1": "分類2", "cat2": "分類23", "name": "名稱1" },
			{ "cat1": "分類2", "cat2": "分類24", "name": "名稱1" },
			{ "cat1": "分類2", "cat2": "分類24", "name": "名稱2" },
			{ "cat1": "分類2", "cat2": "分類24", "name": "名稱3" },
			{ "cat1": "分類3", "cat2": "分類21", "name": "名稱1" },
			{ "cat1": "分類3", "cat2": "分類22", "name": "名稱1" },
			{ "cat1": "分類3", "cat2": "分類23", "name": "名稱1" },
			{ "cat1": "分類3", "cat2": "分類24", "name": "名稱1" },
			{ "cat1": "分類3", "cat2": "分類24", "name": "名稱2" },
			{ "cat1": "分類3", "cat2": "分類25", "name": "名稱1" }
		]},
		proxy: {
			type: 'memory',
			reader: {
				type: 'json',
				root: 'items'
			}
		}
	});

    
    Ext.create('Ext.ux.grid.MergeCellPanel', {
		title: 'Simpsons',
        renderTo: Ext.getBody(),
        viewConfig: {
            mergeColumns: 'cat1>cat2|cat2_desc'
        },
        store: Ext.data.StoreManager.lookup('simpsonsStore'),
        columns: [
            { text: '分類1', dataIndex: 'cat1' },
            { text: '分類2', dataIndex: 'cat2' },
            { text: '分類2描述', dataIndex: 'cat2_desc', flex: 1 },
            { text: '名稱', dataIndex: 'name' },
			{ text: '列合併',
			columns:[
				{ text: 'C1' },
				{ text: 'C2' },
				{ text: 'C3' },
				{ text: 'C4' },
				{ text: 'C5' }
			]}
            
        ]
    });
   
});



重要核心文件如下

MergeCellTable.js

Ext.define('Ext.ux.view.MergeCellTable', {
    extend: 'Ext.view.Table',
    
    alias: ['widget.mergecelltableview'],
    type: 'mergecelltableview',
    baseCls: Ext.baseCSSPrefix + 'mergegrid-view',
    
    stripeRows: false,
    
    separator: '>', // 不同級別分割符
    sameLevelSeparator: '|', // 同級別分割符
    __rowspans: null, // 緩存要合併的列中每個單元格的rowspan, refresh時會刪除重新計算
    __merge_columns: null, // 緩存要合併的列, refresh時會刪除重新獲取
    cellTpl: [ // 增加了rowspan屬性
        '<td role="gridcell" class="{tdCls}" {tdAttr} id="{[Ext.id()]}" rowspan="{rowspan}" <tpl if="hidden">style="display:none"</tpl>>',
            '<div {unselectableAttr} class="' + Ext.baseCSSPrefix + 'grid-cell-inner {innerCls}"',
                'style="height:auto;text-align:{align};<tpl if="style">{style}</tpl>">{value}</div>',
        '</td>', {
            priority: 0
        }
    ],
    renderCell: function(column, record, recordIndex, columnIndex, out) { // 添加rowspan與隱藏td
        var me = this,
            rowspans = me.getRowspans();
        
        var rowspan = (rowspans[recordIndex] || {})[column.dataIndex];
        
        cellValues = me.cellValues,
        cellValues.rowspan = rowspan;
        // cellTpl採用了display:none而不是不生成td, 因爲若不生成td在使用rowediting時會出錯
        cellValues.hidden = rowspan === 0;
        
        me.callParent(arguments);
    },
    onAdd: function(store, records, index, cfg) {
        this.refresh();
    },
    onRemove: function() {
        this.refresh();
    },
    onUpdate: function() {
        this.refresh();
    },
    refresh: function() {
        var me = this;
        
        // 刷新時要重新計算rowspan
        delete me.__rowspans;
        delete me.__merge_columns;
        
        me.callParent(arguments);
    },
    getRowspans: function() {
        var me = this;
        
        // 已經計算過直接返回
        var rowspans = me.__rowspans;
        if (rowspans != null) {
            return rowspans;
        }
        
        // 計算rowspan
        rowspans = [];
        var store = me.dataSource,
            mergeColumns = me.getMergeColumns();
        var setSameLevelRowspan = function(rowspans, rowIndex, columns, rowspan) {// 設置同級其他列的rowspan
            var i, temp, len = columns.length;
            for (i = 1; i < len; i++) {
                temp = columns[i];
                rowspans[rowIndex][temp] = rowspan;
            }
        };
        var calculateRowspans = function(rowspans, mergeColumns, currentColumnIndex, store, from, to) {
            if (currentColumnIndex >= mergeColumns.length) {
                return;
            }
            
            var columns = mergeColumns[currentColumnIndex],
                i, current, prev, mergeStart = 0;
            var column = columns[0];
            
            try {
                for (i = from; i < to + 1; i++) {
                    current = store.getAt(i).get(column);
                    if (current !== prev) {
                        rowspans[i] = rowspans[i] || {};
                        rowspans[i][column] = 1;
                        setSameLevelRowspan(rowspans, i, columns, 1);
                        
                        // 遞歸獲取子列
                        if (prev != null) {
                            calculateRowspans(rowspans, mergeColumns, currentColumnIndex + 1, store, mergeStart, i - 1);
                        }
                        
                        prev = current;
                        mergeStart = i;
                    } else {
                        rowspans[mergeStart][column]++;
                        setSameLevelRowspan(rowspans, mergeStart, columns, rowspans[mergeStart][column]);
                        
                        rowspans[i] = rowspans[i] || {};
                        rowspans[i][column] = 0;
                        setSameLevelRowspan(rowspans, i, columns, 0);
                    }
                }
                if (i > mergeStart) {
                    calculateRowspans(rowspans, mergeColumns, currentColumnIndex + 1, store, mergeStart, i - 1);
                }
            } catch(e) {
                if (console) {
                    console.error(e);
                }
            }
        };
        calculateRowspans(rowspans, mergeColumns, 0, store, 0, store.data.length - 1);
        
        // 緩存
        me.__rowspans = rowspans;
        
        return rowspans;
    },
    getMergeColumns: function() {
        var me = this;
        var columns = me.__merge_columns;
        if (columns != null) {
            return columns;
        }
        
        // 未配置時直接返回
        var mergeColumns = me.mergeColumns;
        if (Ext.isEmpty(mergeColumns)) {
            return [];
        }
        
        // 轉換合併規則
        var separator = me.separator,
            sameLevelSeparator = me.sameLevelSeparator;
        columns = mergeColumns.split(separator);
        var i, len = columns.length;
        for (i = 0; i < len; i++) {
            columns[i] = columns[i].split(sameLevelSeparator);
        }
        
        // 緩存
        me.__merge_columns = columns;
        
        return columns;
    }
});



MergeCellPanel.js

Ext.define('Ext.ux.grid.MergeCellPanel', {
    extend: 'Ext.grid.Panel',
    
    alias: ['widget.mergecellgrid'],
    viewType: 'mergecelltableview',
    
    initComponent: function() {
        var me = this;
        
        Ext.apply(me, {
            selType: 'cellmodel', // 按單元格選擇
            sortableColumns: false, // 禁止排序
            columnLines: true, // 顯示網格線
            rowLines: true, // 顯示網格線
            trackMouseOver: false // 禁止跟蹤鼠標變色
        });
        
        me.callParent();
    }
});


















發佈了57 篇原創文章 · 獲贊 5 · 訪問量 13萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章