关于IIFE
IIFE是JS中的一个概念,就是立即调用函数表达式。
为什么需要IIFE
我们先用一个简单的例子说一下为什么需要这个IIFE。
新建一个窗口,插入一个WebViewer,打开网页。
插入一个按钮,按钮代码为:
'''Async
Dim
js
As
String
=
<![CDATA[
const a = 100;
const b = 200;
const sum = a + b;
sum;
]]>.Value
Dim
wv
As
WebViewer = e.Form.Controls("WebViewer1").WebViewer
Dim
sum
As
Double
=
Await
wv.ExecuteScriptAsync(js)
MessageBoxA.Show(Sum)
第一次运行会显示计算结果300,第二次运行就会出错,这是因为:
第一次执行时,JS代码在全局作用域中创建了三个变量:a、b、sum。这些变量会一直存在于WebViewer的全局环境中,第二次执行同样的代码时,JS引擎会发现
const a 已经定义过了,于是抛出错误:Identifier 'a' has already been declared(标识符'a'已被声明)。这就是全局变量污染的问题——每次执行的代码都在同一个全局作用域中运行,变量会相互干扰。
当然这里的问题很好解决,不用const,改用var即可。
但除了全局变量污染问题,还可能存在变量覆盖、命名冲突、并行执行、内存泄漏等多种问题。
所以对于Foxtable执行的脚本,建议都封装成IIFE执行,以上面的代码为例:
'''Async
Dim
js
As
String
=
<![CDATA[
(function() {
const a = 100;
const b = 200;
return a + b;
})();
]]>.Value
Dim
wv
As
WebViewer = e.Form.Controls("WebViewer1").WebViewer
Dim
sum
As
Double
=
Await
wv.ExecuteScriptAsync(js)
MessageBoxA.Show(sum)
你现在反复单击按钮,都不会出错了。
IIFE传递参数
IIFE是一个字符串表达式,如果需要传递参数,就是将参数合并到这个字符串表达式中。
例如:
'''Async
Dim
wv
As
WebViewer = e.Form.Controls("WebViewer1").WebViewer
' 传递参数给
IIFE
Dim
a
As
Integer
= 150
Dim
b
As
Integer
= 250
Dim
js
As
String
=
<![CDATA[
(function(a, b) {
const c = 100;
return a + b + c;
})(]]>.Value
& a &
", "
& b &
");"
Dim
sum
As
String
=
Await
wv.ExecuteScriptAsync(js)
MessageBoxA.Show("计算结果"
& sum)
如果你有困惑,可以用MessageBox显示一下合成的js代码,会看待到码为:
(function(a, b) {
const c = 100;
return a + b + c;
})(150, 250);
综合示例
普通用户请忽略这个示例。
本示例可参考示例文件"CaseStudy\WebViewer\调用Foxtable对象.Table"的窗口"可拖动HTML窗口js版"。
这个示例的AfterLoad事件代码如下,这里把窗口拖动功能封装成了一个IIFE表达式,粉红色的部分就是这个表达式。你可以直接复制这段代码到其他纯HTML窗口使用,因为IIFE表达式是闭包的,不用担心和你之前的代码有冲突。唯一要注意的是如果改了窗口标题元素的ID,代码也要做对应的修改,我用蓝色标记出来了:
'''Async
e.Form.BaseForm.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None
'去掉窗口边框
Dim
wv
As
WebViewer = e.Form.Controls("WebViewer1").WebViewer
Await
wv.EnsureCoreWebView2Async(Nothing)
Dim
ft
As
New
FoxLib(wv)
'创建Foxtable库
wv.CoreWebView2.AddHostObjectToScript("ft",
ft)
'注入Foxtable库
wv.CoreWebView2.AddHostObjectToScript("frm",
e.Form)
'单独导入窗口
Dim
html
As
String
=
<![CDATA[
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>订单筛选窗口</title>
<style>
*{margin:0;padding:0;box-sizing:border-box;font-family:微软雅黑;}
html, body{height:100%;width:100%;background:#fff;}
.filter-container{width:100%;height:100%;background:#fff;padding:20px;position:
relative;}
.filter-title{font-size:16px;font-weight:bold;margin-bottom:20px;color:#333;border-bottom:1px
solid #eee;padding-bottom:10px;cursor: move;user-select: none;}
.close-btn{position: absolute;top: 15px;right: 15px;width: 24px;height:
24px;border: none;background: transparent;cursor: pointer;padding: 0;z-index:
10;}
.close-btn::before, .close-btn::after{content: '';position:
absolute;width: 2px;height: 18px;background-color: #999;left: 11px;top: 3px;}
.close-btn::before{transform: rotate(45deg);}
.close-btn::after{transform: rotate(-45deg);}
.close-btn:hover::before, .close-btn:hover::after{background-color:
#dc3545;}
</style>
</head>
<body>
<div class="filter-container">
<button class="close-btn" onclick="closeForm()" title="关闭窗口"></button>
<div class="filter-title" id="dragHandle">筛选</div>
<!--
这里可以添加你的其他表单元素
-->
</div>
<script>
const ft = window.chrome.webview.hostObjects.sync.ft;
const frm = window.chrome.webview.hostObjects.sync.frm;
//
拖动功能
(function() {
const dragHandle = document.getElementById('dragHandle');
let isDragging = false;
let lastX, lastY; //
记录上一次鼠标位置
if (!dragHandle) return;
dragHandle.addEventListener('mousedown', function(e) {
//
只有左键按下时才启用拖动
if (e.button !== 0) return;
isDragging = true;
//
记录起始鼠标位置
lastX = e.screenX;
lastY = e.screenY;
e.preventDefault();
});
document.addEventListener('mousemove', function(e) {
if (!isDragging) return;
try {
//
计算鼠标移动的距离
const currentX = e.screenX;
const currentY = e.screenY;
const deltaX = currentX - lastX; //
水平移动距离
const deltaY = currentY - lastY; //
垂直移动距离
//
如果有移动才调用
if (deltaX !== 0 || deltaY !== 0) {
//
移动窗口(相对距离)
frm.MoveAsync(deltaX, deltaY);
//
更新上一次位置
lastX = currentX;
lastY = currentY;
}
e.preventDefault();
} catch(err) {
console.error('移动窗口失败',
err);
isDragging = false;
}
});
document.addEventListener('mouseup', function(e) {
if (isDragging) {
isDragging = false;
e.preventDefault();
}
});
//
防止选中文本
dragHandle.addEventListener('selectstart', function(e) {
e.preventDefault();
});
})();
function closeForm() {
frm.CloseAsync();
}
</script>
</body>
</html>
]]>.Value
wv.NavigateToString(html)
提示:Foxtale实现可拖动HTML窗口不用这么复杂,一行代码都不需要,参考:可拖动HTML窗口