0

我正在尝试将Splidejs集成到Grapesjs编辑器中。安装滑块时,我得到Uncaught Error: [splide] A track/list element is missing.

调试后,我意识到 Splide 没有找到正确安装所需的轨道或列表 HTML 元素。但是,它们存在于 Grapes 组件的 HTML 中。

...
<div class="splide__track">
<ul class="splide__list">
...

Splide 没有找到它们的原因似乎与不同的 HTMLElement 基类型有关,导致我的元素无法识别。

下面的测试(Splide 3.6.9)返回false

在此处输入图像描述

Chrome 开发工具控制台中进行调查时,乍一看__proto__评估的链看起来是正确的。instanceof然而,仔细观察表明它subject具有额外的__zone_symbol__onxxx属性。

> subject.__proto__.__proto__
    HTMLElement {…}
        ...
        __zone_symbol__ononabortpatched: true
        __zone_symbol__ononanimationendpatched: true
        __zone_symbol__ononanimationiterationpatched: true
        ...
> HTMLElement.prototype
    HTMLElement {…}
        ...
        none of the __zone_symbol __onxxx present
        ...
> subject.__proto__.__proto__ == HTMLElement.prototype
    false

这可以通过这两个参考来解释:

(1) https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/instanceof#instanceof_and_multiple_context_e.g._frames_or_windows

instanceof和多个上下文(例如框架或窗口)

不同的作用域有不同的执行环境。这意味着它们具有不同的内置函数(不同的全局对象、不同的构造函数等)。这可能会导致意想不到的结果。例如,[] instanceof window.frames[0].Array将返回false,

(2) https://grapesjs.com/docs/modules/Components-js.html#important-caveat

请记住,所有组件脚本都在画布的 iframe 内执行(隔离,就像您的最终模板一样),因此不是当前文档的一部分。

我怀疑我的 Splide 内容被 zone.js 增强了。因此我开始在 Angular 区域之外创建 Grapes 组件

this.zone.runOutsideAngular(() => {
      this.initGrapesEditor()
    })

但错误仍然存​​在。

您对我如何解决此问题有任何提示吗?

  • 在我的托管 Grapes.js 的组件中完全禁用 zone.js
  • 修改/修复 Splide 搜索(过滤)所需 HTML 元素的方式?
  • 其他建议?
4

1 回答 1

0

我还在grapesjs的github上报告了这个问题 https://github.com/artf/grapesjs/discussions/4062

并添加了两个解决方法

  1. 如下修补 splidejs(未提交 PR)。这允许我的新组件类型的脚本正确加载 splidejs。

如在

/**
 * Tests to see if the given TypeName appears anywhere
 * in the prototype chain of the given subject.
 * This is a lose version of the instanceof operator
 * (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/instanceof)
 * required when checking the type of elements that cross window and iframe bouderies.
 * 
 * @param subject 
 * @param typeName 
 * @returns `true` if 
 */
function isInstanceOf(subject: any, typeName: string) {
  if (subject === null) {
    return false;
  }
  let p = subject.__proto__;
  while (p !== null) {
    if (p.constructor.name === typeName) {
      return true;
    }
    p = p.__proto__;
  }
  return false;
}

export function isHTMLElement( subject: unknown ): subject is HTMLElement {
  return isInstanceOf( subject, 'HTMLElement' );
}

export function isHTMLButtonElement( subject: unknown ): subject is HTMLButtonElement {
  return isInstanceOf( subject, 'HTMLButtonElement' );
}
  1. Splide替换为Swiper。Swiper 不依赖instanceof HTMLElement开箱即用,这简化了我的开发。
于 2022-01-13T12:46:40.243 回答