Подтвердить что ты не робот

JS - window.history - удалить состояние

Используя API html5 window.history, я могу хорошо управлять навигацией в своем веб-приложении.

Приложение в настоящее время имеет два состояния: selectDate (1) и enterDetails (2).

Когда приложение загружается, я replaceState и устанавливаю прослушиватель popState:

history.replaceState({stage:"selectDate",...},...);
window.onpopstate = function(event) {
    that.toStage(event.state.stage);
};

Когда выбрана дата и приложение переходит на этап 2, я нажимаю состояние 2 на стек:

history.pushState({stage:"enterDetails",...},...);

Это состояние заменяется при изменении всех деталей, поэтому они сохраняются в истории.

Есть три способа выйти из стадии 2:

  • Сохранить (ajax submit)
  • отменить
  • Кнопка назад

Кнопка "Назад" обрабатывается слушателем popstate. Кнопка "Отмена" выдвигает этап 1, чтобы пользователь мог вернуться к деталям, которые они вводили на кнопку "Назад". Они оба работают хорошо.

Кнопка сохранения должна вернуться к этапу 1 и не позволить пользователю перейти на страницу сведений (поскольку они уже отправлены). В основном, y это должно сделать стек истории длиной = 1.

Но, похоже, нет history.delete() или history.merge(). Лучшее, что я могу сделать, это history.replaceState(stage1) который оставляет стек истории как: ["selectDate","selectDate"].

Как избавиться от одного слоя?

Редактировать:

Мысль о чем-то другом, но это тоже не работает.

history.back(); //moves history to the correct position
location.href = "#foo"; // successfully removes ability to go 'forward', 
                       // but also adds another layer to the history stack

Это оставляет стек истории как ["selectDate","selectDate#foo"].

Итак, как альтернатива, есть ли способ удалить "форвардную" историю без нажатия нового состояния?

4b9b3361

Ответ 1

Возможно, вы уже переехали, но... насколько я знаю, нет способа удалить запись истории (или состояние).

Один из вариантов, который я изучал, - это обработать историю самостоятельно в JavaScript и использовать объект window.history как носитель сорта.

В основном, когда первая страница загружается, вы создаете свой собственный объект истории (мы пойдем с массивом здесь, но используем все, что имеет смысл для вашей ситуации), а затем создайте свой первоначальный pushState. Я бы передал ваш пользовательский объект истории в качестве объекта состояния, так как он может пригодиться, если вам также нужно будет обрабатывать пользователей, перемещающихся вдали от вашего приложения, и вернуться позже.

var myHistory = [];

function pageLoad() {
    window.history.pushState(myHistory, "<name>", "<url>");

    //Load page data.
}

Теперь, когда вы перемещаетесь, вы добавляете в свой собственный объект истории (или нет - история теперь в ваших руках!) И используйте replaceState чтобы оставить браузер вне цикла.

function nav_to_details() {
    myHistory.push("page_im_on_now");
    window.history.replaceState(myHistory, "<name>", "<url>");

    //Load page data.
}

Когда пользователь перемещается назад, они будут бить ваше "базовое" состояние (ваш объект состояния будет пустым), и вы сможете обрабатывать навигацию в соответствии с вашим пользовательским объектом истории. После этого вы делаете еще одно pushState.

function on_popState() {
    // Note that some browsers fire popState on initial load,
    // so you should check your state object and handle things accordingly.
    // (I did not do that in these examples!)

    if (myHistory.length > 0) {
        var pg = myHistory.pop();
        window.history.pushState(myHistory, "<name>", "<url>");

        //Load page data for "pg".
    } else {
        //No "history" - let them exit or keep them in the app.
    }
}

Пользователь никогда не сможет перемещаться вперед, используя свои кнопки браузера, потому что они всегда находятся на самой новой странице.

С точки зрения браузера каждый раз, когда они идут "назад", они сразу же продвигаются вперед.

С точки зрения пользователя, они могут перемещаться назад по страницам, но не вперед (в основном имитируя модель "стек страниц" смартфона).

С точки зрения разработчика, теперь у вас есть высокий уровень контроля над тем, как пользователь перемещается по вашему приложению, но все же позволяет им использовать знакомые кнопки навигации в своем браузере. Вы можете добавлять/удалять элементы из любой точки в цепочке истории, как вам будет угодно. Если вы используете объекты в вашем массиве истории, вы также можете отслеживать дополнительную информацию о страницах (например, содержимое поля и многое другое).

Если вам необходимо обработать пользовательскую навигацию (например, пользователь, изменяющий URL-адрес в схеме навигации на основе хэша), вы можете использовать несколько иной подход, например...

var myHistory = [];

function pageLoad() {
    // When the user first hits your page...
    // Check the state to see what going on.

    if (window.history.state === null) {
        // If the state is null, this is a NEW navigation,
        //    the user has navigated to your page directly (not using back/forward).

        // First we establish a "back" page to catch backward navigation.
        window.history.replaceState(
            { isBackPage: true },
            "<back>",
            "<back>"
        );

        // Then push an "app" page on top of that - this is where the user will sit.
        // (As browsers vary, it might be safer to put this in a short setTimeout).
        window.history.pushState(
            { isBackPage: false },
            "<name>",
            "<url>"
        );

        // We also need to start our history tracking.
        myHistory.push("<whatever>");

        return;
    }

    // If the state is NOT null, then the user is returning to our app via history navigation.

    // (Load up the page based on the last entry of myHistory here)

    if (window.history.state.isBackPage) {
        // If the user came into our app via the back page,
        //     you can either push them forward one more step or just use pushState as above.

        window.history.go(1);
        // or window.history.pushState({ isBackPage: false }, "<name>", "<url>");
    }

    setTimeout(function() {
        // Add our popstate event listener - doing it here should remove
        //     the issue of dealing with the browser firing it on initial page load.
        window.addEventListener("popstate", on_popstate);
    }, 100);
}

function on_popstate(e) {
    if (e.state === null) {
        // If there no state at all, then the user must have navigated to a new hash.

        // <Look at what they've done, maybe by reading the hash from the URL>
        // <Change/load the new page and push it onto the myHistory stack>
        // <Alternatively, ignore their navigation attempt by NOT loading anything new or adding to myHistory>

        // Undo what they've done (as far as navigation) by kicking them backwards to the "app" page
        window.history.go(-1);

        // Optionally, you can throw another replaceState in here, e.g. if you want to change the visible URL.
        // This would also prevent them from using the "forward" button to return to the new hash.
        window.history.replaceState(
            { isBackPage: false },
            "<new name>",
            "<new url>"
        );
    } else {
        if (e.state.isBackPage) {
            // If there is state and it the 'back' page...

            if (myHistory.length > 0) {
                // Pull/load the page from our custom history...
                var pg = myHistory.pop();
                // <load/render/whatever>

                // And push them to our "app" page again
                window.history.pushState(
                    { isBackPage: false },
                    "<name>",
                    "<url>"
                );
            } else {
                // No more history - let them exit or keep them in the app.
            }
        }

        // Implied 'else' here - if there is state and it NOT the 'back' page
        //     then we can ignore it since we're already on the page we want.
        //     (This is the case when we push the user back with window.history.go(-1) above)
    }
}