简体   繁体   English

如何在MVC 5 SPA模板中使用历史记录进行导航?

[英]How to navigate, with history, in MVC 5 SPA template?

I am struggling with the navigation in the VS2013 SPA MVC-5 template. 我在VS2013 SPA MVC-5模板中的导航中苦苦挣扎。 I made 2 assumptions (because I couldn't find good references), but it seems I am wrong or it is just not working well: 我做了两个假设(因为我找不到很好的参考),但似乎我错了,或者工作不正常:

  • It thought that the navigation was be based on the typical spa # url encoding , for example to navigate to the users account management page directly one should be able to use: http://localhost:18759/#/manage 它认为导航基于典型的spa # url encoding ,例如,直接导航到users account management page应该可以使用: http://localhost:18759/#/manage

  • I also thought that, when navigating across the website (single page) I thought that these # url's where formed by the default knockout.js files, which are included in the template. 我还认为,在浏览网站(单页)时,我认为这些# url's由模板中包含的默认knockout.js文件形成的。 Combined with the previous assumption this would result in a proper history build-up. 结合先前的假设,这将导致适当的历史积累。

http://localhost:18759/#/manage does not seems to navigate to the manage page (other # url's doesn't work either) . http://localhost:18759/#/manage似乎无法导航到manage页面(其他# url's也不起作用)。

I noticed some that some frameworks are available to handle this ( navrouter and sammy.js ) but as far as I can tell it takes quite some effort to implement them, especially if it's already in place in the template. 我注意到一些可用的框架( navroutersammy.js )可用,但据我所知,要实现它们需要花费很多精力,尤其是如果模板中已经存在它们。

As for the reasons why I made these assumptions, there is an article here , which suggests this is in place due to this part: 至于为什么我做这些假设的原因,有一篇文章在这里 ,这表明这是地方由于这一部分:

// app.viewmodel.js - there is a method called "addViewModel()
if (typeof (options.navigatorFactory) !== "undefined") {
        navigator = options.navigatorFactory(self, dataModel);
    } else {
        //suggests "#"-hash navigation
        navigator = function () {
            window.location.hash = options.bindingMemberName;
        };
    } 

But in my own app.viewmodel.js these lines are without reference to the hash at all: 但是在我自己的app.viewmodel.js这些行根本没有引用哈希:

if (typeof (options.navigatorFactory) !== "undefined") {
        navigator = options.navigatorFactory(self, dataModel);
    } else {
        navigator = function () {
            self.errors.removeAll();
            self.view(viewItem);
        };
    }

There is a reference to the hash in app.viewmodel.js here, but this doesn't seem to handle the navigation: 这里在app.viewmodel.js有对哈希的引用,但这似乎无法处理导航:

// Private operations
function cleanUpLocation() {
    window.location.hash = "";

    if (typeof (history.pushState) !== "undefined") {
        history.pushState("", document.title, location.pathname);
    }
}

function getFragment() {
    if (window.location.hash.indexOf("#") === 0) {
        return parseQueryString(window.location.hash.substr(1));
    } else {
        return {};
    }
}

My code to navigate looks like this: 我的导航代码如下所示:

<ul class="nav navbar-nav navbar-right">
     <li data-bind="with: user"><a href="#" data-bind="click: manage">manage</a></li>
</ul>

and the navigation factory is pretty default like: 导航工厂非常默认,例如:

app.addViewModel({
    name: "Manage",
    bindingMemberName: "manage",
    factory: ManageViewModel,
    navigatorFactory: function (app) {
        return function (externalAccessToken, externalError) {
            app.errors.removeAll();
            app.view(app.Views.Manage);

            if (typeof (externalAccessToken) !== "undefined" || 
                typeof (externalError) !== "undefined") {
                   app.manage().addExternalLogin(externalAccessToken, externalError);
            } else {
                app.manage().load();
            };
        }
    }
});

question(s) 问题(S)

  • Should this be working? 这应该工作吗? If so, how can I fix it? 如果是这样,我该如何解决?
  • Or do I need extra components like sammy.js or navrouter ? 还是我需要额外的组件,例如sammy.jsnavrouter

After a day of struggling I came to the following conclusion: 经过一天的奋斗,我得出以下结论:

  • the # navigation doesn't seem present in the default VS2013 MVC 5 SPA template . 默认VS2013 MVC 5 SPA template似乎没有#导航。

I managed to get it working, so I'll sum up the implementation method here. 我设法使其正常工作,因此在这里我将总结实现方法。

Although pagerjs , suggested by Paul Manzotti, does the job pretty well, I have chosen to use sammy.js to perform the navigation. 虽然pagerjs ,保罗Manzotti建议,做工作得很好,我已经选择使用sammy.js执行导航。 Other navigation frameworks should work just as well. 其他导航框架也应该工作。

So the first step is to get it from nuget : 因此,第一步是从nuget获取它:

install-package sammy.js 安装软件包sammy.js

After the installation of sammy.js we need to alter the default VS2013 MVC 5 SPA template 's javascript files. 安装sammy.js之后,我们需要更改默认的VS2013 MVC 5 SPA templatejavascript文件。 I'll sum it up: 我总结一下:

First enable sammy.js . 首先启用sammy.js There are various options of where to put the code, but since I want to use it throughout the entire application I putted it in: ~/Scripts/app/_run.js like this: 有各种各样的代码放置位置选项,但是由于我想在整个应用程序中使用它,因此将其放置在: ~/Scripts/app/_run.js如下所示:

//_run.js
$(function () {
    app.initialize();

    // Activate Knockout
    ko.validation.init({ grouping: { observable: false } });
    ko.applyBindings(app);

    //provides basic '#' navigation
    //run this function after the initialization of the
    //default knockout code.
    Sammy(function () {
        //"#:view" is the parameter's name of the data after the hash tag 
        //it is stored in "this.params.view"
        this.get('#:view', function () {
            //call the navigation functions
            //these are created in the default knockout initiallization
            app["_navigateTo" + this.params.view]();
        });
    }).run("#Home");//Specify the starting page of your application
 });

Next, I wanted the # navigation to work "out of the box". 接下来,我希望#导航“开箱即用”。 A crucial part is that on navigation the # parameter is added to the url So I needed to hook in the navigateTo functions. 一个关键部分是在导航#参数添加到url所以,我需要在挂钩navigateTo功能。 There is a way in ~/Scripts/app/app.viewmodel.js : ~/Scripts/app/app.viewmodel.js有一种方法:

Change: 更改:

//app.viewmodel.js
...
// Add navigation member to AppViewModel (for example, app.NavigateToHome());
self["navigateTo" + options.name] = navigator;

To: 至:

//app.viewmodel.js
...
// Add navigation member to AppViewModel (for example, app.NavigateToHome());
// Override default routing to just set the hash
self["navigateTo" + options.name] = function() {
            window.location.hash = options.name;
    };

    //this one is used by sammy to perform actual default routing
    self["_navigateTo" + options.name] = function() {
        navigator();
    };

A final detail has to be fixed, and that is when a user refreshes it's page, the default route will go to #Home . 最后的细节必须确定,也就是说,当用户刷新页面时,默认路由将转到#Home This is due to the following code in ~/Scripts/app/app.viewmodel.js : 这是由于~/Scripts/app/app.viewmodel.js的以下代码~/Scripts/app/app.viewmodel.js

//app.viewmodel.js
...
self.navigateToLoggedIn = function (userName, accessToken, persistent) {
    self.errors.removeAll();

    if (accessToken) {
        dataModel.setAccessToken(accessToken, persistent)
    }

    self.user(new UserInfoViewModel(self, userName, dataModel));

    //this line only routes to "#Home" when navigation
    //after the login... or register, or something else        
    if (window.location.hash === "#Login" || window.location.hash === "#Register")
        self.navigateToHome();
};

So add the proper if statement to this code and the # is in place. 因此,在此代码中添加适当的if语句,并且#到位。

The proper url to access the manage page will be: 用来访问管理页面的正确URL为:

http://localhost:18759/#Manage

I must say, I haven't had time to give it a proper review (the # url encoding might be used elsewhere and may cause collisions). 我必须说,我还没来得及给它一个适当的审查(在# URL编码可能会被用于其他地方,并可能导致冲突)。 I will update this post if I find some issues. 如果发现一些问题,我将更新此帖子。

Another point: of course there are various alternatives in the way to hook into the routing. 另一点:当然,可以采用多种替代方法来连接路由。 I have chosen these steps because they work in the case I am working on. 我之所以选择这些步骤,是因为它们适用于我正在处理的情况。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM