javascript 如何在单页移动 Web 应用程序中实现我自己的历史堆栈?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10846248/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-26 11:14:21  来源:igfitidea点击:

How to implement my own history stack in a single page mobile web application?

javascriptmobilebackbone.jsbrowser-historyzepto

提问by alex

I have a single-page mobile application developed with Backbone and Zepto.

我有一个用 Backbone 和 Zepto 开发的单页移动应用程序。

It works correctly with the back/forward buttons in the browser.

它与浏览器中的后退/前进按钮一起正常工作。

When the user navigates to a page, the newcontent slides in from the right as the oldcontents slides away to the left (and out of the viewport). I want the same thing to happen if the user presses the "forward" browser button. This all works.

当用户导航到一个页面时,内容从右侧滑入,而内容滑向左侧(并滑出视口)。如果用户按下“前进”浏览器按钮,我希望发生同样的事情。这一切都有效。

I've got a class that I add to the body element navigate-backthat will flip this behaviour, so when the user navigates back with the browser's back button, they see the content sliding backin from the left and the other content sliding into the right. Basically just the opposite of going forward.

我有一个添加到 body 元素的类navigate-back,它将翻转此行为,因此当用户使用浏览器的后退按钮向后导航时,他们会看到内容从左侧滑,其他内容滑入右侧。基本上与前进相反。

I need to detect if the user is navigating backwards so I can invoke the alternate behaviour. I have tried implementing my own history stack, but I've ran into lots of problems where sometimes it marks a forward as a backnavigation which ruins the visual cue. It's descended into a kludge of hacks now and probably would only embarrass me if I posted it.

我需要检测用户是否向后导航,以便我可以调用替代行为。我曾尝试实现我自己的历史堆栈,但我遇到了很多问题,有时它将向前标记为向后导航,这会破坏视觉提示。它现在陷入了一堆黑客攻击,如果我发布它可能只会让我感到尴尬。

What is the best way to implement my own history stack so I can detect if the user is navigating forward/back in the context of a single-page Backbone mobile application?

实现我自己的历史堆栈的最佳方法是什么,以便我可以检测用户是否在单页 Backbone 移动应用程序的上下文中向前/向后导航?

采纳答案by David Mulder

I don't know about backbone.js1, but I have helped develop a mobile application which had to implement exactly this behavior in html5, so I should be able go give some good advice:

我不知道 Backbone.js 1,但我帮助开发了一个移动应用程序,它必须在 html5 中完全实现这种行为,所以我应该能够给出一些好的建议:

First of all it's good to know that the history.pushStatefunction exists. The big problem with it though is that it is supported up to android 2.3, but not on android 3 till android 4.0.3. As kiranvj points out correctly this can be solved by using the popular history.jslibrary which provides a polyfill solution for the lack of the history functionality.

首先,很高兴知道该history.pushState函数存在。它的最大问题是它支持 android 2.3,但不支持 android 3 直到 android 4.0.3。正如 kiranvj 正确指出的那样,这可以通过使用流行的history.js库来解决,该库为缺乏历史功能提供了一个 polyfill 解决方案。

Now, getting to your actual problem, the way I implemented the history direction animations was by adding data to the pushStatefunction ( history.pushState(data,title,url)) with which I identified the logical position of the page. In my application I wasn't only limited to a horizontal bar, but in your case you would keep track of position where any new loaded page get's a position which is one higher then your current page. E.g.

现在,解决您的实际问题,我实现历史方向动画的方式是向pushState函数 ( history.pushState(data,title,url))添加数据,我用它来确定页面的逻辑位置。在我的应用程序中,我不仅限于水平条,而且在您的情况下,您将跟踪任何新加载页面的位置,该位置比当前页面高一个位置。例如

History.pushState({position:History.getState().data.position+1},"Your title","Your URL");

Next, when the window.onstatechangeor window.onanchorchangeevent triggers you observe whether the position is higher or lower than your current page (e.g. by using the history.jsHistory.getState()function which I used above) and depending on this you decide in which direction to move (lower is to the left, and higher is to the right), as is illustrated by the image below:

接下来,当window.onstatechangewindow.onanchorchange事件触发时,您观察位置是否高于或低于当前页面(例如,通过使用我上面使用的history.jsHistory.getState()函数),并根据此决定移动的方向(较低的是左侧,右侧较高),如下图所示:

Illustration of history events

历史事件的插图

You will also note that I already assumed on the first page that you have {position:1}, whereas normally the first page will have no state information. The way this can be achieved is by using history.replaceStatewhich replaces the current empty state with a more informative state. Alternatively you can also check for an empty state on any of the previously mentioned events and if it's empty you assume it to be the left most one ({position:1}).

您还会注意到,我已经在第一页假定您拥有{position:1},而通常第一页将没有状态信息。实现这一点的方法是使用history.replaceStatewhich 用信息更多的状态替换当前的空状态。或者,您还可以检查前面提到的任何事件的空状态,如果它是空的,则假设它是最左边的 ( {position:1})。

