问题
I am trying very hard to implement history.js a jQuery plugin for IE 8 and 9. The demo seems to be fine in IE10+ and other modern browsers but I'm not able to understand the problem below for IE<=9. The demo is a asp.net mvc5 application where I want to provide a single page user experience where I'm just loading partial views and performing a post action via ajax. All the views load in a #shell
div in my master view. May be I am missing something!!
My demo app starts with http://localhost:1089/
which is the first request that renders a login page. Any other pushState() causes a change in the url with appending #Home/About?ref=one
.
Following is my script that is executed in layout.cshtml which is loaded only once:
(function (window, undefined) {
History.Adapter.bind(window, 'statechange', function () {
var state = History.getState();
if (state.data.options == undefined) {
alert("options is undefined");
var options = {
url: state.url,
type: "GET",
dataType: "html"
};
GetPartial(options);
} else {
GetPartial(state.data.options);
}
});
})(window);
$(document).on('click', 'a', function (e) {
e.preventDefault();
var options = {
url: $(this).prop('href'),
type: "GET",
dataType: "html"
};
History.pushState({ options: options }, $(this).text(), $(this).prop('href'));
});
function GetPartial(options) {
if (options) {
$.ajax({
url: options.url,
type: options.type || 'GET',
dataType: options.datatype || 'html',
async: true,
data: options.dataToPost,
beforeSend: function() {
$("#loaderMain").show();
},
complete: function() {
$("#loaderMain").hide();
},
cache: false,
}).success(function(response, status, xhr) {
var ct = xhr.getResponseHeader("content-type") || "";
if (ct.indexOf('html') > -1) {
// returned result is of type html, so act accordingly
if (options.selector == undefined) {
InjectContentToShell(response);
} else {
$(options.selector).empty().append(response);
}
} else if (ct.indexOf('json') > -1) {
// returned result is of type json, so act accordingly
}
}).fail(function(e) {
console.log(e);
});
}
}
function InjectContentToShell(content) {
$('#shell').fadeOut(100, function () {
$(this).empty().append(content);
}).fadeIn(100);
}
When I render this first page, I add one entry to History by pushState method like this:
$('#submit').on('click', function (e) {
e.preventDefault();
var formInstance = $(this).closest('form'),
dataToPost = formInstance.serialize();
var options = {
url: formInstance.prop('action'),
type: formInstance.prop('method'),
dataType: "html",
dataToPost: dataToPost
};
History.pushState({ options: options }, "Home - All Summary Views", "/Home/Index");
});
Pushing the state above, changes the url to http://localhost:1089/#Home/Index
in html4 browser which is fine. I am able to go back and forward. This works well.
Now when I refresh the page in html4 browsers, the request sent to server is for first url i.e. http://localhost:1089/
which bring the first view to the client. So, the user can see the first page i.e. login screen. And then statechange
event is fired and the state url still remembers the last url where page was refreshed and a new request is made for this url to server. The response is then injected in shell.
So, the problem is - on page refresh, user is getting two views instantly - the initial page where the user started his browsing session and soon the second page is loaded from the server and added to shell via animation as when the statechange event is fired, the History.getState()
still remembers the last url.
I don't want to show this initial page on page refresh. If this is solved, then everything works fine with this history.js I think!
The above problem is also mentioned as a concept of bookmarking in the this article. Refer to the first figure and the text written above it.
My demo application works fine in html5 browsers as on every History.pushState()
the browser's url is changed to the url I have specified. And when page is refreshed, the request is sent to the server as per that url and not with the first url in the browsing session started.
回答1:
After trying many things, I have come up with the following solution to avoid showing the first view i.e. login page to the users with html4 browser:
I have created a view "Index" that is the first view being rendered. Which doesn't have any html content but has this script:
<script>
$(function () {
if (History.getCurrentIndex() == 0) {
var options = {
url: "/Account/Login",
type: "GET",
dataType: "html"
};
History.pushState({ options: options }, "Login Page", "/Account/Login");
}
});
</script>
The above code checks if the current index is 0 or not. If it is 0, then it means that user has just started his browsing history and it should give a login screen. If it is not 0, then it means that user was on some other step of user journey within the application which does nothing. And once this view is rendered the statechange
event is fired which already has the information about the url of the page where user requested for refresh. As per the logic of statechange event handler above in my question, that resource is requested from the server and injected in the #shell
container.
The above solution is working very well and gives the same experience to user as if they are on html5 browser. The above code works for me but will be glad to know if someone has any other solution.
来源:https://stackoverflow.com/questions/21910467/how-to-avoid-rendering-the-initial-view-of-browsing-session-when-page-is-refresh