You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

TwinCAT HMI TE2000 HtmlHost中JS文件模块化导入问题求助

TwinCAT HMI TE2000 HtmlHost 脚本拆分问题

我正在为TwinCAT HMI TE2000的HtmlHost编写JS脚本,当前单个HtmlHost对应一份脚本,但画布绘制功能的代码量已过大,希望将drawGrid这类函数拆分至其他文件,仅在主文件中调用redrawCanvas函数。

尝试了ES模块方案但未成功,相关代码及报错如下:

内容区域代码

<div id="MAIN" data-tchmi-type="TcHmi.Controls.System.TcHmiContent" data-tchmi-top="0" data-tchmi-left="0" data-tchmi-width="100" data-tchmi-height="100" data-tchmi-width-unit="%" data-tchmi-height-unit="%" data-tchmi-creator-viewport-width="1152" data-tchmi-width-mode="Value" data-tchmi-height-mode="Value" data-tchmi-creator-viewport-height="972">


    <div id="HtmlHostId" data-tchmi-type="TcHmi.Controls.System.TcHmiHtmlHost" data-tchmi-height="100" data-tchmi-height-unit="%" data-tchmi-left="0" data-tchmi-left-unit="px" data-tchmi-top="0" data-tchmi-top-unit="px" data-tchmi-width="100" data-tchmi-width-unit="%">
        <!-- HEADER -->
        <meta charset="utf-8">
        <link rel="stylesheet" href="/static/customStyle.css">

        <!-- BODY -->
        <div id="testDivId"></div>
        <script src="/static/mainTest.js" type="module"></script>

    </div>
</div>

mainTest.js代码

// Keep these lines for a best effort IntelliSense in the editor.
/// <reference path="./../../../Packages/Beckhoff.TwinCAT.HMI.Framework.14.3.500/runtimes/native1.12-tchmi/TcHmi.d.ts" />
if (!window.testScriptInitialized) {
  (function setTestScript(){
    const testDivId document.getElementById('testDivId');

    if (!testDivId ){
      setTimeout(setTestScript, 100);
      console.log('HtmlHost not initialized, setting timeout');
      return;
    }
    console.log('HtmlHost initialized, running setTestScript');
    import {
      testvarWriter
    } from './testvarFunction.js'
    testvarWriter();
    console.log(testvar1, testvar2);

    window.testScriptInitialized= true;
    console.log('setTestScript completed');
})();
}

testvarFunction.js代码

// Keep these lines for a best effort IntelliSense in the editor.
/// <reference path="./../../../Packages/Beckhoff.TwinCAT.HMI.Framework.14.3.500/runtimes/native1.12-tchmi/TcHmi.d.ts" />


export function testvarWriter() {
const testvar1 = 'hello, i a testvar1';
const testvar2 = 'itsa me, testvar2';
}

控制台报错日志

VM41047 mainTest.js:36 Uncaught SyntaxError: Cannot use import statement outside a module (at VM41047 mainTest.js:36:9)
testvarFunction.js:5 Uncaught SyntaxError: Unexpected token 'export' (at testvarFunction.js:5:1)
mainTest.js:36 Uncaught SyntaxError: Unexpected token '{' (at mainTest.js:36:16)

目前仅能依赖辅助文件先于主文件加载的方式,但该方案不可靠,请问是否有其他可行的解决方案?


解决方案

方案1:IIFE全局挂载(最稳定)

由于TwinCAT HMI的HtmlHost环境对ES模块支持有限,改用IIFE(立即执行函数表达式)将拆分的函数挂载到全局对象,避免模块语法冲突:

改造testvarFunction.js

/// <reference path="./../../../Packages/Beckhoff.TwinCAT.HMI.Framework.14.3.500/runtimes/native1.12-tchmi/TcHmi.d.ts" />
(function(window) {
  function testvarWriter() {
    const testvar1 = 'hello, i a testvar1';
    const testvar2 = 'itsa me, testvar2';
    // 将变量挂载到全局,供主脚本访问
    window.testVars = { testvar1, testvar2 };
  }

  // 统一命名空间,避免全局污染
  window.DrawUtils = window.DrawUtils || {};
  window.DrawUtils.testvarWriter = testvarWriter;
})(window);

改造mainTest.js

/// <reference path="./../../../Packages/Beckhoff.TwinCAT.HMI.Framework.14.3.500/runtimes/native1.12-tchmi/TcHmi.d.ts" />
if (!window.testScriptInitialized) {
  (function setTestScript(){
    const testDivId = document.getElementById('testDivId'); // 修复原代码的语法错误:缺少=

    // 同时检查HtmlHost和工具脚本是否初始化完成
    if (!testDivId || !window.DrawUtils?.testvarWriter){
      setTimeout(setTestScript, 100);
      console.log('HtmlHost或工具脚本未初始化,重试中');
      return;
    }
    console.log('HtmlHost初始化完成,执行脚本');
    
    // 调用拆分的函数
    window.DrawUtils.testvarWriter();
    // 访问全局变量
    console.log(window.testVars.testvar1, window.testVars.testvar2);

    window.testScriptInitialized = true;
    console.log('脚本执行完成');
  })();
}

修改HtmlHost脚本加载

<script src="/static/testvarFunction.js"></script>
<script src="/static/mainTest.js"></script>

移除type="module",通过主脚本的初始化检查避免加载顺序问题。

方案2:动态导入(异步方式)

如果环境支持动态导入,可在主脚本中用异步加载替代静态import

改造mainTest.js

/// <reference path="./../../../Packages/Beckhoff.TwinCAT.HMI.Framework.14.3.500/runtimes/native1.12-tchmi/TcHmi.d.ts" />
if (!window.testScriptInitialized) {
  (async function setTestScript(){
    const testDivId = document.getElementById('testDivId');

    if (!testDivId ){
      setTimeout(setTestScript, 100);
      console.log('HtmlHost未初始化,重试中');
      return;
    }
    console.log('HtmlHost初始化完成,加载工具脚本');
    
    try {
      // 动态导入工具脚本
      const { testvarWriter } = await import('./testvarFunction.js');
      // 接收函数返回的变量
      const { testvar1, testvar2 } = testvarWriter();
      console.log(testvar1, testvar2);
      console.log('脚本执行完成');
    } catch (e) {
      console.error('加载工具脚本失败:', e);
      setTimeout(setTestScript, 500); // 加载失败重试
    }

    window.testScriptInitialized = true;
  })();
}

改造testvarFunction.js

/// <reference path="./../../../Packages/Beckhoff.TwinCAT.HMI.Framework.14.3.500/runtimes/native1.12-tchmi/TcHmi.d.ts" />
export function testvarWriter() {
  const testvar1 = 'hello, i a testvar1';
  const testvar2 = 'itsa me, testvar2';
  // 返回变量供主脚本使用
  return { testvar1, testvar2 };
}

关键注意事项

  1. 原代码存在语法错误:const testvarWriter document.getElementById('testDivId');缺少=,需先修复。
  2. TwinCAT HMI的HtmlHost环境优先推荐IIFE方案,兼容性更稳定。
  3. 拆分的函数如需访问TwinCAT HMI API,必须在HtmlHost初始化完成后调用(通过主脚本的检查逻辑确保)。

内容的提问来源于stack exchange,提问作者SauceTheSecond

火山引擎 最新活动