feat: 标签页新增更多菜单功能

- 新增更多菜单按钮替代原浏览器打开按钮
  - 实现重新加载、复制链接地址、默认浏览器打开功能
  - 实现将标签页移至新窗口功能
  - 实现打印功能
  - 菜单支持根据当前 URL 类型动态启用/禁用选项
  - 添加相关国际化文案
This commit is contained in:
kuaifan 2026-01-10 16:35:19 +00:00
parent 3b1dce6d67
commit 731dbc5507
8 changed files with 56 additions and 47 deletions

View File

@ -23,11 +23,13 @@ const electronMenu = {
reload: "重新加载",
print: "打印",
openInBrowser: "在浏览器中打开",
openInDefaultBrowser: "默认浏览器打开",
saveImageAs: "图片存储为...",
copyImage: "复制图片",
copyEmailAddress: "复制电子邮件地址",
copyLinkAddress: "复制链接地址",
copyImageAddress: "复制图片地址",
moveToNewWindow: "将标签页移至新窗口",
failedToSaveImage: "图片保存失败",
theImageFailedToSave: "图片无法保存",
},

45
electron/electron.js vendored
View File

@ -1963,6 +1963,7 @@ ipcMain.on('webTabExternal', (event) => {
*/
ipcMain.on('webTabShowMenu', (event, args) => {
const windowId = args?.windowId
const tabId = args?.tabId
const windowData = windowId ? webTabWindows.get(windowId) : null
const webTabWindow = windowData?.window
@ -1972,45 +1973,65 @@ ipcMain.on('webTabShowMenu', (event, args) => {
}
const item = currentWebTabInWindow(windowId)
const currentUrl = item?.view?.webContents?.getURL() || ''
const webContents = item?.view?.webContents
const currentUrl = webContents?.getURL() || ''
const canBrowser = !utils.isLocalHost(currentUrl)
const menuTemplate = [
{
label: '重新加载',
label: electronMenu.language.reload,
click: () => {
// TODO: 实现重新加载
if (webContents && !webContents.isDestroyed()) {
webContents.reload()
}
}
},
{
label: '复制链接地址',
label: electronMenu.language.copyLinkAddress,
enabled: canBrowser,
click: () => {
// TODO: 实现复制链接
if (currentUrl) {
clipboard.writeText(currentUrl)
}
}
},
{
label: '默认浏览器打开',
label: electronMenu.language.openInDefaultBrowser,
enabled: canBrowser,
click: () => {
// TODO: 实现默认浏览器打开
if (currentUrl) {
renderer.openExternal(currentUrl).catch(() => {})
}
}
},
{ type: 'separator' },
{
label: '将标签页移至新窗口',
label: electronMenu.language.moveToNewWindow,
enabled: windowData?.views?.length > 1,
click: () => {
// TODO: 实现移至新窗口
if (tabId) {
const bounds = webTabWindow.getBounds()
detachWebTab(windowId, tabId, bounds.x + 50, bounds.y + 50)
}
}
},
{ type: 'separator' },
{
label: '打印',
label: electronMenu.language.print,
click: () => {
// TODO: 实现打印
if (webContents && !webContents.isDestroyed()) {
webContents.print()
}
}
}
]
const menu = Menu.buildFromTemplate(menuTemplate)
menu.popup({ window: webTabWindow })
menu.popup({
window: webTabWindow,
x: args?.x,
y: args?.y
})
event.returnValue = "ok"
})

View File

@ -737,11 +737,14 @@ const utils = {
*/
isLocalHost(url) {
if (!url) {
return false
return true
}
if (!/^https?:\/\//i.test(url)) {
return true
}
try {
const uri = new URL(url)
return uri.hostname == "localhost"
return uri.hostname === 'localhost'
} catch (e) {
return false
}

View File

@ -150,10 +150,10 @@ body {
}
.nav-more svg {
width: 18px;
height: 18px;
width: 20px;
height: 20px;
color: #000000;
opacity: 0.7;
opacity: 0.9;
}
.nav-more:hover svg {

View File

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 32 32"><g fill="none"><path d="M9.5 16a2.5 2.5 0 1 1-5 0a2.5 2.5 0 0 1 5 0zm9 0a2.5 2.5 0 1 1-5 0a2.5 2.5 0 0 1 5 0zm6.5 2.5a2.5 2.5 0 1 0 0-5a2.5 2.5 0 0 0 0 5z" fill="currentColor"></path></g></svg>

Before

Width:  |  Height:  |  Size: 296 B

View File

@ -30,7 +30,7 @@
</li>
</ul>
<div class="nav-more" @click="onShowMenu">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><g fill="none"><path d="M9.5 16a2.5 2.5 0 1 1-5 0a2.5 2.5 0 0 1 5 0zm9 0a2.5 2.5 0 1 1-5 0a2.5 2.5 0 0 1 5 0zm6.5 2.5a2.5 2.5 0 1 0 0-5a2.5 2.5 0 0 0 0 5z" fill="currentColor"></path></g></svg>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 32 32"><g fill="none"><path d="M9.5 16a2.5 2.5 0 1 1-5 0a2.5 2.5 0 0 1 5 0zm9 0a2.5 2.5 0 1 1-5 0a2.5 2.5 0 0 1 5 0zm6.5 2.5a2.5 2.5 0 1 0 0-5a2.5 2.5 0 0 0 0 5z" fill="currentColor"></path></g></svg>
</div>
</div>
</div>
@ -214,13 +214,6 @@
pageTitle() {
return this.activeItem ? this.activeItem.title : 'Untitled'
},
/**
* 是否可以打开浏览器
* @returns {boolean}
*/
canBrowser() {
return !(this.activeItem && this.isLocalHost(this.activeItem.url))
},
/**
* 获取加载状态
* @returns {boolean}
@ -516,7 +509,14 @@
* 显示更多菜单
*/
onShowMenu() {
this.sendMessage('webTabShowMenu', {windowId: this.windowId, tabId: this.activeId})
const btn = document.querySelector('.nav-more')
const rect = btn.getBoundingClientRect()
this.sendMessage('webTabShowMenu', {
windowId: this.windowId,
tabId: this.activeId,
x: Math.round(rect.left),
y: Math.round(rect.bottom)
})
},
/**
@ -608,26 +608,6 @@
*/
updateNavigationState() {
this.sendMessage('webTabGetNavigationState')
},
/**
* 判断是否是本地URL
* @param url
* @returns {boolean}
*/
isLocalHost(url) {
if (!url) {
return true
}
if (!/^https?:\/\//i.test(url)) {
return true
}
try {
const uri = new URL(url)
return uri.hostname == "localhost"
} catch (e) {
return false
}
}
},
}

View File

@ -1270,6 +1270,8 @@ AI 机器人
状态[(*)]设置错误,设置剔除模式时必须填写状态负责人
键盘设置
在浏览器中打开
默认浏览器打开
将标签页移至新窗口
图片存储为...
复制电子邮件地址
复制链接地址

View File

@ -636,11 +636,13 @@ export default {
reload: this.$L("重新加载"),
print: this.$L("打印"),
openInBrowser: this.$L("在浏览器中打开"),
openInDefaultBrowser: this.$L("默认浏览器打开"),
saveImageAs: this.$L("图片存储为..."),
copyImage: this.$L("复制图片"),
copyEmailAddress: this.$L("复制电子邮件地址"),
copyLinkAddress: this.$L("复制链接地址"),
copyImageAddress: this.$L("复制图片地址"),
moveToNewWindow: this.$L("将标签页移至新窗口"),
failedToSaveImage: this.$L("图片保存失败"),
theImageFailedToSave: this.$L("图片无法保存"),
});