首页 > 解决方案 > Zurb Foundation:作为 ES 模块导入时,滑块插件不会触发事件

问题描述

我正在尝试在我的站点上仅使用 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 在这里!

标签: javascriptjqueryzurb-foundationes6-modules

解决方案


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

在发布问题时,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。

所以解决方案是坚持使用某些版本的模块来与模块的内部 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。

如果有人有同样的问题,但不想“坚持”某些版本的 jQuery。

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

使用 Foundation 初始化元素时的特定属性

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

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

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

所以这里的解决方案是jQuery3510使用events来自jQuery3600. 我使用执行此操作的函数扩展 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
});

推荐阅读