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

9 firefox ember.js ember-router

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

我有一个在iframe中运行的Ember应用程序.页面A有一个指向页面B的链接,页面B有一个指向使用"Route#replaceWith"实现的页面C的链接,因此B不会保留在历史堆栈中.页面C有一个调用的链接history.back(),它应返回到页面A.它确实返回到页面A,但仅在重新加载页面后才返回到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>
Run Code Online (Sandbox Code Playgroud)

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

我正在使用locationType: 'hash',不能轻易改变这一点.问题不会发生locationType: 'history'.

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

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

任何和所有的想法都赞赏.

Ma3*_*a3x 2

保留哈希位置类型并解决 Firefox bug 的一种方法是通过扩展内置 Ember HashLocation 并重写 ReplaceURL 函数以使用 History.replaceState 而不是 location.replace 来创建自定义 HashLocation 实现。

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);
  }
});
Run Code Online (Sandbox Code Playgroud)

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

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);
  }
});
Run Code Online (Sandbox Code Playgroud)

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

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

并且您可以正常拨打电话this.replaceWith('c');

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

在 jsFiddle 中,我启用了所有路由步骤的详细日志记录。如果检查控制台输出,您可以看到在使用“后退/前进”按钮或history.back/forward时,转换正常地从c返回到a并向前返回到c,跳过b。