mirror of
https://github.com/kuaifan/dootask.git
synced 2025-12-11 10:33:54 +00:00
perf: 优化错误页
This commit is contained in:
parent
bb83875c99
commit
f534f012d2
75
electron/electron.js
vendored
75
electron/electron.js
vendored
@ -23,7 +23,7 @@ const {
|
||||
nativeTheme,
|
||||
Tray,
|
||||
Menu,
|
||||
BrowserView,
|
||||
WebContentsView,
|
||||
BrowserWindow
|
||||
} = require('electron')
|
||||
|
||||
@ -515,6 +515,9 @@ function createChildWindow(args) {
|
||||
contextIsolation: true,
|
||||
}, webPreferences),
|
||||
}, config)
|
||||
if (!options.webPreferences.contextIsolation) {
|
||||
delete options.webPreferences.preload;
|
||||
}
|
||||
if (options.parent) {
|
||||
options.parent = mainWindow
|
||||
}
|
||||
@ -838,17 +841,16 @@ function createWebTabWindow(args) {
|
||||
webTabWindow.show();
|
||||
|
||||
// 创建 tab 子窗口
|
||||
const viewOptions = Object.assign({
|
||||
useHTMLTitleAndIcon: true,
|
||||
useLoadingView: true,
|
||||
useErrorView: true,
|
||||
}, args.config || {})
|
||||
const viewOptions = args.config || {}
|
||||
viewOptions.webPreferences = Object.assign({
|
||||
preload: path.join(__dirname, 'electron-preload.js'),
|
||||
nodeIntegration: true,
|
||||
contextIsolation: true
|
||||
}, args.webPreferences || {})
|
||||
const browserView = new BrowserView(viewOptions)
|
||||
if (!viewOptions.webPreferences.contextIsolation) {
|
||||
delete viewOptions.webPreferences.preload;
|
||||
}
|
||||
const browserView = new WebContentsView(viewOptions)
|
||||
if (args.backgroundColor) {
|
||||
browserView.setBackgroundColor(args.backgroundColor)
|
||||
} else if (nativeTheme.shouldUseDarkColors) {
|
||||
@ -885,6 +887,20 @@ function createWebTabWindow(args) {
|
||||
if (!errorDescription) {
|
||||
return
|
||||
}
|
||||
// 主框架加载失败时,展示内置的错误页面
|
||||
if (isMainFrame) {
|
||||
const originalUrl = validatedURL || args.url || ''
|
||||
const filePath = path.join(__dirname, 'render', 'tabs', 'error.html')
|
||||
browserView.webContents.loadFile(filePath, {
|
||||
query: {
|
||||
id: String(browserView.webContents.id),
|
||||
url: originalUrl,
|
||||
code: String(errorCode),
|
||||
desc: errorDescription,
|
||||
}
|
||||
}).then(_ => { }).catch(_ => { })
|
||||
return
|
||||
}
|
||||
utils.onDispatchEvent(webTabWindow.webContents, {
|
||||
event: 'title',
|
||||
id: browserView.webContents.id,
|
||||
@ -900,6 +916,9 @@ function createWebTabWindow(args) {
|
||||
}).then(_ => { })
|
||||
})
|
||||
browserView.webContents.on('did-start-loading', _ => {
|
||||
webTabView.forEach(({id: vid, view}) => {
|
||||
view.setVisible(vid === browserView.webContents.id)
|
||||
})
|
||||
utils.onDispatchEvent(webTabWindow.webContents, {
|
||||
event: 'start-loading',
|
||||
id: browserView.webContents.id,
|
||||
@ -933,8 +952,9 @@ function createWebTabWindow(args) {
|
||||
electronMenu.webContentsMenu(browserView.webContents, true)
|
||||
|
||||
browserView.webContents.loadURL(args.url).then(_ => { }).catch(_ => { })
|
||||
browserView.setVisible(true)
|
||||
|
||||
webTabWindow.addBrowserView(browserView)
|
||||
webTabWindow.contentView.addChildView(browserView)
|
||||
webTabView.push({
|
||||
id: browserView.webContents.id,
|
||||
view: browserView
|
||||
@ -950,15 +970,36 @@ function createWebTabWindow(args) {
|
||||
|
||||
/**
|
||||
* 获取当前内置浏览器标签
|
||||
* @returns {Electron.BrowserView|undefined}
|
||||
* @returns {Electron.WebContentsView|undefined}
|
||||
*/
|
||||
function currentWebTab() {
|
||||
const views = webTabWindow.getBrowserViews()
|
||||
const view = views.length ? views[views.length - 1] : undefined
|
||||
if (!view) {
|
||||
return undefined
|
||||
// 第一:使用当前可见的标签
|
||||
try {
|
||||
const item = webTabView.find(({view}) => view?.getVisible && view.getVisible())
|
||||
if (item) {
|
||||
return item
|
||||
}
|
||||
} catch (e) {}
|
||||
// 第二:使用当前聚焦的 webContents
|
||||
try {
|
||||
const focused = webContents.getFocusedWebContents?.()
|
||||
if (focused) {
|
||||
const item = webTabView.find(it => it.id === focused.id)
|
||||
if (item) {
|
||||
return item
|
||||
}
|
||||
}
|
||||
} catch (e) {}
|
||||
// 兜底:根据 children 顺序选择最上层的可用视图
|
||||
const children = webTabWindow.contentView.children || []
|
||||
for (let i = children.length - 1; i >= 0; i--) {
|
||||
const id = children[i]?.webContents?.id
|
||||
const item = webTabView.find(it => it.id === id)
|
||||
if (item) {
|
||||
return item
|
||||
}
|
||||
}
|
||||
return webTabView.find(item => item.id == view.webContents.id)
|
||||
return undefined
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1011,8 +1052,10 @@ function activateWebTab(id) {
|
||||
if (!item) {
|
||||
return
|
||||
}
|
||||
webTabView.forEach(({id: vid, view}) => {
|
||||
view.setVisible(vid === item.id)
|
||||
})
|
||||
resizeWebTab(item.id)
|
||||
webTabWindow.setTopBrowserView(item.view)
|
||||
item.view.webContents.focus()
|
||||
utils.onDispatchEvent(webTabWindow.webContents, {
|
||||
event: 'switch',
|
||||
@ -1032,7 +1075,7 @@ function closeWebTab(id) {
|
||||
if (webTabView.length === 1) {
|
||||
webTabWindow.hide()
|
||||
}
|
||||
webTabWindow.removeBrowserView(item.view)
|
||||
webTabWindow.contentView.removeChildView(item.view)
|
||||
try {
|
||||
item.view.webContents.close()
|
||||
} catch (e) {
|
||||
|
||||
7
electron/render/tabs/assets/css/style.css
vendored
7
electron/render/tabs/assets/css/style.css
vendored
@ -159,8 +159,8 @@ body {
|
||||
.tab-icon {
|
||||
display: inline-block;
|
||||
flex-shrink: 0;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
@ -207,8 +207,7 @@ body {
|
||||
.tab-title {
|
||||
display: inline-block;
|
||||
flex: 1;
|
||||
margin-right: 8px;
|
||||
margin-left: 6px;
|
||||
margin: 0 8px;
|
||||
overflow: hidden;
|
||||
line-height: 150%;
|
||||
text-overflow: ellipsis;
|
||||
|
||||
157
electron/render/tabs/error.html
Normal file
157
electron/render/tabs/error.html
Normal file
@ -0,0 +1,157 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>LOAD FAILED</title>
|
||||
<style>
|
||||
:root {
|
||||
--bg: #ffffff;
|
||||
--fg: #1f2328;
|
||||
--muted: #6a737d;
|
||||
--border: #e1e4e8;
|
||||
--btn: #84c56a;
|
||||
--btn-fg: #ffffff;
|
||||
--btn-outline: #d0e2ff;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--bg: #0D0D0D;
|
||||
--fg: #e6edf3;
|
||||
--muted: #9aa7b2;
|
||||
--border: #30363d;
|
||||
--btn: #84c56a;
|
||||
--btn-fg: #ffffff;
|
||||
--btn-outline: #84c56a44;
|
||||
}
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
background: var(--bg);
|
||||
color: var(--fg);
|
||||
font: 14px/1.5 -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica, Arial, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
}
|
||||
|
||||
.card {
|
||||
width: min(680px, calc(100% - 32px));
|
||||
padding: 20px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin: 0 0 12px;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0 0 12px;
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
code {
|
||||
background: var(--btn-outline);
|
||||
padding: 2px 6px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
margin-bottom: 8px;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.url {
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.actions {
|
||||
margin-top: 14px;
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
button {
|
||||
appearance: none;
|
||||
border: 1px solid var(--btn);
|
||||
background: var(--btn);
|
||||
color: var(--btn-fg);
|
||||
padding: 8px 24px;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
button.secondary {
|
||||
background: transparent;
|
||||
color: var(--fg);
|
||||
border-color: var(--border);
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
function qs(key) {
|
||||
return new URLSearchParams(location.search).get(key) || ''
|
||||
}
|
||||
|
||||
function setText(id, text) {
|
||||
var el = document.getElementById(id);
|
||||
if (el) {
|
||||
el.textContent = text
|
||||
}
|
||||
}
|
||||
|
||||
function retry() {
|
||||
var u = qs('url');
|
||||
if (u) {
|
||||
location.href = u
|
||||
}
|
||||
}
|
||||
|
||||
function closeTab() {
|
||||
window.close()
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
setText('url', qs('url'))
|
||||
setText('code', qs('code'))
|
||||
setText('desc', qs('desc'))
|
||||
})
|
||||
</script>
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline';">
|
||||
<meta name="color-scheme" content="light dark">
|
||||
<meta name="referrer" content="no-referrer">
|
||||
<meta name="robots" content="noindex">
|
||||
<meta name="format-detection" content="telephone=no,email=no,address=no">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="mobile-web-app-capable" content="yes">
|
||||
<meta name="theme-color" content="#00000000">
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
||||
<meta name="apple-mobile-web-app-title" content="Load Error">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="card">
|
||||
<h1>LOAD FAILED</h1>
|
||||
<div class="row">URL: <span id="url" class="url"></span></div>
|
||||
<div class="row">Error code: <code id="code"></code></div>
|
||||
<p id="desc"></p>
|
||||
<div class="actions">
|
||||
<button onclick="retry()">Retry</button>
|
||||
<button class="secondary" onclick="closeTab()">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Loading…
x
Reference in New Issue
Block a user