javascript 根据 Ajax 请求更新整个页面
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5941933/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Update whole page on Ajax request
提问by Nutel
I have an AJAX request that can have two possible outcomes:
我有一个可能有两种结果的 AJAX 请求:
- The server responds with a message which I should place in a
<div>
- The server responds with an HTML page, in this case I need to substitute current page with a new one and change the address (the client knows the address before a request).
- 服务器响应一条消息,我应该把它放在
<div>
- 服务器以 HTML 页面响应,在这种情况下,我需要用新页面替换当前页面并更改地址(客户端在请求之前知道地址)。
What would be the solution if I have the AJAX request that needs to handle both of these cases?
如果我有需要处理这两种情况的 AJAX 请求,那么解决方案是什么?
url = "http://example.com"
ajax.request(callback)
function callback(response) {
if (case2(response)) {
history.pushState({}, "New page", url);
document.innerHTML = response
} else {
updateDiv(response)
}
}
I'm interested in a correct way to implement the first branch, or if the server can somehow compose a headers that will make browser to handle a response as a usual HTTP response and update a page location and content, something like redirect with given content.
我对实现第一个分支的正确方法感兴趣,或者如果服务器可以以某种方式组合一个标头,使浏览器将响应作为通常的 HTTP 响应处理并更新页面位置和内容,例如使用给定内容重定向.
I understand that the server can return a link instead of a page, but in this case one additional stage will be needed on a client - redirect and then populating the new page on the server.
我知道服务器可以返回链接而不是页面,但在这种情况下,客户端需要一个额外的阶段 - 重定向然后在服务器上填充新页面。
回答by T-Bull
Quite frankly, I think that approach is basically broken by design. You shouldn't have to make that decision at that place. For example, the ajax response could only signal that a whole new page should be loaded and the new content then be generated on a second (non-ajax) request to a new URL.
坦率地说,我认为这种方法基本上被设计打破了。你不应该在那个地方做出那个决定。例如,ajax 响应只能表示应该加载一个全新的页面,然后在对新 URL 的第二个(非 ajax)请求中生成新内容。
In case you're forced to take the way you already go, and provided the response content is not very large, you could try Javascript-URIs. Basically, an URI in the form of javascript:"string"
will load a new page which that string is the source code for. So, if response
already is a string, just assigning javascript:response
to window.location.href
should suffice. Maybe you have to do some escaping beforehand. And I don't know, how cross-browser-compatible this approach is.
万一你被迫采取你已经走的路,而且响应内容不是很大,你可以尝试 Javascript-URIs。基本上,形式为 的 URIjavascript:"string"
将加载一个新页面,该页面是该字符串的源代码。所以,如果response
已经是一个字符串,只分配javascript:response
给window.location.href
就足够了。也许你必须事先做一些逃避。我不知道这种方法的跨浏览器兼容性如何。
<a href="javascript:response">load</a>
is also possible.
也是可以的。
A variant of this is building the URL not with the variable name, but with the actual string data. Like
一个变体是不使用变量名称构建 URL,而是使用实际的字符串数据。喜欢
function source2url(src) {
// make valid javascript string from source text
var esc1 = src
.replace(/\/g, '\\')
.replace(/\'/g, '\\'')
.replace(/\x0A/g, '\x0A')
.replace(/\x0D/g, '\x0D');
// make valid url from that
return "javascript:'" + encodeURIComponent(esc1) + "'";
}
window.location.href = source2url(response);
This will, of course, generate pretty large URIs. And you'll always have the Javascript-URI in the address bar.
当然,这会生成相当大的 URI。您将始终在地址栏中看到 Javascript-URI。
UPDATE
更新
A similar approach is to use base64 encoding in a data URI. The Wikipedia entryexplains how it works, including a javascript example. However, you'd have to base64-encodethe content somehow. (Note: You can use data URIs with or without the base64 encoding. You have to see what gives you shorter URIs for your specific content.)
类似的方法是在数据 URI 中使用 base64 编码。在维基百科条目解释它是如何工作的,包括一个javascript例子。但是,您必须以某种方式对内容进行base64 编码。(注意:您可以使用带有或不带有 base64 编码的数据 URI。您必须查看是什么为您的特定内容提供了更短的 URI。)
回答by Dan Manastireanu
I had a similar issue once. A full error page was returned instead of a simple HTML snippet. We eventually fixed this by changing the logic, but here is one of the solutions I found:
我曾经遇到过类似的问题。返回了一个完整的错误页面,而不是一个简单的 HTML 片段。我们最终通过更改逻辑解决了这个问题,但这是我找到的解决方案之一:
document.open();
document.write(responseText);
document.close();
The reason we abandoned this is that on IE there were some problems. I didn't loose any time to investigate why, but it threw an 'Access denied' exception when attempting to write the string. I think there were some <meta>
tags that confused IE, or maybe conditional comments, I'm not sure. (It worked when I used some simple pages...)
我们放弃这个的原因是在 IE 上存在一些问题。我没有浪费任何时间来调查原因,但是在尝试写入字符串时它抛出了“拒绝访问”异常。我认为有些<meta>
标签混淆了 IE,或者可能是条件注释,我不确定。(当我使用一些简单的页面时它起作用了......)
Bottom line is: you shouldn't have to do this, but if there is nothing else you can do (like returning an url string) the code above might work.
底线是:您不应该这样做,但是如果您无能为力(例如返回 url 字符串),则上面的代码可能会起作用。
回答by Eli Grey
It's really easy if the response is valid XML.
如果响应是有效的 XML,那真的很容易。
var new_doc = (new DOMParser).parseFromString(response, "application/xml");
document.replaceChild(document.adoptNode(new_doc.doctype), document.doctype);
document.replaceChild(document.adoptNode(new_doc.documentElement), document.documentElement);
回答by nickb
Since the request is for an updated answer, here's my solution using HTML5's History APIwith jQuery. It should run easily by combining the PHP and HTML parts into one file.
由于请求是更新答案,这是我使用 HTML5 的History API和jQuery 的解决方案。通过将 PHP 和 HTML 部分合并到一个文件中,它应该可以轻松运行。
My solution allows for AJAX to return the following:
我的解决方案允许 AJAX 返回以下内容:
- A message through AJAX, which updates a
<div>
container. - A URL, which causes the browser to redirect to the URL
- A complete HTML page, which calls the History API's
history.pushState()
to add the current URL to the browser's history and replaces the entire HTML on the page with the HTML returned from AJAX.
- 通过 AJAX 的消息,更新
<div>
容器。 - 一个 URL,它使浏览器重定向到该 URL
- 一个完整的 HTML 页面,它调用 History API
history.pushState()
将当前 URL 添加到浏览器的历史记录中,并将页面上的整个 HTML 替换为从 AJAX 返回的 HTML。
PHP
PHP
This is just a sample of what the PHP script will need to return when it is invoked via AJAX. It shows how to encode flags to determine whether the AJAX call should update the container or load a new page, and how to return its result via JSON through json_encode. For completeness, I named this script test.php.
这只是 PHP 脚本通过 AJAX 调用时需要返回的示例。它展示了如何编码标志以确定 AJAX 调用是否应该更新容器或加载新页面,以及如何通过json_encode通过 JSON 返回其结果。为了完整起见,我将此脚本命名为test.php。
<?php
// Random messages to return
$messages = array(
'Stack Overflow',
'Error Message',
'Testing'
);
// If the page was requested via AJAX
if( isset( $_POST['ajax']))
{
$response = array(
'redirect' => // Flag to redirect
( rand() % 2 == 0) ? true : false,
'load_html' => // Flag to load HTML or do URL redirect
( rand() % 2 == 0) ? true : false,
'html' => // Returned HTML
'<html><head><title>AJAX Loaded Title</title></head><body>It works!</body></html>',
'title' => 'History API previous title',
'message' => // Random message
$messages[ (rand() % count( $messages)) ]
);
echo json_encode( $response);
exit;
}
JS
JS
Since I am using jQuery, lets start with that. The following submits an AJAX POST to the server, to the above PHP script at URL test.php. Note that it also sets the POST parameter ajax
to be true
, enabling the PHP script to detect that it received an AJAX request. The dataType
field tells jQuery that the server's response will be in JSON, and that it should decode that JSON to a JSON object in the response callback. Finally, the success
callback, which is fired when the AJAX response is successfully received, determines what to do based on the flags sent from the server.
由于我使用的是 jQuery,让我们从它开始。下面向服务器提交一个 AJAX POST,到 URL test.php的上述 PHP 脚本。请注意,它还将 POST 参数ajax
设置为true
,使 PHP 脚本能够检测到它收到了 AJAX 请求。该dataType
字段告诉 jQuery 服务器的响应将采用 JSON 格式,并且它应该将该 JSON 解码为响应回调中的 JSON 对象。最后,success
当成功接收到 AJAX 响应时会触发回调,它根据从服务器发送的标志确定要执行的操作。
$.ajax({
type: 'POST',
url: "/test.php",
data: {ajax : true},
dataType: "json",
success: function( json) {
if( json.redirect) {
if( json.load_html) {
// If the History API is available
if( !(typeof history.pushState === 'undefined')) {
history.pushState(
{ url: redirect_url, title: document.title},
document.title, // Can also use json.title to set previous page title on server
redirect_url
);
}
// Output the HTML
document.open();
document.write( json.html);
document.close();
}
else {
window.location = redirect_url;
}
}
else {
$('#message').html( json.message);
}
},
});
HTML
HTML
Here is the complete HTML source of my tested file. I tested it in FF4 - FF8. Note that jQuery provides the ready
method to prevent the JS from executing until the DOM is loaded. I've also used Google's hosting of jQuery, so you do not need to upload a copy of jQuery to your server to test this.
这是我测试文件的完整 HTML 源代码。我在 FF4 - FF8 中对其进行了测试。请注意,jQuery 提供了ready
在 DOM 加载之前阻止 JS 执行的方法。我还使用了 Google 托管的 jQuery,因此您无需将 jQuery 的副本上传到您的服务器来进行测试。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.0/jquery.min.js" type="text/javascript"></script>
<title>Default Page</title>
<script type="text/javascript"">
$( document).ready( function() {
$('#ajax_link').click( function() {
var redirect_url = "/test.php";
$.ajax({
type: 'POST',
url: "/test.php",
data: {ajax : true},
dataType: "json",
success: function( json) {
if( json.redirect) {
if( json.load_html) {
// If the History API is available
if( !(typeof history.pushState === 'undefined')) {
history.pushState(
{ url: redirect_url, title: document.title},
document.title, // Can also use json.title to set previous page title on server
redirect_url
);
}
document.open();
document.write( json.html);
document.close();
}
else {
window.location = redirect_url;
}
}
else {
$('#message').html( json.message);
}
},
});
})
});
</script>
</head>
<body>
<div id="message">The default contents of the message</div>
<a id="ajax_link" href="#">Fire AJAX</a>
</body>
</html>
回答by Varun Naharia
Give an id to body <body id="page">
and your other div will be <div id="message"></div>
now your ajax will look like
给 body 一个 id <body id="page">
,你的另一个 div<div id="message"></div>
现在你的 ajax 看起来像
$.ajax({
url:'myAjax.php',
data:{datakey:datavalue},
dataType:"JSON",
success: function (response) {
if(response.message=="your message")
{
$('#message').html(response.content);
}
else
{
$('#page').html(response.content);
}
}
});
回答by Luca Filosofi
as T-Bull say... the whole process is wrong here....
正如 T-Bull 所说……这里的整个过程是错误的……
you simply are over-complicating things and you know that infact:
你只是把事情复杂化了,你知道事实上:
I understand that the server can return a link instead of a page, but in this case one additional stage will be needed on a client - redirect and then populating the new page on the server.
我知道服务器可以返回链接而不是页面,但在这种情况下,客户端需要一个额外的阶段 - 重定向然后在服务器上填充新页面。
stop complicating and start do it well...
停止复杂化并开始做好...
- Client open the page first time, so, track it
$_SESSION['tmp_client_id'] = 'client_'.session_id();
obviously is better if the client is already subscribed, anyway, put stuff in temp table OR into another session var etc... - Client fill in the form;
- Client submit the form;
- Make the AJAX request;
- Store
$_POST
variable insidetmp_client_tbl
with it's uniquetmp_client_id
OR just$_SESSION['client_'.session_id()] = json_encode($_POST);
- Outcome #1 ? display message in a
</div>
- Outcome #2 ? refresh page and check
if( isset($_SESSION['client_'.session_id()])) {
if so let's display the form again with filled fields:} else {
display empty form; SELECT * FROM tmp_client_tbl WHERE tmp_client_id = '{$_SESSION['tmp_client_id']}'
ORjson_decode($_SESSION['client_'.session_id()]);
$form_data = $mysql_rows;
OR$json_array;
foreach($form_data as $name => $value) { echo "<input name='$name' value='$value' />" }
in a ninja way that assume you have such kind of form builder array where$form = array('text' => array('name','lastname'), 'select' => array('countries'), ... )
, OR simply by<input name='lastname' value='{$lastname}' />
where the fields values are pre-polutated with empty vars;- time elapsed, error occurred, browser closed?
session_destroy();
orunset($_SESSION['client_'.session_id()]);
- 客户端第一次打开页面,所以,
$_SESSION['tmp_client_id'] = 'client_'.session_id();
如果客户端已经订阅,跟踪它显然更好,无论如何,将东西放在临时表或另一个会话变量中等等...... - 客户填写表格;
- 客户提交表格;
- 发出 AJAX 请求;
- 将
$_POST
变量存储在tmp_client_tbl
它的唯一tmp_client_id
或只是$_SESSION['client_'.session_id()] = json_encode($_POST);
- 结果#1?显示消息
</div>
- 结果#2?刷新页面并检查
if( isset($_SESSION['client_'.session_id()])) {
是否如此让我们再次显示带有填充字段的表单:} else {
显示空表单; SELECT * FROM tmp_client_tbl WHERE tmp_client_id = '{$_SESSION['tmp_client_id']}'
或者json_decode($_SESSION['client_'.session_id()]);
$form_data = $mysql_rows;
或者$json_array;
foreach($form_data as $name => $value) { echo "<input name='$name' value='$value' />" }
以一种忍者的方式,假设你有这样的表单构建器数组 where$form = array('text' => array('name','lastname'), 'select' => array('countries'), ... )
,或者简单地通过<input name='lastname' value='{$lastname}' />
字段值被空变量预先污染的地方;- 时间已过,发生错误,浏览器关闭?
session_destroy();
或者unset($_SESSION['client_'.session_id()]);