Hope this helps and if you have any additional questions feel free to ask.

希望这会有所帮助,如果您有任何其他问题,请随时提出。

Please note that this answer assumes you are using history.jsand you would need to listen to slightly different events (such as onpopstate) and use slightly different structures (historyrather than History) if you would want to build your own solution.

请注意,此答案假设您使用的是history.js,并且如果您想构建自己的解决方案,则需要侦听略有不同的事件(例如onpopstate)并使用略有不同的结构(history而不是History)。

It is also useful to note that it is possible to build this with your own queue array which gives you a lot more control, but will not work in combination with the browser's back button. This is a big issue with browser sites, however is far easier in case you are building a cordova(a.k.a. phonegap) web application.

还需要注意的是,可以使用您自己的队列数组来构建它,这为您提供了更多控制权,但不能与浏览器的后退按钮结合使用。这是浏览器站点的一个大问题,但是如果您正在构建cordova(又名phonegap)Web 应用程序,则要容易得多



1 Just read about it and it appears to do some history handling of its own, which mightmake it more complex to integrate the technique described above.

1 只需阅读它,它似乎会自行处理一些历史记录,这可能会使集成上述技术变得更加复杂。

回答by o.v.

If you're working on a truesingle-page app, why not you set up an array to hold history urls in a js variable (as opposed to relying on something like history.pushStateand its support)?

如果您正在开发一个真正的单页应用程序,为什么不设置一个数组来在 js 变量中保存历史 URL(而不是依赖于类似的东西history.pushState及其支持)?

Whenever a new page is navigated to, you can push its url into the array, whenever a "back" button is pressed, you can retrieve the url needed as far back as you want. This will work perfectly as long as you correctly discard urls when the user goes back a few steps and then navigates to a newlink.

每当导航到一个新页面时,您都可以将其 url 推送到数组中,每当按下“后退”按钮时,您都可以根据需要检索所需的 url。只要在用户返回几步然后导航到链接时正确丢弃 url,这将完美运行。

I've never tried implementing this to be used for page history, but this worked perfectly well for in-page undo-redo logic.

我从未尝试将其实现为用于页面历史记录,但这对于页内撤消重做逻辑非常有效。

Update:

更新:

After further research, the approach above would not work for a page reload as it would be an action occuring outside of history handling available through JS. It would still work for tracking back/forward transitions, but such history will be lost on navigating to a url external to the app or a page refresh. David Mulder's answer seems to lack this limitation by relying on browser-level history that persists outside of the page scope.

经过进一步研究,上述方法不适用于页面重新加载,因为它是在通过 JS 可用的历史处理之外发生的操作。它仍然可以用于跟踪后退/前进转换,但是在导航到应用程序外部的 url 或页面刷新时,此类历史记录将丢失。David Mulder 的答案似乎没有这种限制,因为它依赖于在页面范围之外持续存在的浏览器级历史记录。

回答by kiranvj

I had the same issue when working with Zepto on mobile with single page - multiple views.

在移动设备上使用单页多视图使用 Zepto 时,我遇到了同样的问题。

Initially I used html5 statechange and onhashchange. It all have some issues in one or other mobile device. Finally I used Zepto history plugin from here https://github.com/browserstate/history.js

最初我使用 html5 statechange 和 onhashchange。它在一个或其他移动设备中都有一些问题。最后我从这里使用了 Zepto 历史插件https://github.com/browserstate/history.js

It somewhat solved most of the issues. Try it, it will be useful, it handle html4 and html5 features wherever possible.

它在某种程度上解决了大部分问题。试试吧,它会很有用,它会尽可能处理 html4 和 html5 功能。

回答by kiran

Use this thing in single page mobile application this will allow to the history and move the user to back.

在单页移动应用程序中使用这个东西,这将允许历史记录并将用户移回原处。

function onBackKeyDown() {
    history.go(-1);
    navigator.app.backHistory();
}

回答by ddotsenko

Sammy.js's v.6.x branch (the one that relies just on hash changes) is a perfect, simplest, most browser-compatible approach to tracking history. There, history is not tracked at all, as Sammy just watches for hashchange.

Sammy.js 的 v.6.x 分支(仅依赖于哈希更改的分支)是一种完美、最简单、最兼容浏览器的历史跟踪方法。在那里,历史根本没有被跟踪,因为 Sammy 只是在观察 hashchange。

Relying on "#/slide/123" allows you to support hard page reloads, and simplifies the work

依靠“#/slide/123”支持硬页面重载,简化工作

Peel off the last part (slide number) on each page view, push into global. On new route, see if number is more or less than what is stored in global and do the correct (left or right) animation. If global is undefined, no animation.

剥离每个页面视图的最后一部分(幻灯片编号),推入全局。在新路线上,查看 number 是否大于或小于 global 中存储的数量,并执行正确的(左或右)动画。如果 global 未定义,则没有动画。