简体   繁体   中英

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

I'm trying to use only ES modules on my site and currently have the issue with Zurb Foundation. I use Skypack to import ES modules and don't use any bundlers.

When I place some classic init code on the page, events from slider fires as expected:

 <.-- 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>

But when I convert code above into ES Module, slider events stops working:

<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>

What I'm missing? And how can it be fixed?

Demo Codepen with problematic code is here!

Ok. I think I found what cause the issue with events.

In time when the question was posted the foundation-sites module import uses the latest version of Zurb Foundation (v6.6.3) and that version was compiled with jQuery v3.5.1 import internally. It can be checked by following urls inside https://cdn.skypack.dev/foundation-sites and inspecting the code.

But in the question's code example I use import $ from 'https://cdn.skypack.dev/jquery?min' which imports the latest jQuery version (v3.6.0)

Because I import jQuery v3.6.0 and Foundation module uses jQuery v3.5.1 internally, the event listener was placed in the different scope (some kind of) which differs from scope of Slider or any of Zurb Foundation UI elements, fix me if I'm wrong here.

Option 1.

So the solution is to stick with certain versions of modules to get 'match' with internal jQuery version of foundation-sites module.

Replace this:

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

With this:

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

Option 2.

In case someone has the same issue but didn't want to 'stick' with certain version of jQuery.

When Foundation wraps the element it adds jQuery{version}{some-kind-of-timestamp} properties to that element. Like so:

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

Two properties which names started with jQuery3510 were added by Foundation. One of them contains events property. But as we uses another jQuery version imported from different ES module there is another one jQuery3600 with events . And when I do

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

the registration of moved.zf.slider event goes into jQuery3600 , not into jQuery3510 as it should.

So the solution here is to update jQuery3510 which contains events with events from jQuery3600 . I extend jQuery with function that does this:

$.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]);
    });
};

Then this:

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

simply can be replaced with this:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM