网站转桌面应用
工具 刘宇帅 5天前 阅读量: 66
这两天工作又比较忙,没看书,没思考,写一篇简单的技术教程。其实我是不想写这种的,因为本身没啥技术含量,只是把写的东西整理一下,即提高不了技术,也没有思考深度,以后要少写,这类还是以笔记的形式记录到博客即可。
最近公司在推jira,但是整体感觉用起来很困难。主要因为是日常浏览器用的会比较多,基本上chrome上都有四五十个tab标签,经常会切到其它tab看东西,然后每次想要找jira的时候都不太好找,所以就想把jira单独打成一个桌面应用,整体操作和心理感受上感觉都简单很多。
electron介绍
Electron是由Github开发,用HTML,CSS和JavaScript来构建跨平台桌面应用程序的一个开源库。 Electron通过将Chromium和Node.js合并到同一个运行时环境中,并将其打包为Mac,Windows和Linux系统下的应用来实现这一目的。
详细教程
新建一个项目并安装electron
electron-builder
两个依赖
mkdir desktopdemo
cd desktopdemo
cnpm init
cnpm i electron --save-dev
cnpm i electron-builder --save-dev
添加构建命令到package.json
"build": {
"appId": "com.example.app",
"mac": {
"target": [
"dmg",
"zip"
]
},
"win": {
"target": [
"nsis",
"zip"
]
}
},
"scripts": {
"start": "electron .",
"dist": "electron-builder"
},
新建index.js
(async () => {
const {app, BrowserWindow, BrowserView, ipcMain, webContents} = require("electron");
const {join} = require("path");
await app.whenReady()
const window = new BrowserWindow({
webPreferences: {
sandbox: false,
nodeIntegration: true,
contextIsolation: false
}
});
await window.loadFile(join(__dirname, "./titlebar.html"));
const browserView = new BrowserView({
webPreferences: {
sandbox: true,
nodeIntegration: false
}
});
window.setBrowserView(browserView);
// const contents = window.webContents;
// contents.openDevTools(); //打开调试工具
const contentBounds = window.getContentBounds();
browserView.setBounds({x: 0, y: 50, width: contentBounds.width, height: contentBounds.height - 30});
browserView.setAutoResize({width: true, height: true});
await browserView.webContents.loadURL("https://www.liuyushuai.com/"); // 更换自己的域名
window.webContents.send("sendId", browserView.webContents.id);
window.webContents.on('did-finish-load', function () {
window.webContents.send("sendId", browserView.webContents.id);
})
browserView.webContents.on("did-navigate", () => {
window.webContents.send("canNav", browserView.webContents.canGoBack(), browserView.webContents.canGoForward());
});
ipcMain.on("goBack", (e, webContentsId) => {
const wc = webContents.fromId(webContentsId);
if (wc && wc.canGoBack()) {
wc.goBack();
}
});
ipcMain.on("goForward", (e, webContentsId) => {
const wc = webContents.fromId(webContentsId);
if (wc && wc.canGoForward()) {
wc.goForward();
}
});
})();
新建titlebar.html
<html>
<body>
<div id="toolbar">
<button id="back" class="button back" disabled>go back</button>
<button id="forward" class="button next" disabled>go forward</button>
</div>
<script src="./renderer.js"></script>
<style>
#toolbar {
height: 50px;
}
a {
margin: 10px;
}
.active {
color:#555 !important;
}
.button {
display: inline-block;
position: relative;
color: #888;
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.8);
text-decoration: none;
text-align: center;
padding: 8px 12px;
font-size: 12px;
font-weight: 700;
font-family: helvetica, arial, sans-serif;
border-radius: 4px;
border: 1px solid #bcbcbc;
-webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12);
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12);
background-image: -webkit-linear-gradient(top, #fff 0%, #efefef 60%, #e1dfe2 100%);
background-image: -moz-linear-gradient(top, #fff 0%, #efefef 60%, #e1dfe2 100%);
background-image: -o-linear-gradient(top, #fff 0%, #efefef 60%, #e1dfe2 100%);
background-image: -ms-linear-gradient(top, #fff 0%, #efefef 60%, #e1dfe2 100%);
background-image: linear-gradient(top, #fff 0%, #efefef 60%, #e1dfe2 100%);
}
.button:hover {
color: #555;
}
.button:active,
.button:active:after,
.button:active:before {
-webkit-box-shadow: none;
box-shadow: none;
/* Back Button */
}
.button.back {
border-left: none;
}
.button.back:after {
content: '';
position: absolute;
height: 50%;
width: 15px;
border-left: 1px solid #bcbcbc;
background-image: -webkit-linear-gradient(top, rgba(255, 255, 255, 0) 0%, #fff 1%, #f0f0f0 100%);
background-image: -moz-linear-gradient(top, rgba(255, 255, 255, 0) 0%, #fff 1%, #f0f0f0 100%);
background-image: -o-linear-gradient(top, rgba(255, 255, 255, 0) 0%, #fff 1%, #f0f0f0 100%);
background-image: -ms-linear-gradient(top, rgba(255, 255, 255, 0) 0%, #fff 1%, #f0f0f0 100%);
background-image: linear-gradient(top, rgba(255, 255, 255, 0) 0%, #fff 1%, #f0f0f0 100%);
left: -5px;
top: 1px;
-webkit-transform: skew(-35deg, 0);
-moz-transform: skew(-35deg, 0);
-o-transform: skew(-35deg, 0);
-ms-transform: skew(-35deg, 0);
transform: skew(-35deg, 0);
}
.button.back:before {
content: '';
position: absolute;
height: 48%;
width: 15px;
border-left: 1px solid #bcbcbc;
bottom: 1px;
left: -5px;
-webkit-transform: skew(35deg, 0);
-moz-transform: skew(35deg, 0);
-o-transform: skew(35deg, 0);
-ms-transform: skew(35deg, 0);
transform: skew(35deg, 0);
background-image: -webkit-linear-gradient(top, #f0f0f0 0%, #efefef 10%, #e1dfe2 100%);
background-image: -moz-linear-gradient(top, #f0f0f0 0%, #efefef 10%, #e1dfe2 100%);
background-image: -o-linear-gradient(top, #f0f0f0 0%, #efefef 10%, #e1dfe2 100%);
background-image: -ms-linear-gradient(top, #f0f0f0 0%, #efefef 10%, #e1dfe2 100%);
background-image: linear-gradient(top, #f0f0f0 0%, #efefef 10%, #e1dfe2 100%);
-webkit-box-shadow: -2px 1px 2px rgba(100, 100, 100, 0.1);
box-shadow: -2px 1px 2px rgba(100, 100, 100, 0.1);
/* Next Button */
}
.button.next {
border-right: none;
}
.button.next:after {
content: '';
position: absolute;
height: 48%;
width: 15px;
border-right: 1px solid #bcbcbc;
background-image: -webkit-linear-gradient(top, #f0f0f0 0%, #efefef 10%, #e1dfe2 100%);
background-image: -moz-linear-gradient(top, #f0f0f0 0%, #efefef 10%, #e1dfe2 100%);
background-image: -o-linear-gradient(top, #f0f0f0 0%, #efefef 10%, #e1dfe2 100%);
background-image: -ms-linear-gradient(top, #f0f0f0 0%, #efefef 10%, #e1dfe2 100%);
background-image: linear-gradient(top, #f0f0f0 0%, #efefef 10%, #e1dfe2 100%);
right: -5px;
bottom: 1px;
-webkit-transform: skew(-35deg, 0);
-moz-transform: skew(-35deg, 0);
-o-transform: skew(-35deg, 0);
-ms-transform: skew(-35deg, 0);
transform: skew(-35deg, 0);
-webkit-box-shadow: 2px 1px 2px rgba(100, 100, 100, 0.1);
box-shadow: 2px 1px 2px rgba(100, 100, 100, 0.1);
}
.button.next:before {
content: '';
position: absolute;
background-image: -webkit-linear-gradient(top, rgba(255, 255, 255, 0) 0%, #fff 1%, #f0f0f0 100%);
background-image: -moz-linear-gradient(top, rgba(255, 255, 255, 0) 0%, #fff 1%, #f0f0f0 100%);
background-image: -o-linear-gradient(top, rgba(255, 255, 255, 0) 0%, #fff 1%, #f0f0f0 100%);
background-image: -ms-linear-gradient(top, rgba(255, 255, 255, 0) 0%, #fff 1%, #f0f0f0 100%);
background-image: linear-gradient(top, rgba(255, 255, 255, 0) 0%, #fff 1%, #f0f0f0 100%);
height: 50%;
width: 15px;
border-right: 1px solid #bcbcbc;
top: 1px;
right: -5px;
-webkit-transform: skew(35deg, 0);
-moz-transform: skew(35deg, 0);
-o-transform: skew(35deg, 0);
-ms-transform: skew(35deg, 0);
transform: skew(35deg, 0);
}
</style>
</body>
</html>
新建 renderer.js
const {ipcRenderer} = require("electron");
const backButton = document.getElementById("back");
const forwardButton = document.getElementById("forward");
let webContentsId = -1;
ipcRenderer.on("sendId", (e, id) => {
webContentsId = id;
});
ipcRenderer.on("canNav", (e, canBack, canForward) => {
backButton.disabled = !canBack;
forwardButton.disabled = !canForward;
backButton.classList = canBack ? "button back active":"button back";
forwardButton.classList = canForward?"button next active":"button next";
});
backButton.onclick = () => {
ipcRenderer.send("goBack", webContentsId);
};
forwardButton.onclick = () => {
ipcRenderer.send("goForward", webContentsId);
};
启动
cnpm start
打包
cnpm run dist
可以看到dist
目录下打包好的包