部分源码

  const util$ = new Util();
  const wxSelectorInfo = {
    homeSearchButton: {
      className: ClassNameType.RelativeLayout,
      desc: "搜索",
      depth: 13,
      id: "com.tencent.mm:id/jha"
    },
    editText: {
      className: ClassNameType.EditText,
      text: "搜索",
      depth: 11,
      id: "com.tencent.mm:id/d98",
      editable: true
    },
    editTextSearchButton: {
      className: ClassNameType.Button,
      text: "搜索",
      depth: 11,
      id: "com.tencent.mm:id/mdg"
    },
    visitWebButton: {
      className: ClassNameType.Text,
      text: "访问网页",
      depth: 28
    },
    continueVisitButton: {
      className: ClassNameType.Button,
      text: "继续访问",
      depth: 19
    },
    homeSerachSelectOption: {
      className: ClassNameType.Text,
      depth: 17,
      id: "com.tencent.mm:id/ltk"
    }
  };
  const findSelectorInfo = {
    startReadButton: {
      id: "readCtl",
      className: ClassNameType.Text,
      text: "开始阅读",
      depth: 20
    },
    coinsText: {
      id: "text2",
      className: ClassNameType.Text,
      depth: 19
    },
    urlText: {
      className: ClassNameType.Text,
      textStartsWith: "http://",
      depth: 22
    }
  };
  function CokeRead(appName, url, taskInterval, interval) {
    this.taskInterval = taskInterval;
    this.interval = interval;
    this.appName = appName;
    this.url = url;
    this.coinsTotal = 0;
    this.pageTotal = 0;
    this.one_task_time = 5;
    this.regex = /阅读第(\d+)篇成功,获得(\d+)币/;
  }
  CokeRead.prototype.start = function() {
    this.interval = setInterval(() => {
      util$.autoService(() => {
        const flag = util$.openApp(this.appName);
        if (!flag) {
          return;
        }
        this.taskOne();
        home();
      });
    }, this.taskInterval);
  };
  CokeRead.prototype.stop = function() {
    clearInterval(this.interval);
    console.log("CokeRead stop");
    this.interval = 0;
  };
  CokeRead.prototype.openCokeRead = function() {
    const wxhomeSearchButton = util$.findSelector(wxSelectorInfo.homeSearchButton);
    if (!wxhomeSearchButton) return false;
    util$.SelectorClick(wxhomeSearchButton);
    util$.wait(2);
    const editText = util$.findSelector(wxSelectorInfo.editText);
    if (!editText) return false;
    editText.setText(this.url);
    util$.wait(2);
    const homeSerachSelectOption = util$.findSelector(wxSelectorInfo.homeSerachSelectOption);
    if (!homeSerachSelectOption) return false;
    util$.SelectorClick(homeSerachSelectOption);
    util$.wait(2);
    const visitWebButton = util.findSelector(wxSelectorInfo.visitWebButton);
    if (!visitWebButton) return false;
    util$.SelectorClick(visitWebButton);
    util$.wait(2);
    const continueVisitButton = util$.findSelector(wxSelectorInfo.continueVisitButton);
    if (!continueVisitButton) return false;
    util$.SelectorClick(continueVisitButton);
    util$.wait(2);
    const startReadButton = util$.findSelector(findSelectorInfo.startReadButton);
    if (!startReadButton) return false;
    util$.SelectorClick(startReadButton);
    util$.wait(2);
    return true;
  };
  CokeRead.prototype.openUrlView = function() {
    const urlText = util$.findSelector(findSelectorInfo.urlText);
    if (!urlText) return false;
    const url = urlText.text();
    for (let i = 0; i < 3; i++) {
      back();
    }
    const editText = util$.findSelector(wxSelectorInfo.editText);
    if (!editText) return false;
    editText.setText(url);
    util$.wait(2);
    const editTextSearchButton = util.findSelector(wxSelectorInfo.editTextSearchButton);
    if (!editTextSearchButton) return false;
    util$.SelectorClick(editTextSearchButton);
    util$.wait(2);
    const visitWebButton = util$.findSelector(wxSelectorInfo.visitWebButton);
    if (!visitWebButton) return false;
    util$.SelectorClick(visitWebButton);
    util$.wait(2);
    const continueVisitButton = util$.findSelector(wxSelectorInfo.continueVisitButton);
    if (!continueVisitButton) return false;
    util$.SelectorClick(continueVisitButton);
    util$.wait(2);
    return true;
  };
  CokeRead.prototype.taskOne = function() {
    let flag = this.openCokeRead();
    if (!flag) return;
    flag = this.openUrlView();
    if (!flag) return;

问题

我使用的vite构建的js,明明没有形参问题

结果报错:

形参后没有")"

9lvuvc6718 · 2 天前

回答

Hamibot AI
1
· 2 天前

该报错是因为 Hamibot 脚本运行环境基于 Rhino 1.7.15 JavaScript 引擎,不支持 ES6 及以上的语法特性,尤其是箭头函数。报错信息“形参后没有')'"是 Rhino 解析箭头函数 => 时的典型错误。

问题原因

  1. 箭头函数不支持:代码中 this.interval = setInterval(() => { ... }, this.taskInterval); 使用了箭头函数 () => {}。Rhino 引擎无法识别 => 符号,导致解析函数参数时出错。
  2. Vite 构建产物兼容性:Vite 默认面向现代浏览器构建,输出的代码通常包含 ES6+ 特性。即使源代码没有箭头函数,构建后的代码也可能包含。
  3. this 指向问题:将箭头函数改为普通函数后,this 的指向会发生变化,不再指向 CokeRead 实例,需要手动绑定。

解决方案

  1. 修改代码语法:将所有箭头函数改为标准 function 表达式。
  2. 修正 this 指向:在函数外部保存 this 引用(例如 var self = this;),或在内部使用 .bind(this)
  3. 调整构建配置:如果必须使用 Vite,需配置 Babel 将目标环境设置为 ES5,确保输出代码不包含箭头函数、constlet 等特性(尽管 Rhino 支持部分 const/let,但 var 最稳妥)。

修正后的代码示例

针对 CokeRead.prototype.start 方法的修正如下:

// 文档地址 https://docs.hamibot.com/
CokeRead.prototype.start = function() {
    var self = this; // 保存 this 指向
    this.interval = setInterval(function() {
        // 普通函数内部 this 指向全局,需使用 self
        util$.autoService(function() {
            var flag = util$.openApp(self.appName);
            if (!flag) {
                return;
            }
            self.taskOne();
            home();
        });
    }, this.taskInterval);
};

其他兼容性建议

在 Hamibot 脚本开发中,请遵循以下规范以避免类似报错:

  1. 禁用箭头函数:所有回调函数均使用 function() {}
  2. 避免默认参数:函数定义不要使用 function(a = 1) {} 语法。
  3. 变量声明:优先使用 var,虽然 Rhino 支持 let/const,但 var 兼容性最好。
  4. 构建工具配置:若使用 Webpack 或 Vite,请配置 target: 'es5' 并使用 Babel 插件 @babel/preset-env 确保转译完全。
  5. 检查构建产物:上传到 Hamibot 前,检查最终生成的 JS 文件是否仍包含 =>classimport/export 等语法。

建议直接在 Hamibot 编辑器中编写脚本,或使用构建工具时严格限制语法特性,确保输出代码符合 Rhino 1.7.15 规范。

ℹ️ 本回答由 AI 生成,内容仅供参考