自定义文件菜单

此演示展示了如何在文件菜单中添加自定义页面。

本示例演示以下内容: 如何向文件菜单添加自定义页面。 如何定义自定义组件并在文件菜单中使用它。
const resources = { tips: '请点击左上角的"文件"按钮,然后选择"模板"选项卡查看自定义页面。', loading: '加载中...' } window.onload = async function () { //change the file menu panel command to add the custom template execute logic. let fileMenuPanelCommand = GC.Spread.Sheets.Designer.getCommand(GC.Spread.Sheets.Designer.CommandNames.FileMenuPanel); let oldExecuteFn = fileMenuPanelCommand.execute; let oldStatusFn = fileMenuPanelCommand.getState; fileMenuPanelCommand.execute = async function (context, propertyName, newValue) { oldExecuteFn.apply(this, arguments); if (propertyName === "customTemplates") { console.log(newValue); showLoadingOverlay(); let json = await loadTemplateData(newValue); let spread = context.getWorkbook(); context.setData("FileMenu_show", false); await spread.fromJSON(json); hideLoadingOverlay(); context.getWorkbook().focus(true); } } fileMenuPanelCommand.getState = function () { let result = oldStatusFn.apply(this, arguments); result.customTemplates = custom_templates; return result; } let config = GC.Spread.Sheets.Designer.DefaultConfig; config.commandMap = { fileMenuPanel: fileMenuPanelCommand } let designer = new GC.Spread.Sheets.Designer.Designer("dss", config); let spread = designer.getWorkbook(); spread.getActiveSheet().setValue(1, 1, resources.tips); } function loadTemplateData(templateID) { let dataPath = custom_templates.find(t => t.id === templateID).dataPath; return fetch(dataPath).then(function (response) { return response.text(); }).then((str) => getDataFromJS(str)); } function showLoadingOverlay() { let overlay = document.createElement('div'); overlay.className = 'loading-overlay'; overlay.id = 'loading-overlay'; overlay.innerHTML = ` <div class="loading-spinner"></div> <div class="loading-text">${resources.loading}</div> `; document.body.appendChild(overlay); } function hideLoadingOverlay() { let overlay = document.getElementById('loading-overlay'); if (overlay) { document.body.removeChild(overlay); } }
<!doctype html> <html style="height:100%;font-size:14px;"> <head> <meta name="spreadjs culture"/> <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"> <link rel="stylesheet" type="text/css" href="$DEMOROOT$/zh/purejs/node_modules/@grapecity-software/spread-sheets-designer/styles/gc.spread.sheets.designer.light.min.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$/zh/purejs/node_modules/@grapecity-software/spread-sheets-charts/dist/gc.spread.sheets.charts.min.js" type="text/javascript"></script> <script src="$DEMOROOT$/zh/purejs/node_modules/@grapecity-software/spread-sheets-print/dist/gc.spread.sheets.print.min.js" type="text/javascript"></script> <script src="$DEMOROOT$/zh/purejs/node_modules/@grapecity-software/spread-sheets-barcode/dist/gc.spread.sheets.barcode.min.js" type="text/javascript"></script> <script src="$DEMOROOT$/zh/purejs/node_modules/@grapecity-software/spread-sheets-pdf/dist/gc.spread.sheets.pdf.min.js" type="text/javascript"></script> <script src="$DEMOROOT$/zh/purejs/node_modules/@grapecity-software/spread-sheets-pivot-addon/dist/gc.spread.pivot.pivottables.min.js" type="text/javascript"></script> <script src="$DEMOROOT$/zh/purejs/node_modules/@grapecity-software/spread-sheets-slicers/dist/gc.spread.sheets.slicers.min.js" type="text/javascript"></script> <script src="$DEMOROOT$/zh/purejs/node_modules/@grapecity-software/spread-sheets-tablesheet/dist/gc.spread.sheets.tablesheet.min.js" type="text/javascript"></script> <script src="$DEMOROOT$/zh/purejs/node_modules/@grapecity-software/spread-sheets-formula-panel/dist/gc.spread.sheets.formulapanel.min.js" type="text/javascript"></script> <script src="$DEMOROOT$/zh/purejs/node_modules/@grapecity-software/spread-sheets-io/dist/gc.spread.sheets.io.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$/zh/purejs/node_modules/@grapecity-software/spread-sheets-designer-resources-cn/dist/gc.spread.sheets.designer.resource.cn.min.js" type="text/javascript"></script> <script src="$DEMOROOT$/zh/purejs/node_modules/@grapecity-software/spread-sheets-designer/dist/gc.spread.sheets.designer.all.min.js" type="text/javascript"></script> <script src="$DEMOROOT$/spread/source/js/license.js" type="text/javascript"></script> <script src="$DEMOROOT$/spread/source/js/designer/license.js" type="text/javascript"></script> <script src="app.js" type="text/javascript"></script> <link href="./styles.css" rel="stylesheet" type="text/css" /> <script src="./component.js"></script> <script src="./template.js"></script> <script src="./data/templateData.js"></script> </head> <body style="margin:0;padding:0"> <div id="dss" style="width:100vw;border:1px solid darkgray"></div> </body> </html>
body { position: absolute; top: 0; bottom: 0; left: 0; right: 0; } #dss { height: 100%; } .template-selector { max-width: 1200px; margin: 0 auto; padding: 20px; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif; min-width: 0; overflow-x: hidden; } .templates-grid { display: flex; flex-wrap: wrap; gap: 16px; margin-top: 20px; justify-content: flex-start; align-items: flex-start; width: 100%; } @media (max-width: 600px) { .templates-grid { justify-content: center; } } .template-card { border: 1px solid #d1d1d1; border-radius: 4px; background: white; cursor: pointer; transition: all 0.2s ease; overflow: hidden; height: 180px; width: 200px; flex: 0 0 auto; display: flex; flex-direction: column; } .template-card:hover { border-color: #0078d4; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); transform: translateY(-2px); } .template-preview { flex: 1; background: #f8f9fa; display: flex; align-items: center; justify-content: center; position: relative; overflow: hidden; } .template-image-placeholder { width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; } .preview-content { width: 90%; height: 90%; border-radius: 2px; position: relative; background: white; border: 1px solid #ddd; display: flex; align-items: center; justify-content: center; } .simple-preview { display: flex; align-items: center; justify-content: center; width: 100%; height: 100%; } .preview-icon { font-size: 32px; opacity: 0.6; } .template-info { padding: 12px; background: white; border-top: 1px solid #e0e0e0; } .template-title { font-size: 14px; font-weight: 400; margin: 0; color: #333; text-align: left; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } @media (max-width: 768px) { .templates-grid { gap: 12px; justify-content: center; } .template-card { width: 160px; height: 150px; } .template-title { font-size: 12px; } .template-info { padding: 8px; } } @media (max-width: 480px) { .template-selector { padding: 10px; } .templates-grid { gap: 8px; justify-content: space-around; } .template-card { width: 140px; height: 130px; } .template-title { font-size: 11px; } } @media (min-width: 1400px) { .template-card { width: 220px; height: 200px; } .preview-icon { font-size: 40px; } } .loading-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.3); display: flex; justify-content: center; align-items: center; z-index: 9999; } .loading-spinner { width: 50px; height: 50px; border: 4px solid #f3f3f3; border-top: 4px solid #0078d4; border-radius: 50%; animation: spin 1s linear infinite; } .loading-text { color: white; margin-left: 16px; font-size: 16px; } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }