关于前端:前端不用Electron也能写Win应用-动手实现一个SwitchHosts程序

56次阅读

共计 6196 个字符,预计需要花费 16 分钟才能阅读完成。

说到前端写 Windows 应用程序,首先想到的肯定是 Electron,这次咱们换一个小众点的工具aardioaardio 是一个很轻量的工具,有着本人的语法, 面向 windows 利用开发,刚好其中也有反对前端利用打包性能。

选型

aardio中波及到 HTML+CSS+JS 的性能。有 Chrome AppElectron,同时还有Sciter.jsHTMLayout 两个 UI 引擎。
一下子就有四种选项,这里按本人摸索的简略总结一下,可能会不太精确:

Chrome App

默认打包进去的应用程序不携带浏览器,程序会启动调用本地的浏览器渲染 (不限于官网的ChromeEdge 以及国产支流 Chromium 内核的浏览器都行),如果都没有会主动装置微软的 Edge(Chromium 版) 浏览器。
劣势是生成体积比拟小(但外部环境不稳固,产生的显示 Bug 可能性也更多),根底大小预计在 800KB 左右(经 UPX 压缩过),前端我的项目迁徙起来不必过多批改就能跑起来。如果要指定环境,也能够在启动代码内指定浏览器门路。

Electron

能够构建 Electron 的利用,Electron自身就是做桌面程序的为什么还须要应用 aardio
看了一下,除了能够利用 aardio 的一些内置的不便性能函数,同时生成的利用体积也是差别很大,软件自带的示例 Electron 我的项目生成文件大略在 800KB 左右(经 UPX 压缩过),作者可能应用了精简版的内核替换了本来的程序。如果只做 Windows 平台利用,这样的打包体积还是很吸引人的。

Sciter.js

这次要是面向桌面开发的一个 UI 渲染引擎,能够利用 HTML+CSS 写界面,将浏览器许多无用性能剔除,只留下 UI 引擎罕用的性能,使得体积尽量玲珑。
本来认为能将整个前端我的项目打包进去,但尝试了一下,如同不行。HTMLCSS 是独自传入的,没方法像是前端那么自在的援用。应用逻辑更像是一个 html 界面就配置一个 Sciter.js 对象,而不是将 html 程序的所有逻辑放到外面去执行。
生成的利用体积也是比拟小的,大略在 2.8MB 左右(经 UPX 压缩过)。看介绍,大部分罕用的 CSS 反对,同时也有一些非凡的语法不便解决界面。

HTMLayout

HTMLayoutSciter.js 的前身,程序体积更小,但反对的 CSS 性能也更加无限。同样也不太实用前端我的项目的打包。
比照了一下 HTMLayoutSciter.js生成利用的体积,利用大略在 1.5MB 左右(经 UPX 压缩过),两者只差了 1.3MB 左右,但放弃的新语法可能要很多,所以这个大部分场景能够不用思考了。

尝试一下

官网有推过一个修改版的 hostsSwitchHelper,应用的就是Chrome App 模式,既然是尝试,那就先选这个模式来试试。

Chrome App模式其实很小白,如果没有与零碎交互的性能,那么简直就是间接将前端我的项目编译,而后导入到开发工具中就能生成一个利用。

先来看看界面:

比拟传统的 IDE 界面,左上角的 Logo 点开,而后点击 新建工程 ,能看到新建窗口。

抉择 Web 界面 栏目,而后抉择第一项 Chrome App,设置好目录就能创立出一个Chrome App 例子了,其中自带曾经能跑起来的代码。
代码量很少,不相熟的能够间接在这个我的项目上做简略批改,就是一个本人的我的项目了。

做一个本人的程序

这是已实现的界面:

前端局部

先从相熟的开始吧,把前端局部先实现。

因为程序不大,于是不应用 Vue 或者 React 了,找了个原生丑陋的 UI 框架LuLu UI,配合TypeScript,打包工具也不要太重的WebPack,咱们选用更加轻量的parcel

其实一开始是间接用 LuLu UI+ 原生 JS,简略的写几个页面,起初对界面细节一直调整(这块重复批改花了不少工夫),以及操作逻辑的优化,总体逻辑绝对简单了起来,于是引入了打包工具,将CSS 换成了 LESSJavaScript 换成了TypeScript,并且分出了目录构造进去。

打包其实只须要编译实现的前端文件,所以前端工程能够随便放在哪儿都行,最初只须要把编译出的文件放到 aardio 设置的目录下就能够了。

至于前端就很一般,常见的建设我的项目,补充款式与逻辑,加上 parcel 自身也很轻量易用,太细节的就不多说了,挑一些次要的说。

敞开翻译提醒

如果不设置,网页默认是英文,关上后 Chrome 会弹出翻译提醒,这个性能对于本地应用程序无意义。设置的话就是标注网页语言为中文,或是简略粗犷在 head 标签里加上这句,禁止应用翻译性能。

<meta name="google" content="notranslate" />
屏蔽影响应用的快捷键

