使用 Sammy.js 取消路由而不影响历史

Posted

技术标签:

【中文标题】使用 Sammy.js 取消路由而不影响历史【英文标题】:Cancel route using Sammy.js without affecting history 【发布时间】:2012-06-09 11:11:21 【问题描述】:

我想拦截 Sammy 的所有路由更改,以首先检查是否有待处理的操作。我使用sammy.before API 完成了此操作,并返回 false 以取消路由。这使用户保持在“页面”上,但它仍然会更改浏览器地址栏中的哈希并将路由添加到浏览器的历史记录中。如果我取消路线,我不希望它出现在地址栏或历史记录中,而是希望地址保持不变。

目前,为了解决这个问题,我可以调用 window.history.back (yuk) 以返回到历史记录中的原始位置,或者调用 sammy.redirect。两者都不太理想。

有没有办法让 sammy 真正取消路线,使其停留在当前路线/页面上,保持地址栏不变,并且不添加到历史记录中?

如果没有,是否有另一个路由库可以做到这一点?

sammy.before(/.*/, function () 
    // Can cancel the route if this returns false
    var response = routeMediator.canLeave();

if (!isRedirecting && !response.val) 
    isRedirecting = true;
    // Keep hash url the same in address bar
    window.history.back();
    //this.redirect('#/SpecificPreviousPage'); 

else 
    isRedirecting = false;

return response.val;
);

【问题讨论】:

【参考方案1】:

万一其他人碰到这个,这就是我结束的地方。我决定使用 sammy 的context.setLocation 功能来处理路由重置。

sammy.before(/.*/, function () 
    // Can cancel the route if this returns false
    var
        context = this,
        response = routeMediator.canLeave();

    if (!isRedirecting && !response.val) 
        isRedirecting = true;
        toastr.warning(response.message); // toastr displays the message
        // Keep hash url the same in address bar
        context.app.setLocation(currentHash);
    
    else 
        isRedirecting = false;
        currentHash = context.app.getLocation();
    
    return response.val;
);

【讨论】:

哈哈哈约翰,我是通过搜索有关您如何在 SPA 系列中实现这一目标的更多信息来到这里的 :-)【参考方案2】:

使用问题和答案中提供的代码时,您必须注意,您取消的路由也将被阻止以供将来所有调用, routeMediator.canLeave 将不会再次评估。使用此方法无法调用两次路由并根据当前状态取消它。

【讨论】:

嗯。我很好奇你为什么这么说。我已经使用了这段代码,它不会阻止未来对 canLeave 的调用。你能详细说明吗?如果我有错误,我想了解如何修复它。 Sammy 之前的文档说:“如果任何回调显式返回 false,则执行任何进一步的回调和路由本身都会停止。” - 这是我在上面的代码中观察到的。这只发生在连续两次访问被阻塞的路由时。在一切正常访问其他路线时。 路线已停止,是的。但它并没有说将来对该路由的调用被阻止。我没有看到这种行为,我可以阻止它离开,然后它下次仍然调用它。【参考方案3】:

我可以产生与 John Papa 在 SPA/Knockout 课程中使用 SammyJS 时相同的结果。

我使用 Cros-s-roads JS 作为路由器,它依靠 Hasher JS 监听浏览器“发出”的 URL 变化。

代码示例是:

hasher.changed.add(function(hash, oldHash) 
    if (pageViewModel.isDirty())
        console.log('trying to leave from ' + oldHash + ' to ' + hash);

        hasher.changed.active = false;
        hasher.setHash(oldHash);
        hasher.changed.active = true;

        alert('cannot leave. dirty.');
    
    else 
        cros-s-roads.parse(hash);
        console.log('hash changed from ' + oldHash + ' to ' + hash);
        
);

【讨论】:

【参考方案4】:

在重温一个较旧的项目并遇到类似情况后,我想分享另一种方法,以防万一其他人被引导到这里。

本质上需要的是一种现代的“身份验证”模式,用于拦截页面并根据凭据进行重定向。

使用此处定义的Sammy.around(callback) 效果很好: Sammy.js docs: Sammy.Application around(callback)

然后,只需执行以下操作...

(function ($) 
    var app = Sammy("body");

    app.around(checkLoggedIn);

    function canAccess(hash) 
        /* access logic goes here */
        return true;
    

    // Authentication Guard
    function authGuard(callback) 
        var context = this;
        var currentHash = app.getLocation();
        if (!canAccess(currentHash)) 
            // redirect
            context.redirect("#/login");
        
        else 
            // execute the route path
            callback();
        
    ;

)(jQuery);

【讨论】:

以上是关于使用 Sammy.js 取消路由而不影响历史的主要内容,如果未能解决你的问题,请参考以下文章

前端路由参数说明

Vue路由切换&Axios接口取消重复请求

vue路由跳转取消上个页面的异步请求

如何使用带有历史回退和 expressjs 路由的 vuejs 路由

openwrt取消旁路由模式无法进入

ExpressJS 更改路由而不刷新