简体   繁体   中英

JavaScript Module Pattern document.ready not working

I have a basic example of the Module pattern that simply adds a class to the footer element on the page.

  1. When the script is loaded in the body tag (after the footer element) it works and adds the class to the footer.

  2. When the script is loaded in the head tag (before the footer element) it doesn't work even though the init shouldn't be getting called until the document is ready.

I assume the document.ready isn't working as expected and therefore it's not finding the footer element as it doesn't exist.

This has been bugging me for ages and I can't seem to find the solution, can someone please shed some light on this problem?

Example: https://jsfiddle.net/5x5skoq3/

var App = (function ($) {
    "use strict";

    // private alias to settings
    var s;

    return {
        settings: {
            footer: $("footer")
        },

        init: function() {
            s = this.settings;

            this.footer();
        },

        footer: function(){
            s.footer.addClass("active");
        }
    };
})(jQuery);


jQuery(document).ready(function() {

    App.init();

});

Thank you

It's not the problem that init is called too early, but rather that settings: { footer: $("footer") } is evaluated too early. You're already referencing the element here when the module is loaded, not when it's initialised.

Luckily that's easy to fix:

var App = (function($) {
    "use strict";

    var footer;

    return {
        settings: {
            footerSelector: "footer"
        },
        init: function() {
            footer = $(this.settings.footerSelector);
            this.footer();
        },
        footer: function() {
            footer.addClass("active");
        }
    };
})(jQuery);

In this case, App is a self invoked function. The function executes creating the return object and all of it's properties. At the time that the function self invokes, footer: $("footer") is called returning a jQuery object with length: 0 indicating that the selector returned no matched element or element sets. I've updated your jsfiddle to alert the number of matches found on your call to init .

You can fix this in a variety of ways. The way I would probably fix it would be to convert settings into an object constructor:

 var App = (function ($) { "use strict"; // private alias to settings var s; return { settings: function () { this.footer = $('footer'); }, init: function() { s = new this.settings(); this.footer(); }, footer: function(){ s.footer.addClass("active"); } }; })(jQuery); jQuery(document).ready(function() { App.init(); }); 
 footer.active { background-color: red; color: #fff; } 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <header> Header content </header> <footer> Footer content </footer> 

Using this method, you still keep the logic out of the init function but maintain the consistency with your original example where settings returns an object.

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