概述
本 Demo 展示了如何为形状添加超链接功能,包括跳转到工作表位置、访问网站、发送邮件以及执行自定义命令。Demo 通过五个工作表展示了不同的超链接使用场景,帮助开发者理解形状超链接的多种应用方式。
实现思路
使用 fromJSON 加载预设的表格数据结构
创建不同类型的形状(箭头、矩形等),使用 sheet.shapes.add() 方法
为形状设置超链接,通过 hyperlink() 方法指定 URL、target 和 tooltip 属性
第一个工作表作为主页,包含导航箭头跳转到其他工作表
第五个工作表演示自定义命令,实现计时器功能
代码解析
创建形状并设置超链接
这段代码创建了一个箭头形状,并为其设置超链接。url 属性使用 sjs:// 协议实现工作表内部跳转,target 属性指定打开方式(0 表示在新窗口打开),tooltip 属性设置鼠标悬停时的提示信息。
设置邮件链接
邮件链接直接使用邮箱地址作为 url 值,点击后会打开默认邮件客户端。
使用自定义命令
command 属性接受一个函数,点击形状时执行该函数。这个示例实现了一个计时器功能,点击形状可以开始或停止计时。
运行效果
主页(第一个工作表)包含四个导航箭头,点击可跳转到对应的工作表
点击"邮件地址"工作表中的矩形,会打开邮件客户端并发送邮件到指定地址
点击"访问 URL"工作表中的矩形,会在新窗口打开指定网站
点击"自定义命令"工作表中的圆角矩形,会启动或停止计时器,显示计时时间
所有形状都设置了 tooltip,鼠标悬停时会显示提示信息
每个子页面都有"返回第一页"的箭头,可快速返回主页
API 参考
hyperlink 方法
获取或设置形状的超链接。
IHyperlink 接口属性
url:字符串,指定超链接的目标位置
支持网站链接(http/https)
支持邮件地址(mailto 或直接使用邮箱)
支持工作表内部跳转(sjs://'工作表名'!单元格)
target:数字,指定链接打开方式,默认值为 0(新窗口打开)
tooltip:字符串,设置鼠标悬停时的提示信息
command:字符串或函数,指定点击超链接时执行的操作
字符串:预定义命令名称
函数:自定义函数,接收 sheet、row、col、sheetArea 参数
注意:根据 MCP 文档建议,在执行 JSON I/O 时,如果传递函数给 command 属性,该功能将丢失。因此建议使用命令字符串而非函数。
window.onload = function () {
var spread = new GC.Spread.Sheets.Workbook(document.getElementById("ss"), { sheetCount: 5 });
initSpread(spread);
};
function initSpread(spread) {
spread.suspendPaint();
var sheet1 = spread.getSheet(0);
var sheet2 = spread.getSheet(1);
var sheet3 = spread.getSheet(2);
var sheet4 = spread.getSheet(3);
var sheet5 = spread.getSheet(4);
sheet1.fromJSON(shape_hyperlink_data_sheet1);
sheet2.fromJSON(shape_hyperlink_data_sheet2);
sheet3.fromJSON(shape_hyperlink_data_sheet3);
sheet4.fromJSON(shape_hyperlink_data_sheet4);
sheet5.fromJSON(shape_hyperlink_data_sheet5);
initSheet1(sheet1);
initSheet2(sheet2);
initSheet3(sheet3);
initSheet4(sheet4);
initSheet5(sheet5);
spread.resumePaint();
}
function initSheet1(sheet) {
window.rightArrow1 = sheet.shapes.add("rightArrow1", GC.Spread.Sheets.Shapes.AutoShapeType.rightArrowCallout, 580, 133, 143, 35);
applyUsageShapeStyle(rightArrow1);
rightArrow1.hyperlink({ url: "sjs://'工作表位置'!A1", target: 0, tooltip: "跳转到 '工作表位置'!A1" });
window.rightArrow2 = sheet.shapes.add("rightArrow2", GC.Spread.Sheets.Shapes.AutoShapeType.rightArrowCallout, 580, 193, 143, 35);
applyUsageShapeStyle(rightArrow2);
rightArrow2.hyperlink({ url: "sjs://'邮件地址'!A1", target: 0, tooltip: "跳转到 '邮件地址'!A1" });
window.rightArrow3 = sheet.shapes.add("rightArrow3", GC.Spread.Sheets.Shapes.AutoShapeType.rightArrowCallout, 580, 254, 143, 35);
applyUsageShapeStyle(rightArrow3);
rightArrow3.hyperlink({ url: "sjs://'访问 URL'!A1", target: 0, tooltip: "跳转到 '访问 URL'!A1" });
window.rightArrow4 = sheet.shapes.add("rightArrow4", GC.Spread.Sheets.Shapes.AutoShapeType.rightArrowCallout, 580, 314, 143, 35);
applyUsageShapeStyle(rightArrow4);
rightArrow4.hyperlink({ url: "sjs://'自定义命令'!A1", target: 0, tooltip: "跳转到 '自定义命令'!A1" });
}
function initSheet2(sheet) {
backToFirstPage(sheet);
}
function initSheet3(sheet) {
backToFirstPage(sheet);
window.rect1 = sheet.shapes.add("rectangle1", GC.Spread.Sheets.Shapes.AutoShapeType.rectangle, 175, 327, 268, 35);
var email = 'ZhangSan@example.com';
applyLinkageShapeStyle(rect1, email);
rect1.hyperlink({ url: email, target: 0 });
}
function initSheet4(sheet) {
backToFirstPage(sheet);
window.rect2 = sheet.shapes.add("rectangle2", GC.Spread.Sheets.Shapes.AutoShapeType.rectangle, 209, 327, 268, 35);
applyLinkageShapeStyle(rect2, 'www.grapecity.com.cn');
rect2.hyperlink({ url: "https://www.grapecity.com.cn", target: 0, tooltip: "跳转到 GrapeCity" });
}
function initSheet5(sheet) {
backToFirstPage(sheet);
window.rect3 = sheet.shapes.add("rectangle3", GC.Spread.Sheets.Shapes.AutoShapeType.roundedRectangle, 261, 188, 280, 140);
applyTimerShapeStyle(rect3, '点击这里开始计时器');
var stopWatch = new Stopwatch(rect3);
rect3.hyperlink({
command: function () {
if (!stopWatch.started) {
stopWatch.start();
} else {
stopWatch.stop();
}
}
});
}
function backToFirstPage(sheet) {
window.leftArrow = sheet.shapes.add("rightArrow1", GC.Spread.Sheets.Shapes.AutoShapeType.leftArrowCallout, 525, 410, 189, 35);
applyUsageShapeStyle(leftArrow, '返回第一页');
leftArrow.hyperlink({ url: "sjs://'超链接形状'!A1", target: 0, tooltip: "跳转到 '超链接形状'!A1" });
}
function applyUsageShapeStyle(shape, text) {
shape.adjustments([0.38, 0.36, 0.52, 0.8]);
shape.text(text || '查看用法');
var style = shape.style();
style.fill.type = 0;
style.line.color = "rgb(11,116,77)";
style.textEffect.color = "rgb(11,116,77)";
style.textFrame.vAlign = 1;
shape.style(style);
}
function applyLinkageShapeStyle(shape, text) {
shape.text(text);
var style = shape.style();
style.fill.type = 0;
style.line.transparency = 1;
style.textEffect.color = "rgb(5,99,193)";
style.textFrame.vAlign = 1;
style.textEffect.font = "20px Calibri"
shape.style(style);
}
function applyTimerShapeStyle(shape, text) {
shape.text(text);
var style = shape.style();
style.fill.type = 0;
style.line.color = "rgb(11,116,77)";
style.textEffect.color = "rgb(11,116,77)";
style.textFrame.hAlign = 1;
style.textFrame.vAlign = 1;
style.textEffect.font = "22px Calibri"
shape.style(style);
}
var Stopwatch = function (shape) {
let interval, ms, sec, min, _started, startTime, endTime;
reset();
function reset() {
ms = 0;
sec = 0;
min = 0;
shape.text('点击这里开始计时器\r\n00 : 00 : 000');
}
function start() {
this.started = _started = !_started;
startTime = new Date();
if (!interval) {
interval = setInterval(update, 10);
}
}
function stop() {
this.started = _started = !_started;
if (interval) {
clearInterval(interval);
interval = null;
var text = shape.text()
shape.text(text.replace('停止', '重新开始'));
ms = 0;
sec = 0;
min = 0;
}
}
function update() {
endTime = new Date();
var s = endTime - startTime;
ms = s % 1000;
s = (s - ms) / 1000;
sec = s % 60;
s = (s - sec) / 60;
min = s % 60;
let milli = (Array(3).join('0') + ms).slice(-3);
let seconds = sec < 10 ? '0' + sec : sec;
let minute = min < 10 ? '0' + min : min;
let timer = minute + " : " + seconds + " : " + milli;
shape.text(timer + '\r\n停止');
}
this.start = start;
this.stop = stop;
this.started = _started;
}
<!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-shapes/dist/gc.spread.sheets.shapes.min.js"
type="text/javascript"></script>
<script src="$DEMOROOT$/spread/source/js/license.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/data/shape-hyperlink-data.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>
</body>
</html>
.sample-tutorial {
position: relative;
height: 100%;
overflow: hidden;
}
.sample-spreadsheets {
width: 100%;
height: 100%;
overflow: hidden;
float: left;
}
body {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}