Добавление pushState() и popstate в мой проект

У меня есть проект, над которым я работаю, в котором есть галерея. Галерея работает так, что пользователю предлагается список изображений, и каждое изображение представляет собой «альбом», который ссылается на другие изображения для данной галереи. В настоящее время у меня это работает, однако, когда пользователь нажимает кнопку «Назад» после перехода в выбранную галерею, он не возвращается в список альбомов. Например, если вы являетесь главной страницей, нажмите на страницу альбомов и откройте галерею. Нажав кнопку «Назад», вы вернетесь на главную страницу.

Итак, я думаю, чтобы исправить это, я могу использовать API истории и использовать pushState и popstate. Моя проблема в том, что я не смог заставить его работать, и я не уверен, где разместить функции в моем заданном скрипте.

Если вы хотите, чтобы у меня была живая версия сайта, над которым я работаю, здесь: Живая демонстрация< /а>

Вот мой текущий скрипт:

(function(code) {
  code(window.jQuery, window, document);
}(function($, window, document) {
  $(function() {
    initialize();
  });

  function initialize() {
    $.getJSON('/assets/js/images.json', function(json) {
      $.each(json.albums, function(i, item) {
        var photos = item.photos,
            name   = item.name,
            id     = item.id;

        showAlbums(photos, name, id);
      });  
    });
  }
  function showAlbums(p, n, i) {
    var albums    = $('.albums'),
        gallery   = $('.gallery'),
        album     = $('#templates #album .thumb').clone(true),
        thumbnail = album.find('.thumbnail'),
        image     = album.find('.image'),
        caption   = album.find('.caption h4');

    thumbnail.attr('href', '#').attr('title', n).attr('data-url', i);
    image.attr('src', p[0].href).attr('alt', n);
    caption.html(n);

    albums.append(album);

    album.on('click', 'a', function(e) {
      e.preventDefault();
      albums.hide();
      gallery.empty().show();
      document.title = "Schultz | " + n;
      $.each(p, function(i, item) {
        var photo = item.href;
        showGallery(photo, n);
      });
    });
  }
  function showGallery(p, n) {
    var gallery = $('.gallery'),
        images  = $('#templates #gallery .thumb').clone(),
        link    = images.find('.thumbnail'),
        image   = images.find('.thumbnail img');

    link.attr('href', p).attr('title', n).attr('data-gallery', '');
    image.attr('src', p).attr('alt', n);

    gallery.append(images);
  }
}));

Любая помощь приветствуется, спасибо


person Su7ech    schedule 30.06.2016    source источник
comment
Нет времени вдаваться в полный ответ здесь, но то, что вы хотите сделать, это преобразовать обработчик кликов вашего альбома в функцию showAlbum, которая вместо того, чтобы зависеть от локальных переменных в области, принимает индекс или идентификатор альбома в JSON data (на которые вы должны поддерживать ссылку, а не просто использовать для инициализации, чтобы вы могли использовать их позже). При щелчке по альбому вы затем pushState получаете новый URL-адрес, вероятно, '?id='+id, а затем showAlbum(id) загружаете представление. Затем в window.onpopstate вы вытащили бы id из строки запроса и showAlbum(id).   -  person numbers1311407    schedule 01.07.2016
comment
Тогда, конечно, если в строке запроса нет id, вы просто скроете gallery и отобразите albums (случай, когда пользователь нажимает назад в представлении галереи). С точки зрения пользовательского интерфейса вы, вероятно, захотите добавить кнопку «Назад в альбомы» из отдельных галерей. Такие вещи особенно важны, когда вы начинаете возиться с историей, например, если пользователь откроет браузер в представлении галереи, у него не будет возможности вернуться к альбомам.   -  person numbers1311407    schedule 01.07.2016
comment
Спасибо за помощь, попробую то, что вы посоветовали. Как только я разберусь с pushstate, следующее, что я планировал сделать, это добавить кнопку «Назад в альбомы».   -  person Su7ech    schedule 01.07.2016


