[英]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. 我注意到一些可用的框架( navrouter
和sammy.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)
sammy.js
or navrouter
? 还是我需要额外的组件,例如sammy.js
或navrouter
? After a day of struggling I came to the following conclusion: 经过一天的奋斗,我得出以下结论:
#
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 template
的javascript
文件。 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.