Frage

I’ve made a one page site. When user clicks on the menu buttons, content is loaded with ajax. It works fine. In order to improve SEO and to allow user to copy / past URL of different content, i use

function show_content() {
        // change URL in browser bar)
        window.history.pushState("", "Content", "/content.php");
        // ajax
        $content.load("ajax/content.php?id="+id);
}

It works fine. URL changes and the browser doesn’t reload the page

However, when user clicks on back button in browser, the url changes and the content have to be loaded.

I've done this and it works :

 window.onpopstate = function(event) {
        if (document.location.pathname == '/4-content.php') {
            show_content_1();
        }
        else if (document.location.pathname == '/1-content.php') {
            show_content_2();
        }
        else if (document.location.pathname == '/6-content.php') {
            show_content_();
        }
    };

Do you know if there is a way to improve this code ?

War es hilfreich?

Lösung

What I did was passing an object literal to pushState() on page load. This way you can always go back to your first created pushState. In my case I had to push twice before I could go back. Pushing a state on page load helped me out.

HTML5 allows you to use data-attributes so for your triggers you can use those to bind HTML data.

I use a try catch because I didn't had time to find a polyfill for older browsers. You might want to check Modernizr if this is needed in your case.

PAGELOAD

try {
    window.history.pushState({
        url: '',
        id: this.content.data("id"), // html data-id
        label: this.content.data("label") // html data-label
    }, "just content or your label variable", window.location.href);
} catch (e) {
    console.log(e);
}

EVENT HANDLERS

An object filled with default information

var obj = {
    url: settings.assetsPath, // this came from php
    lang: settings.language, // this came from php
    historyData: {}
};

Bind the history.pushState() trigger. In my case a delegate since I have dynamic elements on the page.

// click a trigger -> push state
this.root.on("click", ".cssSelector", function (ev) {
    var path = [],
        urlChunk = document.location.pathname; // to follow your example

    // some data-attributes you need? like id or label
    // override obj.historyData
    obj.historyData.id = $(ev.currentTarget).data("id");

    // create a relative path for security reasons
    path.push("..", obj.lang, label, urlChunk);
    path = path.join("/");

    // attempt to push a state
    try {
        window.history.pushState(obj.historyData, label, path);
        this.back.fadeIn();
        this.showContent(obj.historyData.id);
    } catch (e) {
        console.log(e);
    }
});

Bind the history.back() event to a custom button, link or something. I used .preventDefault() since my button is a link.

// click back arrow -> history
this.back.on("click", function (ev) {
    ev.preventDefault();
    window.history.back();
});

When history pops back -> check for a pushed state unless it was the first attempt

$(window).on("popstate", function (ev) {
    var originalState = ev.originalEvent.state || obj.historyData;
    if (!originalState) {
        // no history, hide the back button or something
        this.back.fadeOut();
        return;
    } else {
        // do something
        this.showContent(obj.historyData.id);
    }
});

Using object literals as a parameter is handy to pass your id's. Then you can use one function showContent(id).

Wherever I've used this it's nothing more than a jQuery object/function, stored inside an IIFE.

Please note I put these scripts together from my implementation combined with some ideas from your initial request. So hopefully this gives you some new ideas ;)

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top