mirror of
https://github.com/kuaifan/dootask.git
synced 2025-12-13 12:02:51 +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,
|
nativeTheme,
|
||||||
Tray,
|
Tray,
|
||||||
Menu,
|
Menu,
|
||||||
BrowserView,
|
WebContentsView,
|
||||||
BrowserWindow
|
BrowserWindow
|
||||||
} = require('electron')
|
} = require('electron')
|
||||||
|
|
||||||
@ -515,6 +515,9 @@ function createChildWindow(args) {
|
|||||||
contextIsolation: true,
|
contextIsolation: true,
|
||||||
}, webPreferences),
|
}, webPreferences),
|
||||||
}, config)
|
}, config)
|
||||||
|
if (!options.webPreferences.contextIsolation) {
|
||||||
|
delete options.webPreferences.preload;
|
||||||
|
}
|
||||||
if (options.parent) {
|
if (options.parent) {
|
||||||
options.parent = mainWindow
|
options.parent = mainWindow
|
||||||
}
|
}
|
||||||
@ -838,17 +841,16 @@ function createWebTabWindow(args) {
|
|||||||
webTabWindow.show();
|
webTabWindow.show();
|
||||||
|
|
||||||
// 创建 tab 子窗口
|
// 创建 tab 子窗口
|
||||||
const viewOptions = Object.assign({
|
const viewOptions = args.config || {}
|
||||||
useHTMLTitleAndIcon: true,
|
|
||||||
useLoadingView: true,
|
|
||||||
useErrorView: true,
|
|
||||||
}, args.config || {})
|
|
||||||
viewOptions.webPreferences = Object.assign({
|
viewOptions.webPreferences = Object.assign({
|
||||||
preload: path.join(__dirname, 'electron-preload.js'),
|
preload: path.join(__dirname, 'electron-preload.js'),
|
||||||
nodeIntegration: true,
|
nodeIntegration: true,
|
||||||
contextIsolation: true
|
contextIsolation: true
|
||||||
}, args.webPreferences || {})
|
}, args.webPreferences || {})
|
||||||
const browserView = new BrowserView(viewOptions)
|
if (!viewOptions.webPreferences.contextIsolation) {
|
||||||
|
delete viewOptions.webPreferences.preload;
|
||||||
|
}
|
||||||
|
const browserView = new WebContentsView(viewOptions)
|
||||||
if (args.backgroundColor) {
|
if (args.backgroundColor) {
|
||||||
browserView.setBackgroundColor(args.backgroundColor)
|
browserView.setBackgroundColor(args.backgroundColor)
|
||||||
} else if (nativeTheme.shouldUseDarkColors) {
|
} else if (nativeTheme.shouldUseDarkColors) {
|
||||||
@ -885,6 +887,20 @@ function createWebTabWindow(args) {
|
|||||||
if (!errorDescription) {
|
if (!errorDescription) {
|
||||||
return
|
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, {
|
utils.onDispatchEvent(webTabWindow.webContents, {
|
||||||
event: 'title',
|
event: 'title',
|
||||||
id: browserView.webContents.id,
|
id: browserView.webContents.id,
|
||||||
@ -900,6 +916,9 @@ function createWebTabWindow(args) {
|
|||||||
}).then(_ => { })
|
}).then(_ => { })
|
||||||
})
|
})
|
||||||
browserView.webContents.on('did-start-loading', _ => {
|
browserView.webContents.on('did-start-loading', _ => {
|
||||||
|
webTabView.forEach(({id: vid, view}) => {
|
||||||
|
view.setVisible(vid === browserView.webContents.id)
|
||||||
|
})
|
||||||
utils.onDispatchEvent(webTabWindow.webContents, {
|
utils.onDispatchEvent(webTabWindow.webContents, {
|
||||||
event: 'start-loading',
|
event: 'start-loading',
|
||||||
id: browserView.webContents.id,
|
id: browserView.webContents.id,
|
||||||
@ -933,8 +952,9 @@ function createWebTabWindow(args) {
|
|||||||
electronMenu.webContentsMenu(browserView.webContents, true)
|
electronMenu.webContentsMenu(browserView.webContents, true)
|
||||||
|
|
||||||
browserView.webContents.loadURL(args.url).then(_ => { }).catch(_ => { })
|
browserView.webContents.loadURL(args.url).then(_ => { }).catch(_ => { })
|
||||||
|
browserView.setVisible(true)
|
||||||
|
|
||||||
webTabWindow.addBrowserView(browserView)
|
webTabWindow.contentView.addChildView(browserView)
|
||||||
webTabView.push({
|
webTabView.push({
|
||||||
id: browserView.webContents.id,
|
id: browserView.webContents.id,
|
||||||
view: browserView
|
view: browserView
|
||||||
@ -950,15 +970,36 @@ function createWebTabWindow(args) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取当前内置浏览器标签
|
* 获取当前内置浏览器标签
|
||||||
* @returns {Electron.BrowserView|undefined}
|
* @returns {Electron.WebContentsView|undefined}
|
||||||
*/
|
*/
|
||||||
function currentWebTab() {
|
function currentWebTab() {
|
||||||
const views = webTabWindow.getBrowserViews()
|
// 第一:使用当前可见的标签
|
||||||
const view = views.length ? views[views.length - 1] : undefined
|
try {
|
||||||
if (!view) {
|
const item = webTabView.find(({view}) => view?.getVisible && view.getVisible())
|
||||||
return undefined
|
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) {
|
if (!item) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
webTabView.forEach(({id: vid, view}) => {
|
||||||
|
view.setVisible(vid === item.id)
|
||||||
|
})
|
||||||
resizeWebTab(item.id)
|
resizeWebTab(item.id)
|
||||||
webTabWindow.setTopBrowserView(item.view)
|
|
||||||
item.view.webContents.focus()
|
item.view.webContents.focus()
|
||||||
utils.onDispatchEvent(webTabWindow.webContents, {
|
utils.onDispatchEvent(webTabWindow.webContents, {
|
||||||
event: 'switch',
|
event: 'switch',
|
||||||
@ -1032,7 +1075,7 @@ function closeWebTab(id) {
|
|||||||
if (webTabView.length === 1) {
|
if (webTabView.length === 1) {
|
||||||
webTabWindow.hide()
|
webTabWindow.hide()
|
||||||
}
|
}
|
||||||
webTabWindow.removeBrowserView(item.view)
|
webTabWindow.contentView.removeChildView(item.view)
|
||||||
try {
|
try {
|
||||||
item.view.webContents.close()
|
item.view.webContents.close()
|
||||||
} catch (e) {
|
} 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 {
|
.tab-icon {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
width: 18px;
|
width: 16px;
|
||||||
height: 18px;
|
height: 16px;
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -207,8 +207,7 @@ body {
|
|||||||
.tab-title {
|
.tab-title {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
margin-right: 8px;
|
margin: 0 8px;
|
||||||
margin-left: 6px;
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
line-height: 150%;
|
line-height: 150%;
|
||||||
text-overflow: ellipsis;
|
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