【问题标题】:Adding pushState() and popstate to my project将 pushState() 和 popstate 添加到我的项目中
【发布时间】:2016-06-30 20:33:27
【问题描述】:

我正在处理一个有画廊的项目。画廊的工作方式是让用户看到一个图像列表,每个图像都是一个“相册”,链接到给定画廊的更多图像。我目前正在工作,但是当用户在转到所选画廊后单击后退按钮时,他们不会被带回专辑列表。比如你是首页,点击相册页面,打开一个图库。单击返回按钮后,您将返回主页。

所以我想解决这个问题,我可以使用历史 API 并使用 pushState 和 popstate。我的问题是我无法让它工作,我不确定在给定脚本中放置函数的位置。

如果您想要我正在开发的网站的实时版本:Live Demo

这是我当前的脚本:

(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);
  }
}));

感谢您的帮助,谢谢

【问题讨论】:

  • 没有时间在这里找到完整的答案,但是您要做的是将您的专辑点击处理程序重构为 showAlbum 函数,该函数不依赖于范围内的局部变量,而是接受在 JSON 数据中专辑的索引或 ID 中(您应该维护对它的引用,而不是仅仅使用 to init,以便您以后可以使用它)。点击相册,然后pushState 一个新的 URL 可能是'?id='+id,然后showAlbum(id) 加载视图。然后在window.onpopstate 中,您将从查询字符串中提取idshowAlbum(id)
  • 那么当然,如果查询字符串中没有id,您只需隐藏gallery并显示albums(用户在图库中单击“返回”的情况看法)。在 UI 方面,您可能希望从各个画廊中添加一个页面内“返回相册”按钮。一旦你开始弄乱历史,这类事情就特别重要,就好像用户在画廊视图上打开浏览器一样,他们没有办法“返回”到相册。
  • 感谢您的帮助,我会尝试您的建议。一旦我弄清楚了 pushstate,我计划做的下一件事就是添加一个返回相册按钮。

标签: javascript jquery html html5-history


【解决方案1】:

基本上你想要做的是将你的专辑点击处理程序重构为一个可以在初始化之外调用的函数来构建专辑视图,然后在点击专辑时调用该函数,和popstate(后退/前进)。

要实现这一点,您应该存储对您为构建画廊而拉取的 JSON 数据的引用(数据本身或用于检索它的 XHR)。这样我们就可以编写一个“showAlbum”函数,取而代之的是一个索引或 ID,我们可以使用它来访问数据中选定的专辑。

所以是这样的:

// 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 没有查询变量。

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,您还需要在页面加载时检查专辑 ID 的查询字符串,并像在 popstate 中一样显示专辑(popstate 在某些浏览器在页面加载时运行,但它不应该)

【讨论】:

  • 非常感谢您的回答。我只有几个问题。首先是如何使用上述方法将 json 数据传递给 showAlbumById 函数?那是用于显示给定专辑画廊的功能吗?点击事件也是在函数之外还是在 showAlbumsById 函数内部?
  • 1.您不需要将数据传递给函数,因为它是在最初从 JSON 获取后存储的。因此,您只需将变量albumData 声明在相同或更高的范围内,即可供showAlbumByID 函数使用。代码的编写方式showAlbumByID 在 JSON 请求返回之前永远不会被调用,所以你会知道它一直在那里。
  • 2.是的 showAlbumByID 会被调用来显示一个单独的画廊,你会在专辑点击、浏览器返回/转发到画廊视图时调用它,以及在初始化结束时加载当前画廊(例如,如果你访问了“ /mypage.html?id=1" 直接或刷新页面)。
  • 3.您将专辑点击事件绑定在同一位置,在 showAlbums 内,您正在构建整个专辑索引。处理程序 调用 showAlbumsByID,所以不,它不会进入该函数。应该去同一个地方。
  • 非常感谢您的帮助!我明白我现在错过了什么。
猜你喜欢
  • 2012-04-03
  • 1970-01-01
  • 2014-01-31
  • 1970-01-01
  • 1970-01-01
  • 2018-12-13
  • 2023-03-17
  • 2014-12-19
  • 1970-01-01
相关资源
最近更新 更多