Ответы (1)


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

Чтобы это произошло, вы должны хранить ссылку на данные JSON, которые вы извлекаете для создания галерей (либо сами данные, либо XHR, которые вы использовали для их извлечения). Таким образом, мы можем написать функцию «showAlbum», которая вместо этого принимает индекс или идентификатор, который мы можем использовать для доступа к выбранному альбому в данных.

Что-то вроде этого:

// As you're doing your initialization, process the JSON array of albums
// into a hash by ID (this is one of many ways to go about this, a more
// robust solution would be to use the XHR promise to ensure the JSON is
// always there when you need it).
var albumData = {};

function initialize () {
  $.getJSON('/assets/js/images.json', function(json) {
    $.each(json.albums, function(i, item) {
      var photos = item.photos,
          name   = item.name,
          id     = item.id;

      // Same as you have now, but with this line:
      albumData[id] = item;

      showAlbums(photos, name, id);
    });  
  });
}


// Then we create a function to show an album by ID, essentially the same as
// your click handler now, but retrieving the data from the structure we
// built out of the JSON.
function showAlbumById (id) {
  e.preventDefault();
  var album = albumData[id]
    , photos = album.photos
    , name = album.name;
  albums.hide();
  gallery.empty().show();
  document.title = "Schultz | " + n;
  $.each(photos, function(i, item) {
    showGallery(item.href, name);
  });
});

Затем вы замените обработчик кликов вашего альбома, чтобы вместо этого нажать на состояние и вызвать эту функцию. Здесь я использую переменную запроса для представления состояния в URL-адресе и theAlbumId для ясности (в коде на нее ссылается i). Если вы добавите кнопку «назад к альбомам», вы сделаете аналогичный обработчик, но отправите URL-адрес без запроса var.

album.on('click', 'a', function(e) {
  e.preventDefault();
  history.pushState({}, '', '?id='+theAlbumID);
  showAlbumById(theAlbumId);
});

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

// define `onpopstate` or add a listener for `popstate` on the window
window.onpopstate = function (state) {
  // pseudocode, you'd need to write or find a function to pull query vars
  var albumId = getQueryParameter('id');

  // if an album ID is in the query string, show it
  if (albumId) {
    showAlbumById(albumId);
  } 
  // otherwise show the index (this should probably be another function)
  else {
    albums.show();
    gallery.empty().hide();
    document.title = "Schultz";
  }
};

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

person numbers1311407    schedule 02.07.2016
comment
Большое спасибо за ваш ответ. У меня есть пара вопросов. Во-первых, как вы передаете данные json функции showAlbumById, используя приведенное выше? И это функции, которые будут использоваться для отображения галереи данного альбома? Также событие щелчка выходит за пределы функции или внутри функции showAlbumsById? - person Su7ech; 05.07.2016
comment
1. Вам не нужно передавать данные в функцию, потому что они сохраняются после первоначального получения из JSON. Таким образом, вы просто сделаете переменную albumData доступной для функции showAlbumByID, объявив ее в той же области видимости или выше. То, как написан код showAlbumByID, никогда не будет вызываться до тех пор, пока не вернется запрос JSON, поэтому вы будете знать, что он всегда был там. - person numbers1311407; 05.07.2016
comment
2. Да, showAlbumByID будет вызываться для отображения отдельной галереи, и вы будете вызывать ее при щелчке по альбому, в браузере назад/вперед к просмотру галереи и в конце инициализации для загрузки текущей галереи (если, например, вы посетили / mypage.html?id=1 напрямую или обновил страницу). - person numbers1311407; 05.07.2016
comment
3. Вы привязываете событие клика по альбому в том же месте, внутри showAlbums, где вы строите индекс всего альбома. Однако обработчик вызывает showAlbumsByID, так что нет, он не входит внутрь этой функции. Должен идти в том же месте. - person numbers1311407; 05.07.2016
comment
Большое вам спасибо за вашу помощь! Теперь я понимаю, чего мне не хватало. - person Su7ech; 05.07.2016