网页的 F12Ctrl+Shift+iCtrl+u 等,万一触碰到会影响应用程序体验,用 JS 代码将这些快捷键禁用。
因为 KeyboardEvent.keyCode 曾经被废除了,这里间接应用 KeyboardEvent.key 判断

  window.onkeydown = window.onkeyup = window.onkeypress = function (event: KeyboardEvent) {
    // 禁止 ctrl+u
    if (event.ctrlKey && event.key.toLowerCase() == 'u') return false;
    // 禁止 ctrl+s
    if (event.ctrlKey && event.key.toLowerCase() == 's') return false;
    // 禁止 ctrl+shift+i
    if (event.ctrlKey && event.shiftKey && event.key.toLowerCase() == 'i') return false;
    // 禁止 F5
    if (event.key == 'F5') return false;
    // 禁止 F12
    if (event.key == 'F12') return false;
  };
屏蔽右键

右键的菜单也有无关动货色,影响应用体验,重点还很难看。如果没有右键性能能够间接屏蔽,这里为了不便加上了右键性能,所以重画了右键菜单键,替换了原生的右键。

  window.oncontextmenu = function (event: MouseEvent) {event.preventDefault();
    show(event); // 外面包含关上本人的菜单层
    return false;
  };
  
  document.addEventListener('click', close); // 敞开右键菜单 close 函数里就是将相应的层暗藏

show的逻辑很简略,获取以后鼠标地位,而后判断窗口是否会溢出,做相应的高度批改,最初将指定的菜单层显示。

/**
 * 显示右键菜单
 * @param {MouseEvent} event
 */
function show(event: MouseEvent) {if (!isNavItem(event)) return;
  // 获取以后鼠标地位
  let mouseX = event.clientX;
  let mouseY = event.clientY;
  // 判断边界值,避免菜单栏溢出可视窗口
  const winHeight = document.documentElement.clientHeight ?? document.body.clientHeight;
  // BUS.contextMenu 是存储的前端菜单 DOM
  if (mouseY > winHeight - BUS.contextMenu.offsetHeight) mouseY = winHeight - BUS.contextMenu.offsetHeight - 10;
  else mouseY = mouseY;

  BUS.contextMenu.style.left = `${mouseX}px`;
  BUS.contextMenu.style.top = `${mouseY}px`;
}

这里减少了一些细节判断,像是编辑器区域不弹出右键,在标签项右键与导航空白区右键显示不同菜单。

调试模式

因为禁用掉开发者工具在调试的时候很麻烦,通过正文代码屏蔽又容易遗记,parcel打包工具同样提供了环境变量。

process.env.NODE_ENV === 'production'
网页元素重渲染

因为没有应用古代框架,这部分起始逻辑很重。像是鼠标右键不同中央显示不同菜单的性能实现起来就会很麻烦,要不然代码就很冗余。于是引入了玲珑快捷的前端模板引擎art-template,一部分操作交给引擎判断,通过增加不同的类名展现不同的状态。

比方鼠标右键点击在标签项上,如果以后的项没有增加 url 参数,则是本地的 Hosts,渲染时会增加disabled 类名,标识禁用此元素。disabled类的 CSS 外围是pointer-events: none;,这样即可让此元素不响应鼠标事件,无需再增加多余的 js 逻辑。

导航栏的以后选中的类名增加、增加新项等操作全副只是在对立的数据中做记录,而后依赖从新渲染一次性替换掉 HTML,防止了写简单简短的DOM 增删逻辑,也简化了代码耦合。

所以我的项目里独自做了一个数据管理的模块。从本来的简略 nav 渲染单文件逻辑开始,到起初因为 UI 逻辑越做越粗疏,这个里也从单文件变成了多文件,尽量把内部操作与纯数据操作隔离。

文本编辑器

如果应用 textarea 标签能够实现多行文本,但没方法提供正文文字的辨别显示,也没方法提供行号、快捷键、搜寻等扩大性能,所以咱们须要一个文本编辑器。

通过筛选比拟常见的代码编辑器有 CodeMirroraceEditormonacoEditorVS Code 的前身),三者中 CodeMirror 体积最小,咱们须要的性能也不要太多,于是就选这个了。

应用办法网上很多,源码中正文也很分明,应用形式就不多提了。

语法色彩

因为咱们的 Hosts 理论只须要给 #号上色,编辑器有相似的语法,但也会将多余的关键字和构造显示出色彩,这时候咱们能够本人批改一个。
简略的翻阅语法源码能发现在 tokenBasereturn中的 token 有对很多信息做匹配,将没有的信息删除,缩小判断逻辑,连带的能够删除几个相干函数代码。之后在底部 CodeMirror.defineMIME 中有自定义许多关键字,对咱们也没用,都能够删除。而后记得改一个新名字,这样就实现了一个咱们专门的语法,导入插件中就能应用了。

