如何使用popstate事件判断前进或后退按钮被按下

9

我做了一些研究,发现popstate事件在历史记录更改时触发,但似乎没有内置的方法可以确定用户是单击浏览器的后退按钮还是前进按钮。

我的用例是,在ajax应用程序中转换路由时,当回到历史记录或前进历史记录时,会出现方向动画。我需要确定用户是向后还是向前,以便动画有意义。遗憾的是,popstate事件不支持事件的方向。

我还要提到,我的应用程序是一个AngularJS应用程序,如果有特定于Angular的答案,那就更好了,尽管更通用的JavaScript解决方案将是最佳选择。


为什么不利用变量呢?只需在每个状态中保存一个增量状态ID并保存上一个状态的ID。当弹出时,计算旧状态和新状态之间的差异,并查看用户走了哪个“方向”。但是,是的,浏览器本地实现会很好。 - Kiruse
是的,这很有道理。我可以在应用程序本身中存储全局状态来确定用户的移动方向。虽然我不想这样跟踪,但如果没有其他方法来确定历史记录的方向,我想这就是需要做的事情。谢谢! - nek4life
@Umur 那个其他问题指定了使用pushState的应用程序。无论如何,我在那里发布了一个通用解决方案。它可能也能回答这个OP的问题。 - Michael Allan
1个回答

5

我不确定哪种理解是正确的,但是我对HTML5 pushstate的理解与此不同。

推送状态支持简单地允许您捕获在浏览器中的URL更改,否则这些更改将被发送为请求到服务器(您的或其他人的)。 它的目的不是为您提供“前进”和“后退”事件,而更像是一般的“位置更改”事件。 然后,你的应用程序负责检查URL并确定用户试图去哪里。

想象一下:如果用户在您的应用程序中点击了您想要使用JavaScript处理的链接? 您将设置一些事件处理程序,这些处理程序将捕获单击并以某种方式操纵您的应用程序。 因此,点击“向后”或“向前”就像单击链接,但您获得的仅是用户尝试查看的URL - 没有链接可绑定事件。

那么你怎么知道用户想要做什么? 您可以使用全局变量或任何其他方法来管理状态。 如果您想减少代码重复,您可以使用URL处理所有应用程序路由。 因此,您的单击处理程序不会绑定到特定的链接(或一组链接),而是可以捕获浏览器URL的更改,然后确定如何处理新的URL。

BackboneJS使用路由器对象来完成此操作,其中特定路径与特定的路由器函数绑定,这些函数以某种方式设置应用程序的状态,例如:

MyAppRouter = Backbone.Router.extend({
    routes: {
        'home': 'setupHomeScreen',
        'recipes': 'setupRecipesList',
        'recipes/:id': 'setupRecipeScreen'
    },

    setupHomeScreen: function() {
        // ...
    },

    setupRecipesList: function() {
        // ...
    },

    setupRecipeScreen: function(id) {
        // ...
    },

    // ...

});

请原谅在一个Angular问题上出现的Backbone代码。由于我仍在学习The Angular Way,并且来自形成了我对pushstate理解的Backbone背景。

回答您的问题

如果您的视图形成某种层次结构或顺序,您可以将其存储在全局变量中。也许您决定为每个视图分配ID,然后每次浏览器状态更改时,将这些ID推入数组中。

var viewHistory = [];

// ... they visited the recipe list. push it into the history
viewHistory.push('recipeList');

// ... they visited a particular recipe. push it into the history
viewHistory.push('recipe:13');

// ... they clicked the "back" button. we know from the URL that they want
// the recipeList, but we don't know if they're trying to go forward or back.
var nextView = 'recipeList';
if (viewHistory.indexOf(nextView) > 0) {
    // *** Back Button Clicked ***
    // this logic assumes that there is never a recipeList nested
    // under another recipeList in the view hierarchy
    animateBack(nextView);

    // don't forget to remove 'recipeList' from the history
    viewHistory.splice(viewHistory.indexOf(nextView), viewHistory.length);
} else {
    // *** They arrived some other way ***
    animateForward(nextView);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接