Bootstrap Tour не помнит, где я ушел

У меня возникли проблемы с запуском Bootstrap Tour в многостраничном туре, когда я попаду на вторую страницу.

У меня есть начало тура с событием клика, а localStorage - false. Тур начинается отлично с событием клика, но затем, когда я перехожу на второй этап тура и загружаю новую страницу, тур не поднимается там, где он остановился.

Как мне возобновить тур со второго шага на этой новой странице? Я знаю, что мне нужно повторно инициализировать тур, но я, видимо, не делаю этого правильно.

$(document).ready(function () {
    // Instance the tour
    var tour = new Tour({
        name: "CiteTour",
        steps: [{
            element: "",
            title: "#1",
            content: "You can find help with formatting citations on the Guide page. Click 'Next' to go there now.",
            placement: ""
        }, {
            element: "#CiteTour2",
            title: "#2 - Citation Resources",
            content: "There are several options for getting help with formatting citations. Once on the Guide page, look for the box labeled 'Citation Help.'",
            placement: "right",
            path: "/newpath",
            onNext: function (tour) {
                tour.init();
                tour.restart();
            }
        }, {
            element: "#CiteTour3",
            title: "#3",
            content: "This site can help format your research paper and references in APA, MLA, and the other major citation formats.",
            placement: "right",
        }, {
            element: "#AskTour1",
            title: "#4 - Ask-a-Librarian",
            content: "If you still have questions about citations or citation format, feel free to contact the librarians.  Good luck!",
            placement: "left",
        }],
        storage: false,
    });

    // Initialize the tour
    tour.init();
    $('#CiteTour-go').on('click', function () {
        // Start the tour
        tour.start();
    });
});

Ответ 1

Вопросы и пояснения

Сначала, вы должны убедиться, что используете storage: window.localStorage, который использует Storage API. Это вариант по умолчанию для тура, поэтому все, что вам нужно сделать, не отменяет его на false, как вы это делали. Это позволяет Bootstrap Tour сохранять текущую информацию о шаге на нескольких страницах в одном домене.

Хотите доказательства? - Откройте свои инструменты для разработчиков и посмотрите: Resources

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

Кроме того, вам нужно использовать ссылку абсолютного пути, предварительно используя URL-адрес с косой чертой, так что это относится к корневому каталогу. Если вы используете относительные пути, путь будет изменен при перемещении по страницам/шагам. Для получения дополнительной информации см. мой раздел внизу на странице "Бесконечная страница"

Третий, пока вы определяете объект tour и init ialize it, тур автоматически будет автоматически загружаться на новой странице.

Посмотрите на упрощенную версию что init() делает:

Tour.prototype.init = function(force) {
  // other code omitted for brevity

  if (this._current !== null) {
    this.showStep(this._current);
  }
};

Итак, как только вы инициализировали тур, пока он замечает, что тур начался и еще не закончился (т.е. он имеет текущий шаг), он автоматически запустит этот шаг. Поэтому вам не нужно инициализировать, нажав на событие onNext на втором шаге.

Многостраничный тур Доказательство концепции

Редактируемый планшет | Runnable Demo

script.js

$(function() {

  // define tour
  var tour = new Tour({
    steps: [{
      path: "/index.html",
      element: "#my-element",
      title: "Title of my step",
      content: "Content of my step"
    }, {
      path: "/newPage.html",
      element: "#my-other-element",
      title: "Title of my step",
      content: "Content of my step"
    }]
  });

  // init tour
  tour.init();

  // start tour
  $('#start-tour').click(function() {
    tour.restart();
  });

});

index.html

<!DOCTYPE html>
<html>
<head>
  <title>Multipage Bootstrap Tour - Page 1</title>
  <link rel="stylesheet" href="bootstrap.css" />
  <link rel="stylesheet" href="bootstrap-tour.min.css">
</head>
<body>
  <div class="container">
    <h1>First Page</h1>

    <button class="btn btn-lg btn-primary" id="start-tour">
      Start Tour
    </button><br/><br/>


    <span id="my-element">
      My First Element
    </span>

  </div>
  <script src="jquery.min.js"></script>
  <script src="bootstrap.js"></script>
  <script src="bootstrap-tour.min.js"></script>
  <script src="script.js"></script>
</body>
</html>

newpage.html

<!DOCTYPE html>
<html>
<head>
  <title>Multipage Bootstrap Tour - Page 2</title>
  <link rel="stylesheet" href="bootstrap.css" />
  <link rel="stylesheet" href="bootstrap-tour.min.css">
</head>
<body>
  <div class="container">
    <h1>New Page</h1>

    <span id="my-other-element">
      My Second Elemennt
    </span>

  </div>
  <script src="jquery.min.js"></script>
  <script src="bootstrap.js"></script>
  <script src="bootstrap-tour.min.js"></script>
  <script src="script.js"></script>
</body>
</html>

Где вы ввели следующие библиотеки:

Бесконечная проблема обновления страницы

