在C#中,我可以编写如下事件处理程序:
var wdApp = new Microsoft.Office.Interop.Word.Application();
wdApp.DocumentBeforeSave += (Document doc, ref bool saveAsUI, ref bool cancel) => {
//do stuff here
};
在VBA/VB6中,我可以使用静态事件处理:
Dim WithEvents wdApp As Word.Application
Private Sub wdApp_DocumentBeforeSave(ByVal Doc As Document, SaveAsUI As Boolean, Cancel As Boolean)
'do stuff here
End Sub
我更喜欢使用动态事件处理。然而,在JScript中,即使使用以下语法的静态事件处理:
var wdApp = new ActiveXObject('Word.Application');
wdApp.Visible = true;
function wdApp::Quit() {
window.alert('Quit');
};
它失败了:
0x800a138f-JScript运行时错误:需要对象
此外,静态事件处理是VBA/VB6中的一个选项,因为声明可以标记为Private
。但是,在JScript中,变量和处理程序都必须在全局作用域中声明。
两个问题:
如何在HTA环境中使用JScript处理Automation创建的对象的事件(注意:我知道在WSH中使用传递给
CreateObject
的前缀和名为wdApp_Quit
的函数是可能的,但我正在寻找HTA解决方案。)如何在不污染全球范围的情况下做到这一点
这里有一个老问题。
错误似乎是因为
-
在Javascript/JScript中,在初始化变量之前,首先对函数声明进行求值。就好像代码是这样写的:
var wdApp; function wdApp::Quit() { ... } wdApp = new ActiveXObject('Word.Application');
-
Microsoft JScript解析器将特殊命名的声明(使用
::
)解释为将函数附加为事件处理程序的指令。 -
但在声明时,处理程序不能附加到
wdApp
引用的对象,因为此时的wdApp
仍然是undefined
。因此,出现了错误。
解决方案是在初始化wdApp
之后强制计算函数声明。这可以通过1的三种方式之一实现:
-
由于函数声明仅被提升到函数范围内,因此将函数声明包装在IIFE:中
var wdApp = new ActiveXObject('Word.Application'); (function() { function wdApp::Quit() { //do stuff here } })();
-
使用某种字符串创建声明->代码机制——
eval
、带字符串的setTimeout
、window.execScript
或new Function
:var wdApp = new ActiveXObject('Word.Application'); eval('function wdApp::Quit() { ... }`);
-
初始化当前
SCRIPT
块之前的变量。ScriptingEvents文章中的大多数示例都是通过在SCRIPT
块之前的某个元素上设置id
属性来实现这一点的:
<object progid="ordersystem.clsorder" id="myorder" events="true"/> <script language="jscript"> function myorder::onNew() { WScript.Echo("new order received from myorder") } //...
,但这也可以使用多个SCRIPT
块来完成:
<SCRIPT>
var wdApp = new ActiveXObject('Word.Application');
</SCRIPT>
<SCRIPT>
function wdApp::Quit() {
//do stuff here
}
</SCRIPT>
就污染全局命名空间而言,只有第三个变体要求wdApp
在全局命名空间中;其他两种变体可以封装在IIFE中。
1.从技术上讲,IE和HTAs下有第四种方式,但它涉及非标准HTML,而不是非标准Javascript;但是,只有使用HTMLOBJECT
标记而不是new ActiveXObject( ... )
声明对象时,才能使用它
<script for="wdApp" event="Quit">
//do stuff here
</script>