主题款式咱们也能够自定义,同样是找一份看的不错的款式,而后把 CSS 代码复制过去,其中有许多状态的款式名称,依据相应名称修色彩即可。

这里我开启了高亮选中行,所以在以后行会有一个蓝色底色,因为我在编辑器文本框背景上又加了一个以后项的类型图标,会导致图标被笼罩,这时候只须要将 div.CodeMirror-selected 的色彩调成半透明模式即可,但因为我背景的透明度调的很低(背景透明度是 0.06,而选中的透明度是 0.8),所以不认真看的话实际上还是有点像是被覆盖住。

快捷键

自身是做切换标签才主动保留的逻辑,但如果用户批改了文本内容,误以为是实时保留而间接敞开软件,这样就会导致批改失落。所以须要加上一个以后文本批改过的标识,于是又在右上角加了一个保留按钮(一个不难看,顺便又加上了刷新与更新近程文件按钮)。

有了按钮,天然的会习惯用 Ctrl+s 去保留文件,好在 CodeMirror 是提供了自定义快捷键的。

extraKeys: {'Ctrl-S': eventTextareaSave, // 这里是自定义的保留逻辑}
网络申请及代理

常见的利用场景是从网络上复制他人整顿好的 Hosts 信息,所以为了不便减少了从网络获取 Hosts 性能。但这种个别须要借助代理性能能力获取到,搜寻网上并没见到 js 能间接设置代理的方法。

这时候就应该将前端不易操作的性能放到 aardio 中,通过 inet.http 库能够间接发动网络申请,同时默认也会走零碎代理设置,齐全满足了目前的性能所需。

aardio 局部

到这里就进入了咱们不是相熟的局部了。aardio语法很像 js,但细节上跟 js 又有差距,所以写起来的时候很容易弄混,要留神一下。

这里说几个看目前代码须要了解的点:
import,是将对应的命名空间导入以后的命名空间,应用的时候能够间接应用。会按 内核库 规范库 用户库 (应用程序 lib 目录)查问引入。
var,申明变量不肯定都要应用var 关键字,如果没应用是默认挂在以后命名空间下的。如果应用了,则作用域是在以后代码块。同时申明变量也只有 var 关键字,不要棘手把 ES6 的关键字用上了。
global,这是默认的全局空间名字,简写是 .. 在代码中常常看到,比方要操作 io 库,能够写成 ..io 调用。
tableaardiotable 是一种类型,相似 js 里的数组和对象,两种类型同时是 table 类型。写法上 keyvalue连贯是用 =,开端完结是用;,这个与 js 差别很大,不小心写错会导致报错,复查错觉无时往往容易因为惯性而疏忽。
多返回值 ,程序是反对多返回值的,用, 分隔,接管返回也是间接用 , 分隔写变量即可接管。
目录环境 ,门路如果是~ 结尾的代表 exe 利用程序运行的当前目录,如果是在测试环境,则是 aardio.exe 主程序的目录。

其余不必写大段逻辑的话,根本也能看懂了。

创立 chrome 程序

main.aardio是程序主入口,在这个文件里写起始逻辑。

import chrome.app; // 导入所需的库
var theApp = chrome.app(); // 创立一个实例
theApp.start(url); // chrome 关上指定的 url

这样就能启动一个 chrome 利用了。

js 与 aardio 交互
theApp.external = {key = function(){// 逻辑};
}

external 外面传入相应的逻辑,前端通过 aardio 组件能够实现调用。

引入前端文件

在左侧新建“虚拟目录”,右侧会呈现设置项,“目录门路”批改成咱们前端的门路,“内嵌资源”要选true,不然无奈生成单文件的应用程序。

最初对着这个虚拟目录单击右键,抉择“同步本地目录”,如果目录内有文件的话会全副显示进去。如果有批改从新生成前端文件的话,也要记得手动同步一次,目录是不会主动刷新的。

编译利用

这样咱们的前端我的项目就能打包成 win 的应用程序了,按 F7 就能一键编译,略微等一儿编译好的利用就生成了,是不是很简略?

Electron 版尝试

aardioElectron做了简化,目前的我的项目能够间接复制到 Electron 工程的 渲染过程 中应用,只有启动代码做相应批改即可。但尝试下来,发现 UI 渲染非常卡顿,不晓得是什么起因。目前性能临时够用,这块等之后有空再理解吧。

结尾

总体应用下来,对于相熟前端以及前端工具链的模式,aardio的界面和文本编辑器很不适应(VS Code上有人做了一个插件,说是能够间接在 VS Code 编译,配置了仍然报错,而且没有格式化,没有智能提醒,反不如原生 IDE 不便)。
文档也绝对比较简单,须要有肯定的急躁,很多中央须要本人从右侧的范例中查找例子学习,如果没有例子,则要从左下角的规范库里,看源代码和智能提醒理解具体有什么性能和如何编写代码。

我的项目源码

具体细节有趣味的话请查阅源码:HostsSwitch
https://github.com/Lnncoco/ho…

正文完
 0