IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> 放弃 Electron,拥抱 WebView2,JavaScript 快速开发独立 EXE 程序 -> 正文阅读

[JavaScript知识库]放弃 Electron,拥抱 WebView2,JavaScript 快速开发独立 EXE 程序

Electron 不错,但也不是完美的。
Electron 带来了很多优秀的桌面软件,但并不一定总是适合我们的需求。

多个选择总是好事!

? 我使用 Electron 遇到的一些麻烦

1、Electron 太大了!

2、每一个 Electron 写的软件都要重复地带一个 Electron …… 升级与分发都不方便。

3、Electron 不方便嵌入其他窗口界面,与其他语言、技术融合不易。

4、并不是所有桌面软件都需要 Electron 的跨平台特性。macOS , Linux 的桌面系统市场份额小于被遗忘的 Windows 8 ,如果软件只是在 Windows 平台运行,并且需要大量与专用系统 API 交互,跨平台反而是不必要的负担。

5、我曾经在 aardio 中封装了一个 electron 扩展库,然后我在写这个扩展库的时候,当时看到的还是 remote 真香 …… 然后我为这个扩展库写了个很大的 JS 文件就用到了 remote。可是等我写完没多久, 就看到 remote 被 Electron 抛弃了,remote 会慢一万倍 ,各种缺陷 ……

? WebView2 的优势

1、WebView2 基于性能强悍的 Edge(Chromium) 内核。

2、调用 WebView2 生成的软件体积很小。所有基于 WebView2 的软件可以共享同一个 WebView2 组件。Win11 已经内置 WebView2 组件,其他操作系统也可以快速地自动安装 WebView2 。

3、WebView2 接口非常简洁,嵌入其他窗口界面也非常方便。

总结一句话就是:WebView2 简单、好用、生成软件体积小。

aardio 标准库中的 web.view 就是基于 WebView2。WebView2 的接口是如此简洁,所以我写的这个库也只有很少的代码。因为 aardio 可以将网页自动内嵌到独立 EXE 文件,就可以非常方便地生成独立 EXE 程序。

? 一个最简单的程序演示

下面我们用 aardio 调用 web.view (WebView2)写一个最简单的程序:

import win.ui;
/*DSG{{*/
mainForm = win.form(text="WebView2")
mainForm.add(
btnCallJs={cls="button";text="调用 JS 函数";left=461;top=395;right=726;bottom=449;note="点这里调用 JavaScript  函数";z=1};
custom={cls="custom";left=17;top=21;right=730;bottom=356;z=2}
)
/*}}*/

//创建浏览器组件
import web.view;
var wb = web.view(mainForm.custom);

//导出本地函数给网页 JavaScript
wb.external = {
	getComputerName = function(){
		return sys.getComputerName();
	}
}
import sys;

//写入网页 HTML
wb.html = /**
<html>
<head>
    <script> 
    (async ()=>{ 
    	var n = await aardio.getComputerName();
    	alert(n);
    })()
    </script>
</head>
<body>
**/

//响应按钮事件
mainForm.btnCallJs.oncommand = function(id,event){
	//调用 JS 函数
	wb.xcall("document.write","测试")
}

mainForm.show();
win.loopMessage();

对,这就是一个完整程序的源代码,可以一键生成独立 EXE 文件。

? 入门

首先点选 「aardio 主菜单 > 新建工程 > 窗口程序 > 空白工程」,然后点击「创建工程」。
在这里插入图片描述

如果熟悉网页前端开发,也可以点击 「 新建工程 > Web 界面 > WebView2 」创建工程。

双击工程入口代码 main.aardio 打开主窗口,自「界面控件」中拖一个 「调用 JS 函数」的按钮上去,再拖一个 custom 控件到窗体上 —— 用来嵌入网页

在这里插入图片描述
然后切换到代码视图,添加以下代码创建网页浏览器:

import web.view;
var wb = web.view(mainForm.custom);

web.view 的第 1 个参数指定要嵌入 WebView2 的窗口对象,该参数可以是 mainForm.custom 这样的控件窗口,也可以是 mainForm 这样的窗体对象。

在这里插入图片描述

下面使用

wb.html = "<html></html>"

就可以写网页 HTML 代码了。

或者使用

wb.go("网址")

可以打开指定的网页。

使用

import wsock.tcp.simpleHttpServer;
wb.go("\res\index.html");

可以打开资源目录的网页,支持SPA 单页应用。资源目录可以嵌入 EXE 生成 独立 EXE 文件,放心不用多写其他代码。

在这里插入图片描述

添加下面的代码导出 external 对象给网页 JavaScript :

//导出本地函数给网页 JavaScript
wb.external = {
	getComputerName = function(){
		return sys.getComputerName();
	}
}

import sys;

在网页 JavaScript 里可以调用上面导出的 external 对象,不过在 JavaScript 里要用 aardio 这个名字表示 external 对象,网页代码如下:

wb.html = /**
<html>
<head>
    <script> 
    (async ()=>{ 
    	var n = await aardio.getComputerName();
    	alert(n);
    })()
    </script>
</head>
<body>
**/

注意在 aardio 中 /* 注释 */ 可以作为字符串赋值给其他变量。

要注意所有 aardio 对象在 JavaScript 中都是异步 Promise 对象。如上在 async 函数体内可以愉快地使用 await 调用 aardio 函数 —— 这非常方便。

我们在窗体设计视图双击「调用 JS 函数」按钮,这会切换到代码视图,并自动添加以下回调函数:

mainForm.btnCallJs.oncommand = function(id,event){
	
}

用户点击按钮时就会调用上面的函数。

小改一下添加 aardio 代码调用 JavaScript 函数:

//响应按钮事件
mainForm.btnCallJs.oncommand = function(id,event){
	//调用 JS 函数
	wb.xcall("document.write","测试")
}

很简单,一个程序就写好了。可以在 aardio 中点击「运行」按钮直接运行代码,也可以点击「发布」按钮直接生成 EXE 文件。

在这里插入图片描述

? 如何将网页显示在窗体的指定位置?并且支持自动缩放?

web.view() 构造函数的第 1 个嵌入窗口参数可以是 win.form 对象(独立窗口),也可以是 custom, static 这样的普通控件对象。例如前面的例子就是将 WebView2 嵌入 custom 控件:

import web.view;
var wb = web.view(mainForm.custom);

aardio 中的所有控件都可以非常方便的支持自动缩放。只要简单地在窗体设计器中选定控件,然后在「属性」面板设置「固定边距」、「自适应大小」这些属性就可以。

在这里插入图片描述

一个更简单的方法是在窗体设计器上点右键,然后在弹出菜单中点击「九宫格缩放布局」—— aardio 将会自动设置所有控件的自适应缩放属性。

在这里插入图片描述

至于网页内容自适应排版很简单,不需要在 aardio 中编写代码。

? 使用 wb.export 导出 aardio 函数到 Javascript

前面我们介绍过使用 external 导出 aardio 函数到网页 JavaScript 。我们还可以用 wb.export 导出 aardio 函数,先看例子:

import web.view;
var wb = web.view(mainForm.custom);

wb.export({
	alert = function(msg){
		winform.msgbox(msg) 
	};
	nativeAdd = function(a,b){ 
		return a + b; 
	}
})

注意:

1、wb.export() 导出的是 JavaScript 全局函数。

2、wb.export() 导出的函数在 JavaScript 中同样是异步 Promise 对象。

3、wb.export() 导出的 Javascript 全局函数, 使用 JSON 自动转换调用参数和返回值,可以更好的兼容只能支持纯 aardio 对象 / 纯 JavaScript 对象的代码。

4、wb.export() 导出的函数内部禁止调用 wb.doScript 或 wb.eval 执行Javascript 。

wb.external 内部是调用 wb.exportHostObject() 导出 aardio 对象,中间不需要经过 JSON 自动转换。

? 示例:网页 JavaScript 调用本地 Ping 命令

我经常被问到几个类似的问题:

1、JavaScript 的异步函数太麻烦了,怎样把他搞成同步的,不用 await ,不用 async 。

2、JavaScript 的异步函数太好用了,怎样在 aardio 中也这样搞,如何在 aardio 里 await 。

其实同步有同步的优势,异步有异步的好处,扬长避短是智慧,倒行逆施最累人。下面我们一起来写一个在 WebView2 中调用本地 Ping 命令的小程序体验一下。


第一步:创建窗口。

import win.ui;
var winform = win.form(text="Ping")

第二步:基于窗口创建 WebView2 浏览器组件。

import web.view;
var wb = web.view(winform);

第三步:使用 external 对象导出 JavaScript 可以调用的本地函数。

import process.popen;
wb.external = {
  ping = function(domain){
    
    var prcs = process.popen("ping "+ domain);
    for( all,out,err in prcs.each() ){
        wb.invoke("document.body.insertAdjacentText",'beforeend',all); 
    }
    
    return "恭喜,事做好了!"
  } 
}

在 JavaScript 里用 aardio.ping() 就可以直接调用上面的 external.ping() 函数了。

第四步:下面在网页里写 JavaScript 来调用 aardio 函数。

wb.html = /**
<body style="white-space: pre;"><script>
doSomething = async() => {
    var result = await aardio.ping('www.baidu.com');
    document.body.insertAdjacentText('beforeend',result);
};
</script>
<button  οnclick="doSomething()">开始干活了</ping>
**/

就这么短短几句,一个简单的程序就完成了,请看运行效果:

在这里插入图片描述

上面程序的完整 aardio 源代码如下:

//创建窗口
import win.ui;
var winform = win.form(text="Ping")

//嵌入浏览器组件
import web.view;
var wb = web.view(winform);

//导出 aardio 函数到 JavaScript
wb.external = {
	ping = function(domain){
		
		//同步有同步的优势,扬长避短是智慧,倒行逆施最累人。 
		var prcs = process.popen("ping "+ domain);
		for( all,out,err in prcs.each() ){
		    wb.invoke("document.body.insertAdjacentText",'beforeend',all); 
		}
		
		return "恭喜,事做好了!"
	} 
}
import process.popen;

//写入网页 HTML
wb.html = /**
<body style="white-space: pre;"><script>
doSomething = async() => {
	
	//异步有异步的好处,扬长避短是智慧,倒行逆施最累人。
  	var result = await aardio.ping('www.baidu.com');
  	document.body.insertAdjacentText('beforeend',result);
};
</script>
<button  οnclick="doSomething()">开始干活了</ping>
**/

//显示窗口
winform.show();

//启动界面消息循环
win.loopMessage();

? aardio 调用 JS 函数

在 aardio 中可以使用 wb.doScript() , wb.eval() , wb.xcall() 等函数调用网页 JavaScript ,下面看一个在 aardio 中调用 xterm.js 的简单例子:

import win.ui;
var winform = win.form(text="xterm")

import web.view;
var wb = web.view(winform);

wb.html = /**
<!DOCTYPE html> 
<head>
  <meta charset="UTF-8">
  <title></title>
  <link rel="stylesheet" href="https://unpkg.com/xterm@4.13.0/css/xterm.css">
  <script src="https://unpkg.com/xterm@4.13.0/lib/xterm.js"></script>
</head>
<body style="height:100vh;"> 
  <script>
    let term  = new Terminal();
    term.open(document.body);
    term.write('\x1b[31m红色字体\x1b[37m测试')
  </script>
</body>
</html>
**/

wb.xcall("term.write",'\e[32m绿色字体');

winform.show();
win.loopMessage();

? 无边框窗口:用网页实现窗口标题栏

「无边框窗口」指的是去掉独立窗体默认的边框与标题栏,然后由程序自行定制边框与标题栏。

aardio 做这事还是很容易的,首页在窗体属性中指定「边框」属性为 none。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uaoT9XMG-1662478572992)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/dff6603dbcad4f92bdf4748b6a759202~tplv-k3u1fbpfcp-zoom-1.image)]

这样直接运行后显示的窗体就没有边框和标题栏了( 按 Alt + F4 关闭窗口 )。

然后添加下面的代码就可以为窗体添加标题栏、标题栏按钮、阴影边框、并支持拖动边框缩放:

import win.ui.simpleWindow;
win.ui.simpleWindow(winform);

win.ui.simpleWindow 的源码很简单,参考其源码也可以自己编写新的库定制边框与标题栏。

这里我们不用上面的方法,而是用网页实现标题栏。

我们知道网页绘制一个标题栏与标题栏按钮很简单,难点在于怎么在网页里控制窗口。我们先学习几个专用于无边框窗口的 aardio 函数:

winform.hitMax() //模拟点击最大化按钮
winform.hitMin() //模拟点击最小化按钮
winform.hitClose() //模拟点击关闭按钮
winform.hitCaption() //拖动标题栏

下面写个简单的例子,先看下运行效果:

在这里插入图片描述

WebView2 无边框窗口示例完整源码如下:

import win.ui;
/*DSG{{*/
var winform = win.form(text="无边框窗口";right=759;bottom=469;bgcolor=16777215;border="none")
winform.add()
/*}}*/

