脏概念定义如下:
通常,只有单元格值的变更才导致其成为脏数据。
如果单元格是脏数据,其所在的行也将是脏数据。
如果插入了一行并为其中的一个单元格设置了值,那么此行将只是一个插入的行,而不是脏数据。被设值的那个单元格也不是脏数据。
加载绑定数据的项不是脏数据,但是,在通过 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);