我的网站上有一个简单的注册表单,用户可以在其中输入他们的电子邮件和姓名。
为了避免出现双重注册错误,我进行了一个简单的Ajax调用,查看电子邮件是否已经存在。如果是,我什么都不做,如果不是,我提交表格。
我的问题是表单的目标是_blank
,所以延迟提交调用会触发浏览器上的弹出窗口阻止程序。
现在,我知道了为什么会发生这种情况-我不再是可信点击事件中的一员。我将Ajax调用更改为同步调用,但收到一条警告,主线程上的同步Ajax调用已被弃用。
所以我目前的选择似乎是:
- 无论如何都要使用syncAjax调用,但最终它将停止工作
- 删除我表单上的目标
_blank
,使其在同一页面上重定向(糟糕的用户体验)
有没有更好的方法可以绕过弹出窗口阻止程序,将我延迟的表单提交为弹出窗口?
代码:
HTML:
<form action="//external-site.com" method="post" target="_blank" onsubmit="onSubmitSignupForm(event)">
...
</form>
JS:
function onSubmitSignupForm( e )
{
e.preventDefault();
var request = new XMLHttpRequest();
request.open( 'POST', 'checkEmail.php', true );
request.setRequestHeader( 'Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8' );
request.onload = onLoad;
request.onerror = onError;
// NOTE: params = urlencoded params recovered from form
request.send( params );
}
function onLoad( e )
{
var request = e.target;
if( request.status == 200 )
{
var data = JSON.parse( request.responseText );
if( data != null && data.success )
{
onFinish( request, data );
return;
}
}
// if we get here, then it means that the request failed, or there was a problem
onError( e );
}
function onError( e )
{
var request = e.target;
var data = JSON.parse( request.responseText );
onFinish( request, data );
}
function onFinish( request, data )
{
var success = ( data != null ) ? data.success : false;
if( !success )
$form.submit(); // blocked by popup
}
好吧,所以我有一个解决方案,尽管它可能有点特定于我的情况,而且如果用户已经注册,我会重定向用户,这对我有所帮助。
当表单最初提交时,我基本上会打开一个新的中间页面(这样就可以绕过弹出问题,因为它是在一个受信任的事件中),并在该页面上填充一个隐藏的表单(如果用户愿意,可以使用手动提交的链接)。ajax调用被发送,根据结果,我要么在第2页提交表单,要么在他们已经注册的情况下重定向。
- 用户在第1页提交表单
- 停止事件,然后打开Page2,它具有相同的形式,尽管是隐藏的
- 使用第1页表单中的值填充第2页表单
- 在Page2上显示一条消息,说明我们正在处理它,并附上一个手动提交隐藏表单的链接(良好的用户体验)
- 在Page1上,激发Ajax请求以查看用户是否已经订阅
- 当Ajax结果出来时,可能会发生两件事
- (a) 用户未注册-第2页上的表单已提交(可以选择将第1页重定向到内容)
- (b) 用户已注册-将Page2重定向到内容
唯一需要注意的是,在填写表单和Ajax结果返回之前,确保Page2已完全加载。为此,我使用了一个带有onload
事件的简单布尔系统。
它的代码看起来像这样:
function onSubmitSignupForm( e )
{
e.preventDefault();
var $form = e.target;
var name = ...; // get name value from form
var email = ...; // get email value from form
// open a new window that we'll be able to control and redirect in (otherwise, we'll
// get stung with a trying to open a popup, as when we get the result, we'll no longer
// be in the trusted click event)
var win = window.open( '/signup/', '_blank' );
win.onload = function() {
win.setDetails( name, email ); // fill in the hidden form
}
// check if the email is already signed up
// NOTE: result might be null if we couldn't reach the server
checkEmail( name, email, function onFinish( result ){
// set the result in the other window
// NOTE: the window might not have loaded yet
if( typeof win.setResult == 'undefined' )
{
var f = win.onload; // replace the one we already have
win.onload = function(){
if( f )
f();
win.setResult( result );
}
}
else
win.setResult( result );
});
}
setDetails
和setResult
都将尝试调用第三个函数handleResult
,该函数将仅继续由两个函数设置的布尔值为true。