防止用户使用hashbang在单页应用中留下路线 [英] Prevent user to leave the route in a single page app with hashbang

查看:71
本文介绍了防止用户使用hashbang在单页应用中留下路线的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在为我的单页应用程序使用Sammy.js.我想创建类似于SO的功能(当您键入问题并尝试离开页面时,它会询问您是否确定).

I am using Sammy.js for my single page app. I want to create functionality similar to SO (the one when you type your question and try to leave the page and it is asking you if you are sure).

如果它不是单页应用程序,那么我会做类似的事情:

If it would not be a single page app, I would just do something like:

$(window).bind('beforeunload', function(){
  return 'Are you sure you want to leave?';
});

问题在于,在单页面应用程序中,用户实际上并没有离开页面,而是更改了他的document.location.hash(他可以通过关闭页面来离开页面).有没有一种方法可以使SPA变得相似,最好是使用sammy.js?

The problem is that in single page app user do not actually leave the page, but rather changing his document.location.hash (he can leave the page by closing it). Is there a way to make something similar for a SPA, preferably with sammy.js?

推荐答案

在我的工作中,我们在Single Page Webapp中也有类似的问题要解决.我们有一些页面可能很脏,如果有的话,我们希望阻止导航离开该页面,直到用户确认可以这样做为止.由于我们想防止导航,因此我们无法监听onhashchange事件,该事件是在更改哈希之后而不是之前触发的.因此,我们决定覆盖默认的LocationProxy,以包含允许我们在更改位置之前有选择地阻止导航的逻辑.

We had a similar problem to solve in our Single Page Webapp at my work. We had some pages that could be dirty and, if they were, we wanted to prevent navigation away from that page until a user verifies it's okay to do so. Since we wanted to prevent navigation, we couldn't listen for the onhashchange event, which is fired after the hash is changed, not before. Therefore, we decided to override the default LocationProxy to include logic that allowed us to optionally prevent the navigation before the location was changed.

请记住,这是我们使用的代理:

With that in mind, here is the proxy that we used:

PreventableLocationProxy = (function () {
    function PreventableLocationProxy(delegateProxy, navigationValidators) {
        /// <summary>This is an implementation of a Sammy Location Proxy that allows cancelling of setting a location based on the validators passed in.</summary>
        /// <param name="delegateProxy" type="Sammy.DefaultLocationProxy">The Location Proxy which we will delegate all method calls to.</param>
        /// <param name="navigationValidators" type="Function" parameterArray="true" mayBeNull="true">One or more validator functions that will be called whenever someone tries to change the location.</param>
        this.delegateProxy = delegateProxy;
        this.navigationValidators = Array.prototype.slice.call(arguments, 1);
    }

    PreventableLocationProxy.prototype.bind = function () {
        this.delegateProxy.bind();
    };

    PreventableLocationProxy.prototype.unbind = function () {
        this.delegateProxy.unbind();
    };

    PreventableLocationProxy.prototype.getLocation = function () {
        return this.delegateProxy.getLocation();
    };

    PreventableLocationProxy.prototype.setLocation = function (new_location) {
        var doNavigation = true;
        _.each(this.navigationValidators, function (navValidator) {
            if (_.isFunction(navValidator)) {
                // I don't just want to plug the result of the validator in, it could be anything!
                var okayToNavigate = navValidator(new_location);
                // A validator explicitly returning false should cancel the setLocation call. All other values will
                // allow navigation still.
                if (okayToNavigate === false) {
                    doNavigation = false;
                }
            }
        });
        if (doNavigation) {
            return this.delegateProxy.setLocation(new_location);
        }
    };

    return PreventableLocationProxy;
}());

此代码本身非常简单,它是一个带有委托代理的javascript对象,以及一个或多个验证器函数.如果这些验证器中的任何一个显式返回false,则导航将被阻止并且位置将不会更改.否则,将允许导航.为了使此工作有效,我们必须覆盖锚标记的默认onclick处理,以使其通过Sammy.Application.setLocation进行路由.不过,一旦完成,这无疑使我们的应用程序可以处理脏页逻辑.

This code is pretty simple in and of itself, it is a javascript object that takes a delegate proxy, as well as one or more validator functions. If any of those validators explicitly return false, then the navigation is prevented and the location won't change. Otherwise, the navigation is allowed. In order to make this work, we had to override our anchor tags' default onclick handling to route it through Sammy.Application.setLocation. Once done, though, this cleanly allowed our application to handle the dirty page logic.

出于良好的考虑,这是我们的脏页验证器:

For good measure, here is our dirty page validator:

function preventNavigationIfDirty(new_location) {
    /// <summary>This is an implementation of a Sammy Location Proxy that allows cancelling of setting a location based on the validators passed in.</summary>
    /// <param name="new_location" type="String">The location that will be navigated to.</param>
    var currentPageModels = [];
    var dirtyPageModels = [];
    //-----

    // Get the IDs of the current virtual page(s), if any exist.
    currentPageModels = _.keys(our.namespace.currentPageModels);

    // Iterate through all models on the current page, looking for any that are dirty and haven't had their changes abored.
    _.forEach(currentPageModels, function (currentPage) {
        if (currentPage.isDirty() && currentPage.cancelled === false) {
            dirtyPageModels.push(currentPage);
        }
    });

    // I only want to show a confirmation dialog if we actually have dirty pages that haven't been cancelled.
    if (dirtyPageModels.length > 0) {
        // Show a dialog with the buttons okay and cancel, and listen for the okay button's onclick event.
        our.namespace.confirmDirtyNavigation(true, function () {
            // If the user has said they want to navigate away, then mark all dirty pages with the cancelled
            // property then do the navigating again. No pages will then prevent the navigation, unlike this
            // first run.

            _.each(dirtyPageModels, function (dirtyPage) {
                dirtyPage.cancelled = true;
            });

            our.namespace.sammy.setLocation(new_location);
        });

        // Returns false in order to explicitly cancel the navigation. We don't need to return anything in any
        // other case.
        return false;
    }
}

请记住,如果用户显式更改位置,则此解决方案将不起作用,但这不是我们要支持的用例.希望这可以使您更接近自己的解决方案.

Remember, this solution won't work if the user explicitly changes the location, but that wasn't a use case that we wanted to support. Hopefully this gets you closer to a solution of your own.

这篇关于防止用户使用hashbang在单页应用中留下路线的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