在 FF 中的 iframe 中使用 "replaceWith" 运行 在 Ember 应用程序中使用 "history.back" 的奇怪行为

Odd behavior with "history.back" in Ember app using "replaceWith" running in iframe in FF

更新:这不是 Ember 中的错误,而是 Firefox 中的错误。参见 https://bugzilla.mozilla.org/show_bug.cgi?id=301307。一旦赏金到期,我将删除这个问题(除非有人提出解决方法)。

我在 iframe 中有一个 Ember 应用 运行。页面A有一个link到页面B,页面B有一个link到页面C使用'Route#replaceWith'实现,这样B就不会留在历史堆栈中。页面 C 有一个 link 调用 history.back(),它应该 return 到页面 A。它对页面 A 执行 return,但在 Firefox 中 仅在重新加载后页面。没有理由重新加载页面,并且在 Chrome 中未观察到此行为。此行为也不会发生,除非应用程序在 iframe 中 运行。

这是应用程序:

// router.js
var Router = Ember.Router.extend({location:'hash'});
Router.map(function() { 'abc'.split('').forEach(x => this.route(x));});
export default Router;

// a/route.js
export default Ember.Route.extend({actions:{b:function(){this.transitionTo('b');}}});

// a/template.js
This is A.
<a href="#" {{action 'b'}}>Goto B!</a>

// b/route.js
import Ember from 'ember';
export default Ember.Route.extend({ actions: { link: function() { this.replaceWith('c'); } } });

// b/template.js
This is B.
<a href="#" {{action 'link'}}>GOTO C (no history entry)</a>

// c/route.js
export default Ember.Route.extend({ actions: { back: function() { history.back(); } } });

// c/template.hbs
This is C
<a href="#" {{action 'back'}}>Go back</a>

如果我将 B 中的 replaceWith 更改为 transitionTo,并将 C 中的 history.back() 更改为 history.go(-2),则一切正常,不会发生重新加载。但这不是一个可行的解决方案,因为浏览器后退按钮还必须将用户从 C 返回到 A。

我正在使用 locationType: 'hash',无法轻易更改。 locationType: 'history'.

不会出现此问题

我能想到为什么 Firefox 在尝试 return 到 A 时可能会重新加载页面的唯一原因是由于更积极的缓存管理。如果这确实是问题所在,那么我想知道是否有某种方法可以告诉 Firefox 放松并从缓存中将页面返回到历史记录中,而不是再次返回到服务器。

仅供参考,这是一个新鲜的小 Ember 应用程序 运行 堆栈中所有内容的最新版本。

感谢所有想法。

保持散列位置类型并解决 Firefox 错误的一种方法是通过扩展内置 Ember HashLocation 并重写 replaceURL 函数以使用 history.replaceState 而不是 location.replace.

HashWithFFWorkaroundLocation = Ember.HashLocation.extend({
  implementation: 'hash-with-ff-workaround',

  replaceURL(path) {
    var history = this.get('history') || window.history;

    var useFixOnlyForFF = true; // Use the fix only in Firefox?
    var isFF = navigator.userAgent.toLowerCase().indexOf('firefox') > -1;

    var useFix = useFixOnlyForFF && isFF || !useFixOnlyForFF;

    if (useFix && 'object' === typeof history && 'function' === typeof history.replaceState)
    {
        var state = { path: path };
        history.replaceState(state, null, '#' + path);
    }
    else
    {
        // Next line is the original implementation which triggers a bug in Firefox
        // See: https://bugzilla.mozilla.org/show_bug.cgi?id=301307
        this.get('location').replace('#' + path);
    }

    this.set('lastSetUrl', path);
  }
});

然后您将自定义实现注册为具有初始值设定项的新位置类型

Ember.Application.initializer({
  name: 'hash-with-ff-workaround-location',

  initialize: function(container, application) {
    // register the custom implementation for locationType: hash-with-ff-workaround
    application.register('location:hash-with-ff-workaround', HashWithFFWorkaroundLocation);
  }
});

将上述代码添加到项目后,您需要在现有代码中更改的唯一行是

// router.js
var Router = Ember.Router.extend({ location: 'hash-with-ff-workaround' });

你可以正常调用this.replaceWith('c');.

这是 jsFiddle 演示:http://jsfiddle.net/Ma3x/hs39vbqg/6/

在 jsFiddle 中,我启用了对所有路由步骤的详细记录。如果您检查控制台输出,您可以看到在使用 Back/Forward 按钮或 history.back/forward.[=15 时,转换正常地从 c 返回到 a 并向前返回到 c 跳过 b 正如预期的那样=]