import web.view;
var wb = web.view(winform);
 
//导出为 Javascript 中的 aardio 对象
wb.external = { 
	close = function(){
		winform.close();
	};
	hitCaption = function(){
		winform.hitCaption();
	};
	hitMin = function(){
		winform.hitMin();
	};
	hitMax = function(){
		return winform.hitMax();
	};
}

wb.html = /**
<!doctype html>
<html>
<head>
    <meta charset="utf-8">
	<style type="text/css">
	html {
    	margin: 0px;
    	padding: 0px; 
		background-color: #202020; 
	}
	
	#title-bar {
		height: 32px;	
		padding: 0px;
    	margin: 0px;
	}
	
	#title-bar .caption {
		position: fixed;
		top: 0px;
		left: 0px;	
		width: 100%;
		padding-left: 10px;
		color: #ADADAD;
		line-height: 32px;
		font-size: 14px;
		cursor: default;
		user-select:none;
	}
	
	#title-bar .buttons {
		position: fixed;
		top: 1px;
		right: 1px;	
	}
	
	#title-bar button {
		font: 14px Marlett ;
		color: #F5F5F5;
		background-color: transparent;
		border: none;
		height: 28px;
		width: 28px;  
	}
	 
	#title-bar button:hover {
		background-color: #FF4500;
	}
	
	#title-bar button:active {
		background-color: #B0451E;
		color: #C5C5C5;
	}
	
	#main {
		padding: 12px;	
		color: #C0C0C0;
	}
	 
    </style>
    <script type="text/javascript">  
    
    </script>
</head>
  <body>
    <div id="title-bar" >
      <div class="caption" οnmοusedοwn="aardio.hitCaption()">按住这里调用 aardio.hitCaption() 拖动窗口 </div>
      <div class="buttons">
        <button id="min-btn" οnclick="aardio.hitMin()">0</button>
        <button id="max-btn"  οnclick="aardio.hitMax()">1</button>
        <button id="close-btn" οnclick="aardio.close()">r</button>
      </div>
    </div>
    <div id="main">
  	  1、请指定窗体「边框」属性为 none ,创建无边框窗口。<br />
  	  2、调用 win.ui.shadow(winform) 创建阴影边框<br />
    </div>
    <script src="default.js"></script>
  </body>
</html>
**/ 

//添加阴影边框
import win.ui.shadow;
win.ui.shadow(winform);

//设置窗口缩放范围
import win.ui.minmax;
win.ui.minmax(winform);

//切换最大化、还原按钮
winform.adjust = function( cx,cy,wParam ) {
	if( wParam == 0x2/*_SIZE_MAXIMIZED*/ ){ 
		wb.doScript(`document.getElementById("max-btn").innerText="2";`)
	}
	elseif( wParam == 0x0/*_SIZE_RESTORED*/ ){
		wb.doScript(`document.getElementById("max-btn").innerText="1";`)
	} 
};
			
winform.show();
win.loopMessage();

以上源码来自 aardio 自带范例 > Web 界面 > web.view :

在这里插入图片描述

WebView2 + 前端工程

如果熟悉网页前端开发,也可以点击 「 新建工程 > Web 界面 > WebView2 」创建工程。

在这里插入图片描述

运行创建的范例工程会显示帮助:

在这里插入图片描述

这些熟悉前端的一看就懂,就不多说了。

注意 WebView2 默认工程的「网页源码」这个目录的「内嵌资源」属性为 false —— 也就是说发布后的 EXE 文件不会包含这个目录。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7D009BWp-1662478572995)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/4dfeab72261542b085e92ff376a5bf3e~tplv-k3u1fbpfcp-zoom-1.image)]

而工程中的「网页」目录「内嵌资源」属性为 true —— 也就是说发布后的 EXE 文件会包含这个目录。

在这里插入图片描述

「网页」目录「本地构建」属性为 true —— 这指的是该目录下的文件会无条件添加到发布 EXE 文件中(不必添加到工程 )。

其他浏览器组件

aardio 中的浏览器组件非常多,用法与 web.view 基本都类似。aardio 甚至可以调用操作系统已安装的 Chrome,Edge 等浏览器写软件界面。

请参考「 aardio 自带范例 > Web 界面」:

在这里插入图片描述

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-09-13 11:05:12  更:2022-09-13 11:08:38 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 9:49:08-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码