Office-Tab-for-Mac Office 窗口标签化,Office 多文件标签化管理
Office Tab:让操作更高效,给微软 Office 添加多标签页功能
Office 可以说是大家装机必备的软件,无论学习还是工作都少不了。其中最强大、用的最多的,还是微软的 Microsoft Office。
遗憾的是,微软的 Office 不支持多标签页功能。如果同时打开多个文档的话,文档间切换起来很不方便。
用过 WPS 多标签页的用户,如果再回头用微软 Office,感觉尤为明显。
今天我们就给大家分享一款超好用的 Office 标签插件——「Office Tab」。
给 Microsoft Office 加上多标签页功能,简洁漂亮,让操作更高效。
主要功能:
- 在标签页中读取、编辑和管理多个文件
- 轻松打开、保存和关闭所有文件
- 通过为标签页添加颜色标记来识别文件
- 按组对文件进行分类和管理
- Office Tab 支持在单个标签窗口中打开、查看、编辑多个Office文档,就像网页浏览器(如谷歌浏览器、火狐浏览器等)一样。
- Office Tab适配Microsoft Office 2024、2021、2019、2016、2013、2010、2007、2003和Office 365(包括Word、Excel、PowerPoint、Publisher、Access、Project和Visio)标签式界面。
一、Office-Tab-for-Windows:
You can Download from Office-Tab official
二、Office-Tab-for-Mac:
0. 前提条件
-
Node.js:确保已安装Node.js和npm。
-
Office Developer Tool Yo Office:使用npm安装
Yo Office
,这是微软为搭建Office插件而开发的工具。npm install -g yo generator-office
-
代码编辑器:使用VS Code或任何编辑器进行开发。
实施步骤
第一步:创建Office插件项目
- 运行以下命令,创建新的Office插件项目:
yo office
- 按照提示进行操作,选择以下选项:
Option | Selection |
---|---|
Project type | Office Add-in Task Pane project |
Script type | JavaScript |
Project name | TabbedWordPlugin |
Type of project | Task Pane |
Office products | Word (Excel, OneNote, Outlook, PowerPoint, Project, Word) |
- 生成后,进入项目目录:
cd TabbedWordPlugin
步骤2:设计标签式用户界面
在./src/taskpane/taskpane.html
中,设计HTML结构以创建标签栏和内容区域(此处可根据自己需求进行自定义)。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Tabbed Word Plugin</title>
<link rel="stylesheet" href="taskpane.css" />
</head>
<body>
<div id="tab-bar">
<!-- Tabs will be dynamically added here -->
</div>
<button id="new-tab-btn">New Document Tab</button>
<div id="content-area">
<p id="document-content">No document loaded.</p>
</div>
<script src="taskpane.js"></script>
</body>
</html>
在taskpane.css
中添加CSS,为标签式界面设置样式。
#tab-bar {
display: flex;
border-bottom: 1px solid #ccc;
background-color: #f9f9f9;
}
.tab {
padding: 10px;
cursor: pointer;
border-right: 1px solid #ccc;
}
.tab.active {
background-color: #ddd;
font-weight: bold;
}
#content-area {
padding: 20px;
}
.context-menu {
position: fixed;
background: white;
border: 1px solid #ccc;
box-shadow: 2px 2px 5px rgba(0,0,0,0.2);
z-index: 1000;
}
.menu-item {
padding: 8px 12px;
cursor: pointer;
}
.menu-item:hover {
background-color: #f0f0f0;
}
.sub-menu {
position: absolute;
left: 100%;
top: 0;
background: white;
border: 1px solid #ccc;
display: none;
}
.menu-item:hover .sub-menu {
display: block;
}
.save-dialog {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: white;
padding: 20px;
border: 1px solid #ccc;
box-shadow: 0 0 10px rgba(0,0,0,0.2);
z-index: 1001;
}
.dialog-buttons {
display: flex;
justify-content: flex-end;
gap: 10px;
margin-top: 20px;
}
.dialog-buttons button {
padding: 6px 12px;
cursor: pointer;
}
第三步:实现标签切换逻辑
在taskpane.js
中编写JavaScript代码,用于管理标签并在文档视图之间切换。
let tabs = [];
let activeTab = null;
// Get UI elements
const tabBar = document.getElementById("tab-bar");
const newTabBtn = document.getElementById("new-tab-btn");
const contentArea = document.getElementById("document-content");
// Create a new tab
newTabBtn.addEventListener("click", async () => {
const tabId = `doc-${tabs.length + 1}`;
const tab = document.createElement("div");
tab.className = "tab";
tab.textContent = `Document ${tabs.length + 1}`;
tab.dataset.id = tabId;
tab.addEventListener("click", () => switchTab(tabId));
tabBar.appendChild(tab);
tabs.push({ id: tabId, element: tab });
switchTab(tabId);
});
// Switch tabs
async function switchTab(tabId) {
if (activeTab === tabId) return;
// Deactivate the current tab
if (activeTab) {
const currentTab = tabs.find((tab) => tab.id === activeTab);
currentTab.element.classList.remove("active");
}
// Activate the new tab
const newTab = tabs.find((tab) => tab.id === tabId);
newTab.element.classList.add("active");
activeTab = tabId;
// Load document content
await loadDocumentContent(tabId);
}
// Load document content
async function loadDocumentContent(tabId) {
try {
await Word.run(async (context) => {
// Get document content
const body = context.document.body;
body.load("text");
await context.sync();
contentArea.textContent = body.text;
});
} catch (error) {
console.error("Error loading document content:", error);
}
}
// Initialize context menu
function initializeContextMenu() {
const contextMenu = document.createElement("div");
contextMenu.className = "context-menu";
contextMenu.style.display = "none";
document.body.appendChild(contextMenu);
const menuItems = [
{ text: "新建标签页", handler: createNewTab },
{ text: "复制标签页", handler: duplicateTab },
{ text: "关闭标签页", handler: closeTab },
{ text: "关闭右侧标签页", handler: closeRightTabs },
{ text: "关闭左侧标签页", handler: closeLeftTabs },
{ text: "颜色标记", subItems: [
{ text: "蓝色", color: "#e6f3ff" },
{ text: "红色", color: "#ffe6e6" },
{ text: "黄色", color: "#fff9e6" },
{ text: "橘色", color: "#fff0e6" },
{ text: "绿色", color: "#e6ffe6" },
{ text: "紫色", color: "#f3e6ff" }
]}
];
menuItems.forEach(item => {
const menuItem = document.createElement("div");
menuItem.className = "menu-item";
menuItem.textContent = item.text;
if (item.subItems) {
const subMenu = document.createElement("div");
subMenu.className = "sub-menu";
item.subItems.forEach(subItem => {
const subMenuItem = document.createElement("div");
subMenuItem.className = "menu-item";
subMenuItem.textContent = subItem.text;
subMenuItem.onclick = () => setTabColor(subItem.color);
subMenu.appendChild(subMenuItem);
});
menuItem.appendChild(subMenu);
} else {
menuItem.onclick = item.handler;
}
contextMenu.appendChild(menuItem);
});
return contextMenu;
}
// Create a new tab
async function createNewTab() {
try {
await Word.run(async (context) => {
context.application.createDocument();
await context.sync();
updateTabs();
});
} catch (error) {
console.error("Error creating new document:", error);
}
}
// Duplicate current tab
async function duplicateTab() {
if (!activeTab) return;
try {
await Word.run(async (context) => {
const doc = context.application.documents.getById(activeTab);
const range = doc.body;
range.select();
await context.sync();
document.execCommand('copy');
await createNewTab();
document.execCommand('paste');
});
} catch (error) {
console.error("Error duplicating tab:", error);
}
}
// Close tab with save check
async function closeTab(tabId) {
try {
await Word.run(async (context) => {
const doc = context.application.documents.getById(tabId);
context.load(doc, 'saved');
await context.sync();
if (!doc.saved) {
const result = await showSaveDialog(doc.properties.title);
switch (result) {
case 'save':
await doc.save();
await doc.close();
break;
case 'dontSave':
await doc.close(false);
break;
case 'cancel':
return false;
}
} else {
await doc.close();
}
return true;
});
} catch (error) {
console.error("Error closing document:", error);
return false;
}
}
// Show save dialog
function showSaveDialog(docName) {
return new Promise((resolve) => {
const dialog = document.createElement("div");
dialog.className = "save-dialog";
dialog.innerHTML = `
<h3>保存文档</h3>
<p>文档 '${docName}' 已修改,是否保存更改?</p>
<div class="dialog-buttons">
<button οnclick="resolve('save')">保存</button>
<button οnclick="resolve('dontSave')">不保存</button>
<button οnclick="resolve('cancel')">取消</button>
</div>
`;
document.body.appendChild(dialog);
});
}
// Close tabs to the right
async function closeRightTabs() {
const currentIndex = tabs.findIndex(tab => tab.id === activeTab);
for (let i = tabs.length - 1; i > currentIndex; i--) {
const success = await closeTab(tabs[i].id);
if (!success) break;
}
}
// Close tabs to the left
async function closeLeftTabs() {
const currentIndex = tabs.findIndex(tab => tab.id === activeTab);
for (let i = currentIndex - 1; i >= 0; i--) {
const success = await closeTab(tabs[i].id);
if (!success) break;
}
}
// Set tab color
function setTabColor(color) {
const tab = document.querySelector(`[data-id="${activeTab}"]`);
if (tab) {
tab.style.backgroundColor = color;
}
}
第四步:调试并运行插件
-
在终端运行以下命令,启动本地服务器并打开Word:
npm start
-
在Word中,进入“插入”选项卡并加载“我的加载项”以加载插件。
-
测试添加选项卡、切换选项卡以及验证文档内容加载。
进一步改进
- 多文档支持:增强每个选项卡,加载一个独特的文档。
- 选项卡关闭功能:允许关闭选项卡并管理多个文档状态。
- 自动保存:在选项卡之间切换时自动保存文档内容。
按照本指南操作,您应该可以在Word插件中创建一个功能正常的选项卡式文档界面。祝您开发愉快!