Во множестве конфигураций вы попадаете в цикл, где страница бесконечно обновляется, постоянно пытаясь решить путь текущего шага. Здесь рассмотрим, почему возникает эта проблема и как ее исправить.

Как Bootstrap Tour переходит к следующему шагу?

Когда вы нажмете кнопку Next, тур вызовет showStep(i) для следующего шага

Здесь приведен упрощенный вариант showStep:

Tour.prototype.showStep = function (i) {
    // other code omitted for brevity

    // get step path
    path = tour._options.basePath + step.path;

    // get current path - join location and hash
    current_path = [document.location.pathname, document.location.hash].join('');

    // determine if we need to redirect and do so
    if (_this._isRedirect(path, current_path)) {
        _this._redirect(step, path);
        return;
    }
};

Итак, если текущий путь в документе отличается от пути для следующего шага, то тур автоматически перенаправляется на следующий шаг.

Вот упрощенная форма перенаправления, которая просто учитывает строковые значения:
Я пропустил пути, основанные на регулярном выражении, хотя Bootstrap Tour также поддерживает их

Tour.prototype._isRedirect = function(path, currentPath) {
    var checkPath = path.replace(/\?.*$/, '').replace(/\/?$/, '');
    var checkCurrent = currentPath.replace(/\/?$/, '');
    return (checkPath !== checkCurrent);
};

Tour.prototype._redirect = function(step, path) {
    this._debug("Redirect to " + path);
    return document.location.href = path;
};

Примечание. Регулярное выражение только там, чтобы удалить параметры запроса (/\?.*$/) и завершение косой черты (//? $/`)

Когда какая-либо страница загружается, она не уверена, что Bootstrap Tour перенаправил ее, или вы просто возвращаетесь и пытаетесь забрать тур, где вы остановились.

Итак, на любой странице, когда вы инициализируете тур:

  • он запустит текущий шаг, основанный на значении в локальном хранилище.
  • когда текущий шаг загружается, он будет подтверждать, что путь для шага совпадает с текущим URL
  • если нет, он перенаправит путь к шагу и начнет работу с шага 1

Другими словами, он знает, как добраться до того места, где ему нужно идти дальше, но не имеет способа подтвердить, что это случай, когда он туда доберется. Возьмите эту ситуацию, например, с шагом, который выглядит следующим образом:

var step = {
      path: "index.html",
      element: "#my-element",
      title: "Title of my step",
      content: "Content of my step"
    }

Он может быть перенаправлен на относительную ссылку просто отлично, но когда страница загружается снова и проверяет, что она была загружена с правильным адресом, это произойдет:

infinite loop

"KyleMit", вы можете протестовать: "Не может ли это просто выяснить, что я хочу?"

-Нет!

Если вы полагаетесь на относительные пути перенаправления, когда он загружает шаг, он не может гарантировать, что вы действительно достигли этого шага, и он попытается перенаправить вас снова.

Это потому, что в веб-адресах "index.html" !== "\index.html". Это два разных пути! Один гарантированно находится в корне домена, а другой может быть где угодно. Представьте, что у вас есть несколько вложенных представлений:

  • Просмотров
    • Общий
      • index.html
      • newpage.html
    • Человек
      • index.html
      • newpage.html

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

Это подводит нас к решению этой проблемы:

Использовать абсолютные URL-адреса Абсолютно

Совет: лучше понять, что происходит, пройдя в debug:true при создании своего тура, в котором будет записываться каждый редирект:
redirect

Ответ 2

В частности, для SPA, построенных с помощью Angular

Фантастический ответ от @KyleMit мне очень помог: я выполнил все три рекомендации, но тур не продолжился. Я считаю, что bootstrap-tour по-прежнему имеет проблемы с одностраничными приложениями.

Поскольку я использую Angular в SPA, это фактически та же самая "веб-страница", но разные Angular "представления". Тур не продолжался...

Пока я не добавил $(window).resize(); к моему фиксированному навигационному контроллеру. Навигационная панель фиксируется в верхней части экрана. Поэтому контроллер создается один раз. И у меня уже был обработчик изменения местоположения:

$scope.$on("$locationChangeSuccess", $scope._handleLocationChange);

Подсказка к этому "решению" заключалась в том, что мне пришлось нажать F12 для просмотра консольных сообщений в панели "Firebug" (пристыкованную), и вот, тур продолжился! Я проверил, и это будет продолжаться, когда я закрываю или открываю панель Firebug. Я все еще не могу понять, почему resize необходимо, но это безобидно в контексте моего приложения, и мне нужно двигаться дальше, после столь большого количества времени на эту проблему. Удалите вызов resize, и маршрут не будет продолжен после перенаправления. Добавьте его обратно, и тур продолжится по назначению.

У меня была "basePath": "/app/#" в конфигурации тура, которая охватывает только два вида. Пути были похожи на "path": "/" (для "домашнего" представления) и "path": "/show/chair" (типичный вид в приложении).

Я использую Angular 1.4.8 в этом приложении.

НТН.