概述
本 Demo 展示了如何使用 SpreadJS 的单元格级别数据绑定功能,将 JavaScript 对象的属性绑定到工作表的指定单元格。Demo 演示了数据绑定、事件监听和双向数据同步的完整流程,包括嵌套对象属性的绑定(如 address.postcode)。
实现思路
创建数据对象(包含嵌套属性的 person 对象)
使用 CellBindingSource 包装数据对象,创建数据源
通过 setBindingPath 方法为单元格设置绑定路径
调用 setDataSource 方法将数据源设置到工作表
监听 SelectionChanged 事件,显示选中单元格的绑定路径
监听 CellChanged 事件,同步单元格变化到 HTML 输入框
实现数据更新函数,允许通过 HTML 输入框修改数据源并刷新表格
代码解析
创建数据源并设置绑定路径
这段代码创建了数据源并将其绑定到单元格。CellBindingSource 构造函数接收数据对象,setBindingPath 的第三个参数支持嵌套属性路径(如 "address.postcode"),setDataSource 方法将包装后的数据源应用到工作表。
监听选择变化事件
当用户选择不同的单元格时,SelectionChanged 事件被触发,通过 getBindingPath 方法获取当前单元格的绑定路径并显示在页面上。
监听单元格内容变化事件
当单元格内容被修改时,CellChanged 事件触发,由于单元格已绑定到 person 对象,对象的属性值会自动更新。这段代码将更新后的数据同步显示到页面的输入框中,实现了从表格到界面的数据同步。
更新数据源并刷新表格
这些函数允许通过 HTML 输入框修改数据源对象的属性。修改后调用 sheet.repaint() 方法刷新表格显示,实现了从界面到表格的数据同步。
运行效果
表格中的灰色单元格已绑定到 person 对象的相应属性
点击绑定单元格时,页面底部会显示该单元格的绑定路径(如 "name"、"address.postcode")
直接在表格中修改单元格内容,右侧的输入框会自动更新为最新的数据值
在右侧输入框中修改数据并按键盘,表格中对应的单元格会实时更新
支持嵌套属性绑定,如 address.postcode 绑定到第 5 行第 2 列
API 参考
CellBindingSource 构造函数
data:要绑定的数据对象
setBindingPath 方法
row:单元格行索引
col:单元格列索引
path:绑定路径,支持嵌套属性(如 "address.postcode")
getBindingPath 方法
返回指定单元格的绑定路径字符串
setDataSource 方法
data:数据源(对于单元格级别绑定,应为 CellBindingSource 对象)
reset:可选,是否重置工作表
var person, sheet;
window.onload = function () {
var spread = new GC.Spread.Sheets.Workbook(document.getElementById("ss"));
initSpread(spread);
};
function initSpread(spread) {
var spreadNS = GC.Spread.Sheets;
sheet = spread.sheets[0];
sheet.suspendPaint();
sheet.setColumnWidth(0, 120);
sheet.setColumnWidth(1, 120);
sheet.setColumnWidth(2, 120);
sheet.setValue(0, 0, 'cell-binding');
sheet.setValue(2, 1, 'Name');
sheet.setValue(3, 1, 'Age');
sheet.setValue(4, 1, 'Sex');
sheet.setValue(5, 1, 'Address.postcode');
person = { name: "Wang Feng", age: 25, sex: "Male", address: { postcode: "710075" } };
document.getElementById("personName").value=person.name || "";
document.getElementById("personAge").value=person.age || "";
document.getElementById("personSex").value=person.sex || "";
document.getElementById("personPostcode").value=person.address.postcode || "";
var source = new spreadNS.Bindings.CellBindingSource(person);
sheet.setBindingPath(2, 2, "name");
sheet.setBindingPath(3, 2, "age");
sheet.setBindingPath(4, 2, "sex");
sheet.setBindingPath(5, 2, "address.postcode");
sheet.setDataSource(source);
sheet.setSelection(2, 2, 1, 1);
var path = sheet.getBindingPath(2, 2);
sheet.getRange(2, 2, 4, 1).backColor("rgb(208,206,206)");
document.getElementById("bindingPath").innerHTML=path || "";
sheet.bind(spreadNS.Events.SelectionChanged, function() {
var activeCell = sheet.getSelections()[0];
var path = sheet.getBindingPath(activeCell.row, activeCell.col);
document.getElementById("bindingPath").innerHTML=path || "";
});
sheet.bind(spreadNS.Events.CellChanged, function() {
document.getElementById("personName").value=person.name || "";
document.getElementById("personAge").value=person.age || "";
document.getElementById("personSex").value=person.sex || "";
document.getElementById("personPostcode").value=person.address.postcode || "";
});
sheet.resumePaint();
};
var updateName = function(value) {
if (person && sheet) {
person.name = value;
sheet.repaint();
}
};
var updateAge = function(value) {
if (person && sheet) {
person.age = value;
sheet.repaint();
}
};
var updateSex = function(value) {
if (person && sheet) {
person.sex = value;
sheet.repaint();
}
};
var updatePostcode = function(value) {
if (person && sheet) {
person.address.postcode = value;
sheet.repaint();
}
};
<!doctype html>
<html style="height:100%;font-size:14px;">
<head>
<meta name="spreadjs culture" content="zh-cn" />
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" type="text/css"
href="$DEMOROOT$/zh/purejs/node_modules/@grapecity-software/spread-sheets/styles/gc.spread.sheets.excel2013white.css">
<script src="$DEMOROOT$/zh/purejs/node_modules/@grapecity-software/spread-sheets/dist/gc.spread.sheets.all.min.js"
type="text/javascript"></script>
<script
src="$DEMOROOT$/zh/purejs/node_modules/@grapecity-software/spread-sheets-resources-zh/dist/gc.spread.sheets.resources.zh.min.js"
type="text/javascript"></script>
<script src="$DEMOROOT$/spread/source/js/license.js" type="text/javascript"></script>
<script src="app.js" type="text/javascript"></script>
<link rel="stylesheet" type="text/css" href="styles.css">
</head>
<body>
<div class="sample-tutorial">
<div id="ss" class="sample-spreadsheets"></div>
<div class="options-container">
<div class="option-row">
<label style="background-color:#F4F8EB;">Select one of the gray cells to get its binding. You can also
change the Person object below to see it change in the Spread instance: change any of the text in
the text boxes below.</label>
</div>
<div class="option-row">
<label>Name: </label>
<input type="text" id="personName" onkeyup="updateName(this.value)" />
<label>Age: </label>
<input type="text" id="personAge" onkeyup="updateAge(this.value)" />
<label>Sex: </label>
<input type="text" id="personSex" onkeyup="updateSex(this.value)" />
<label>Postcode: </label>
<input type="text" id="personPostcode" onkeyup="updatePostcode(this.value)" />
<label>GetBindingPath: </label>
<label id="bindingPath" style="color:darkgreen"></label>
</div>
</div>
</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;
}
label {
display: block;
margin-bottom: 6px;
}
input {
padding: 4px 6px;
}
input[type=button] {
margin-top: 6px;
display: block;
}
input[type=text] {
margin-top: 6px;
margin-bottom: 6px;
display: block;
}
body {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}