Zurb Foundation:Slider 插件在作为 ES 模块导入时不会触发事件

Zurb Foundation: Slider plugin doesn't fire events when imported as ES module

我试图在我的网站上仅使用 ES 模块,目前 Zurb Foundation 存在问题。我使用 Skypack 导入 ES 模块并且不使用任何打包器。

当我在页面上放置一些经典的初始化代码时,来自滑块的事件按预期触发:

<!-- Basic slider template. See https://get.foundation/sites/docs/slider.html -->
<div id="test-slider" class="slider" data-slider data-initial-start="30" data-end="100">
  <span class="slider-handle" data-slider-handle role="slider" tabindex="1"></span>
  <span class="slider-fill" data-slider-fill></span>
  <input type="hidden">
</div>

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/foundation/6.6.3/css/foundation.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/foundation/6.6.3/js/foundation.min.js"></script>

<script>
  $(document).ready(function() {

    // Init Foundation
    //Foundation.addToJquery($);
    $(document).foundation();

    $('#test-slider').on('moved.zf.slider', function() {
      console.log('This should work while slider slides!');
      //console.log($._data($('#test-slider')[0]).events);
    });

  });
</script>

但是当我将上面的代码转换为 ES 模块时,滑块事件停止工作:

<h4>Drag the slider</h4>

<!-- Basic slider template. See https://get.foundation/sites/docs/slider.html -->
<div id="test-slider" class="slider" data-slider data-initial-start="30" data-end="100">
  <span class="slider-handle"  data-slider-handle role="slider" tabindex="1"></span>
  <span class="slider-fill" data-slider-fill></span>
  <input type="hidden">
</div>

<h4>Expected</h4>
<p>Drag slider and console should populated with <strong>'This should work while slider slides!'</strong> message.</p>
<h4>Current</h4>
<p>Drag slider and console shows nothing.</p>

<link rel="stylesheet" href="https://cdn.skypack.dev/foundation-sites/dist/css/foundation.css">

<script type="module">
  
  import $ from 'https://cdn.skypack.dev/jquery?min'; // Latest jQuery from skypack.dev
  import { Foundation } from 'https://cdn.skypack.dev/foundation-sites?min'; // Latest Foundation from skypack.dev
   
  $(document).ready(function() {
    
    Foundation.addToJquery($);
    $(document).foundation();
    
    $('#test-slider').on('moved.zf.slider', function () {
      console.log('This should work while slider slides!');
      //console.log($._data($('#test-slider')[0]).events);
    });
    
    // This will work because it is natural jQuery event, not the one from Foundation
    //$('#test-slider').on('click', function () {
    //   console.log('Click works!');
    //});
  });
</script>

我错过了什么?以及如何解决?

具有问题代码的演示 Codepen 是 here!

好的。我想我找到了导致事件问题的原因。

在发布问题时,foundation-sites 模块导入使用了最新版本的 Zurb Foundation (v6.6.3),并且该版本是在内部使用 jQuery v3.5.1 导入编译的。可以通过 https://cdn.skypack.dev/foundation-sites 中的 url 并检查代码来检查它。

但在问题的代码示例中,我使用 import $ from 'https://cdn.skypack.dev/jquery?min' 导入最新的 jQuery 版本 (v3.6.0)

因为我导入了 jQuery v3.6.0 并且 Foundation 模块在内部使用了 jQuery v3.5.1,事件监听器被放置在 不同的范围 (某种)不同于 Slider 的范围或任何 Zurb Foundation UI 元素,如果我在这里错了,请修复我。

选项 1。

所以解决方案是坚持使用某些版本的模块以获得 'match' 内部 jQuery 版本的 foundation-sites 模块。

替换为:

import $ from 'https://cdn.skypack.dev/jquery?min'; // Latest jQuery from skypack.dev
import { Foundation } from 'https://cdn.skypack.dev/foundation-sites?min'; // Latest Foundation from skypack.dev

有了这个:

import $ from 'https://cdn.skypack.dev/jquery@3.5.1?min'; // jQuery v3.5.1 from skypack.dev
import { Foundation } from 'https://cdn.skypack.dev/foundation-sites@6.6.3?min'; // Foundation v6.6.3 from skypack.dev

选项 2。

以防有人遇到同样的问题但不想 'stick' 使用某些版本的 jQuery。

当 Foundation 包装元素时,它会向该元素添加 jQuery{version}{some-kind-of-timestamp} 属性。像这样:

基金会添加了名称以 jQuery3510 开头的两个属性。其中之一包含 events 属性。但是当我们使用从不同 ES 模块导入的另一个 jQuery 版本时,还有另一个 jQuery3600events。当我这样做时

$('#test-slider').on('moved.zf.slider', function () {
   // Do something
});

moved.zf.slider 事件的注册进入 jQuery3600,而不是应有的 jQuery3510

所以这里的解决方案是用来自 jQuery3600 的事件更新包含 eventsjQuery3510。我用执行此操作的函数扩展 jQuery:

$.fn.mutatedOn = function (events, callback) {

    function getPropsByName(obj, startWith) {
        return Object.keys(obj).filter((propertyName) => {
            return propertyName.indexOf(startWith) === 0;
        });
    }

    function findPropsWithEvents(obj) {
        const props = getPropsByName(obj, "jQuery");
        return props.find((element) => {
            return obj[element].events !== undefined;
        });
    }

    $(this).each((index, el) => {

        // Let's find all properties which starts with 'jQuery'.
        // And filter them to determine those which contains 'events'
        // right before we attach the event listener.
        const jqueryKeys = getPropsByName(el, "jQuery");
        const jqueryKeysWithEvents = findPropsWithEvents(el);

        $(el).on(events, callback);

        // After the listener attached, another 'jQuery' property with 'events' was added for $(el).
        // Let's find this newly added property using difference between new and old arrays.
        const newJqueryKeys = getPropsByName(el, "jQuery");
        const newJqueryKeysWithEvents = $(newJqueryKeys).not(jqueryKeys).get(0);

        // After we determine new property with 'events'
        // lets merge it into the old one to make Foundation events work as expected.
        $.extend(el[jqueryKeysWithEvents], el[newJqueryKeysWithEvents]);
    });
};

然后这个:

$('#test-slider').on('moved.zf.slider', function () {
    // Do something
});

可以简单地替换为:

$('#test-slider').mutatedOn('moved.zf.slider', function () {
    // Do something
});