脏数据

脏数据可以帮助你获得变更的的数据。脏数据可以是插入的行,删除的行,更新的行(含有更新单元格的行),或者更新的单元格。当你需要捕获任何用户改变,而不必获得整个工作表时,这是特别有用的。

脏概念定义如下: 通常,只有单元格值的变更才导致其成为脏数据。 如果单元格是脏数据,其所在的行也将是脏数据。 如果插入了一行并为其中的一个单元格设置了值,那么此行将只是一个插入的行,而不是脏数据。被设值的那个单元格也不是脏数据。 加载绑定数据的项不是脏数据,但是,在通过 spreadSheet 修改绑定数据之后,它将变为脏数据。 脏数据的状态不会因为撤销操作而改变。 你可以通过调用表单上的 getDirtyRows 方法来获取所有的脏行。如果存在绑定的数据,用户可以从脏行中获取 row, item, 和 originalItem 信息。否则,只能获得行数据。 你可以通过调用 getDirtyCells 方法来获取脏单元格。当指定区域时,需要提供以下的操作参数。 row: 区域中左上方单元格的行索引值。 col: 区域中左上方单元格的列索引值。 rowCount: 区域行数目。 colCount:区域列数目。 每一个脏单元格都提供这些信息: row, col, oldValue, newValue. 你可以通过调用表单上的 getDeletedRows 方法来获取所有删除的行。如果存在绑定数据,用户可以从脏行中获取 row 和 originalItem 信息。否则,只能获得行数据。 你可以通过调用表单上的 getInsertRows 方法来获取所有插入的行。每一个插入的行都提供 行 和 项目 信息。 脏,插入和删除状态可以通过 clearPendingChanges 方法清除。在调用 setRowCount, setColumnCount, fromJSON, 或者 setDataSource 方法之后,它们也会被自动清除。你也可以按范围清除脏/插入/删除状态。会提供可选对象参数的clearChangeInfo以指定清除操作. clearChangeInfo.row: [optional] 清除区域的行索引 clearChangeInfo.col: [optional] 清除区域的列索引 clearChangeInfo.rowCount: [optional] 清除区域的行数 clearChangeInfo.colCount: [optional] 清除区域的列数 clearChangeInfo.clearType: [optional] 清除挂起的更改的类型,包括脏/插入/删除,默认为脏,该值为GC.Spread.Sheets.ClearPendingChangeType的枚举
<template> <div class="sample-tutorial"> <gc-spread-sheets class="sample-spreadsheets" @workbookInitialized="initSpread"> <gc-worksheet> </gc-worksheet> </gc-spread-sheets> <div class="options-container"> <p>Insert/delete rows or change row/column count using the buttons below.</p> <p>You can then get the dirty (what’s changed) rows or cells by clicking the “Get Dirty Rows”, “Get All Dirty Cells”, etc. buttons.</p> <div class="option-row"> <input type="button" id="btnInsertRow" value="Insert Row" title="Insert an new row at selected row" @click="insertRow($event)" /> <input type="button" id="btnDeleteRow" value="Delete Rows" title="Deleted seleted rows" @click="deleteRow($event)" /> </div> <p>If clear pending change by range, please select range in sheet and select type with Dirty/Insert/Delete.</p> <div class="option-row"> <div> <input id="clearByRange" type="checkbox"> <label for="clearByRange">Clear by Range</label> </div> <div> <input id="clearDirty" type="checkbox"> <label for="clearDirty">Dirty</label> <input id="clearInsert" type="checkbox"> <label for="clearInsert">Insert</label> <input id="clearDelete" type="checkbox"> <label for="clearDelete">Delete</label> </div> <input type="button" id="btnClearPendingChanges" value="Clear Pending Changes" title="Clear pending changes" @click="clearPendingChanges($event)" /> </div> <div class="option-row"> <input type="button" id="btnSetRowCount" value="Set Row Count" title="Set row count to 60" @click="setRowCount($event)" /> <input type="button" id="btnSetColumnCount" value="Set Column Count" title="Set column count to 16" @click="setColumnCount($event)" /> </div> <div class="option-row"> <input type="button" id="btnGetDirtyRows" value="Get Dirty Rows" @click="getDirtyRows($event)" /> <input type="button" id="btnGetDirtyCells" value="Get All Dirty Cells" @click="getAllDirtyCells($event)" /> <input type="button" id="btnGetSelectionDirtyCells" value="Get Selection Dirty Cells" @click="getSelectionDirty($event)" /> </div> <div class="option-row"> <input type="button" id="btnGetInsertRows" value="Get Insert Rows" @click="getInsertRow($event)" /> <input type="button" id="btnGetDeleteRows" value="Get Delete Rows" @click="getDeleteRow($event)" /> </div> <div class="option-row" style="width:100%;height:80px;"> <textarea id="taResult" style="width:100%;padding:0;float:right;height:80px;background:none" v-model="text"></textarea> </div> </div> </div> </template> <script> import Vue from "vue"; import '@grapecity-software/spread-sheets-resources-zh'; GC.Spread.Common.CultureManager.culture("zh-cn"); import "@grapecity-software/spread-sheets-vue"; import GC from "@grapecity-software/spread-sheets"; import "./styles.css"; let App = Vue.extend({ name: "app", data: function() { return { text: "" }; }, methods: { initSpread: function(spread) { const spreadNS = GC.Spread.Sheets; this.spread = spread; let sheet = spread.getSheet(0); sheet.suspendPaint(); for (let r = 0; r < 30; r++) { sheet.setText(r, 0, "A" + (r + 1)); } for (let c = 1; c < 20; c++) { sheet.setText(0, c, String.fromCharCode(65 + c) + "1"); } sheet.resumePaint(); sheet.clearPendingChanges(); let self = this; spread.bind(spreadNS.Events.CellChanged, function(event, data) { let row = data.row, col = data.col; if (row === undefined || col === undefined) { return; } if (sheet.hasPendingChanges(row, col)) { let dirtyDataArray = sheet.getDirtyCells(row, col); if (dirtyDataArray.length > 0) { self.appendResult(getChangedCellData(dirtyDataArray[0])); } } }); spread.bind(spreadNS.Events.RowChanged, function(event, data) { let row = data.row, count = data.count, propName = data.propertyName; if (row === undefined || count === undefined || propName === undefined) { return; } if (propName === "addRows" || propName === "deleteRows") { self.appendResult(propName + " @ " + row + (count > 1 ? " count: " + count : "")); } }); }, insertRow() { let sheet = this.spread.getActiveSheet(); let sels = sheet.getSelections(); let len = sels.length; if (len > 0) { let s = sels[0]; sheet.addRows(s.row, 1); } }, deleteRow() { let sheet = this.spread.getActiveSheet(); let sels = sheet.getSelections(); let len = sels.length; if (len > 0) { let s = sels[0]; sheet.deleteRows(s.row, s.rowCount); } }, clearPendingChanges() { let sheet = this.spread.getActiveSheet(); let clearByRange = _getElementById("clearByRange").checked; if (clearByRange) { let dirty = _getElementById("clearDirty").checked ? 1 : 0; let insert = _getElementById("clearInsert").checked ? 2 : 0; let deleted = _getElementById("clearDelete").checked ? 4 : 0; let clearType = dirty | insert | deleted; let selections = sheet.getSelections(); selections.forEach((selection) => { sheet.clearPendingChanges({ clearType: clearType, row: selection.row, rowCount: selection.rowCount, col: selection.col, colCount: selection.colCount }); }); } else { sheet.clearPendingChanges(); } this.text = ''; }, setRowCount() { let sheet = this.spread.getActiveSheet(); sheet.setRowCount(60); }, setColumnCount() { let sheet = this.spread.getActiveSheet(); sheet.setColumnCount(16); }, getDirtyRows() { let sheet = this.spread.getActiveSheet(); let rows = sheet.getDirtyRows(); if (rows.length > 0) { this.appendResult("Dirty rows @ " + rows.map(function(item) { return item.row; }).join(", ")); } }, getAllDirtyCells() { let sheet = this.spread.getActiveSheet(); let cells = sheet.getDirtyCells(); if (cells.length > 0) { this.appendResult("Dirty Cells:\n" + cells.map(function(item) { return getDirtyCellData(item); }).join("\n")); } }, getSelectionDirty() { let sheet = this.spread.getActiveSheet(); let sels = sheet.getSelections(); let len = sels.length; if (len > 0) { let s = sels[0]; let row = s.row, col = s.col; if (row < 0) { row = 0; } if (col < 0) { col = 0; } let cells = sheet.getDirtyCells(row, col, s.rowCount, s.colCount); if (cells.length > 0) { this.appendResult("Dirty Cells:\n" + cells.map(function(item) { return getDirtyCellData(item); }).join("\n")); } } }, getInsertRow() { let sheet = this.spread.getActiveSheet(); let rows = sheet.getInsertRows(); if (rows.length > 0) { this.appendResult("Inserted rows @ " + rows.map(function(item) { return item.row; }).join(", ")); } }, getDeleteRow() { let sheet = this.spread.getActiveSheet(); let rows = sheet.getDeletedRows(); if (rows.length > 0) { this.appendResult("Deleted rows @ " + rows.map(function(item) { return item.row; }).join(", ")); } }, appendResult(txt) { this.text = this.text + txt + "\n"; } } }); function _getElementById(id) { return document.getElementById(id); } function getChangedCellData(dirtyItem) { return ["Cell (", dirtyItem.row, ",", dirtyItem.col, ") changed from ", dirtyItem.oldValue, " to ", dirtyItem.newValue].join(""); } function getDirtyCellData(dirtyItem) { return ["Cell (", dirtyItem.row, ",", dirtyItem.col, ") oldValue: ", dirtyItem.oldValue, " newValue: ", dirtyItem.newValue].join(""); } new Vue({ render: h => h(App) }).$mount("#app"); </script>
<!doctype html> <html style="height:100%;font-size:14px;"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <link rel="stylesheet" type="text/css" href="$DEMOROOT$/zh/vue/node_modules/@grapecity-software/spread-sheets/styles/gc.spread.sheets.excel2013white.css"> <!-- SystemJS --> <script src="$DEMOROOT$/zh/vue/node_modules/systemjs/dist/system.src.js"></script> <script src="systemjs.config.js"></script> <script> System.import('./src/app.vue'); System.import('$DEMOROOT$/zh/lib/vue/license.js'); </script> </head> <body> <div id="app"></div> </body> </html>
.sample-tutorial { position: relative; height: 100%; overflow: hidden; } .sample-spreadsheets { width: calc(100% - 280px); height: 100%; overflow: hidden; float: left; } .options-container { float: right; width: 280px; padding: 12px; height: 100%; box-sizing: border-box; background: #fbfbfb; overflow: auto; } .option-row { font-size: 14px; padding: 5px; margin-top: 10px; } p{ padding:2px 10px; background-color:#F4F8EB; } input[type="button"] { width: 100%; margin-bottom: 2px; } body { position: absolute; top: 0; bottom: 0; left: 0; right: 0; }
(function(global) { System.config({ transpiler: 'plugin-babel', babelOptions: { es2015: true }, meta: { '*.css': { loader: 'css' }, '*.vue': { loader: 'vue-loader' } }, paths: { // paths serve as alias 'npm:': 'node_modules/' }, // map tells the System loader where to look for things map: { '@grapecity-software/spread-sheets': 'npm:@grapecity-software/spread-sheets/index.js', '@grapecity-software/spread-sheets-resources-zh': 'npm:@grapecity-software/spread-sheets-resources-zh/index.js', '@grapecity-software/spread-sheets-vue': 'npm:@grapecity-software/spread-sheets-vue/index.js', '@grapecity-software/jsob-test-dependency-package/react-components': 'npm:@grapecity-software/jsob-test-dependency-package/react-components/index.js', 'jszip': 'npm:jszip/dist/jszip.js', 'css': 'npm:systemjs-plugin-css/css.js', 'vue': 'npm:vue/dist/vue.min.js', 'vue-loader': 'npm:systemjs-vue-browser/index.js', 'tiny-emitter': 'npm:tiny-emitter/index.js', 'plugin-babel': 'npm:systemjs-plugin-babel/plugin-babel.js', 'systemjs-babel-build': 'npm:systemjs-plugin-babel/systemjs-babel-browser.js' }, // packages tells the System loader how to load when no filename and/or no extension packages: { src: { defaultExtension: 'js' }, rxjs: { defaultExtension: 'js' }, "node_modules": { defaultExtension: 'js' } } }); })(this);