简体   繁体   中英

Routing knockout.js app with Sammy.js and history with html4 support

I just started playing around with sammy.js and first thing I want to do is to test how history changes works. And it works as expected, even better, but once I open IE10 and switched to IE9 browser mode, everything felled apart. If I'm not setting the links with hash, IE9 just keeps following the links. Same problem with IE8 of course.

At this moment I only have this bit of code related with sammy

App.sm = $.sammy('#content', function() {

    this.get('/', function(context) {
        console.log('Yo yo yo')
    });

    this.get('/landing', function(context) {
        console.log('landing page')
    });

    this.get('/:user', function(context) {
        console.log(context)
    });

});

And initiator

$(function() {
    App.sm.run('/');
});

I also looked at this example which contains three types of the links, normal ones, hash and again normal ones, but working properly on IE9 and IE8. that makes me think that somehow it should be possible to make sammy.js support html5 history and html4 at the same time.

So my question would be, how I can do achieve that?

Update

I found the way to make it work on IE

I just added this snippet:

this.bind('run', function(e) {
        var ctx = this;
        $('body').on('click', 'a', function(e) {
            e.preventDefault();
            ctx.redirect($(e.target).attr('href'));
            return false;
        });
    });

Anyway, I'm still having a problem with entry to the website, html5 history supporting browsers is always redirected to the domain.com, no matter what was initial url.

So I wonder how I should configure sammy.js to work peroperly. Or maybe anyone could recommend some other router which would work nicely with knockout.js.

For a number of reasons, including search engine spiders and link sharing; your site should work without the History API. If a user sees http://example.org/poodles/red and wants to show someone else the red poodles on your web site, they copy the link. The other visitor needs to be able to see the same content at the same URL; even if they don't start at the homepage.

For this reason, I suggest using the History API as a progressive enhancement. Where it's available, you should use it to provide a better UX. Where it's not available, links should function as normal.

Here's an example Router (like Sammy) which simply allows the default browser navigation if history.pushState isn't available.

And about the Knockout part; I have used this in a KnockoutJS project and it works well.

(function($){

    function Route(path, callback) {
        function escapeRegExp(str) {
            return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
        }

        // replace "/:something" with a regular expression fragment
        var expression = escapeRegExp(path).replace(/\/:(\w+)+/g, "/(\\w+)*");

        this.regex = new RegExp(expression);
        this.callback = callback;
    }

    Route.prototype.test = function (path) {
        this.regex.lastIndex = 0;

        var match = this.regex.exec(path);

        if (match !== null && match[0].length === path.length) {
            // call it, passing any matching groups
            this.callback.apply(this, match.slice(1));
            return false;
        }

    };

    function Router(paths) {
        var self = this;
        self.routes = [];
        $.each(paths, function (path, callback) {
            self.routes.push(new Route(path, callback));
        });

        self.listen();
        self.doCallbacks(location.pathname);
    }

    Router.prototype.listen = function () {
        var self = this, $document = $(document);

        // watch for clicks on links
        // does AJAX when ctrl is not down
        // nor the href ends in .html
        // nor the href is blank
        // nor the href is /
        $document.ready(function(e){


           $document.on("click", "[href]", function(e){
               var href = this.getAttribute("href");

               if ( !e.ctrlKey && (href.indexOf(".html") !== href.length - 5) && (href.indexOf(".zip") !== href.length - 4) && href.length > 0 && href !== "/") {
                   e.preventDefault();
                   self.navigate(href);
               }
           });
        });

        window.addEventListener("popstate", function(e) {
            self.doCallbacks(location.pathname);
        });
    };

    Router.prototype.navigate = function(url) {
        if (window.history && window.history.pushState) {
            history.pushState(null, null, url);
            this.doCallbacks(location.pathname);
        }
    };

    Router.prototype.doCallbacks = function(url) {
        var routes = this.routes;

        for (var i=0; i<routes.length; i++){
            var route = routes[i];

            // it returns false when there's a match
            if (route.test(url) === false) {
                console.log("nav matched " + route.regex);
                return;
            }
        }

        if (typeof this.fourOhFour === "function") {
            this.fourOhFour(url);
        } else {
            console.log("404 at ", url);
        }
    };

    window.Router = Router;

}).call(this, jQuery);

Example usage:

router = new Router({
    "/": function () {

    },
    "/category/:which": function (category) {

    },
    "/search/:query": function(query) {

    },
    "/search/:category/:query": function(category, query) {

    },
    "/:foo/:bar": function(foo, bar) {

    }
});

router.fourOhFour = function(requestURL){

};

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