猿问

有关于新页面弹窗的问题

1、需求

        网站内有一个table做的客户列表,其中一列有个“查看详情”的按钮,点击后会向服务器发起一个请求(参数为该行客户的id信息),然后根据返回值判断是否打开一个新页面(返回true则打开新页;返回为false则toast提示“无法查看!”)。

        这个需求其实蛮常见,实现似乎也很简单,但还是遇到一些值得一提的情况。

2、方案

1)方案一:window.open

queryUserViewAuth(params).then((res) => {
    If (res.data.isSuccess) {
        Window.open('/newPage')
    } else {...}
})

        但是当点击按钮触发弹窗时,被浏览器拦截了,项目负责人认为这个体验是不好的,所以需要考虑如何解决这个问题。

        在此之前,先提一下浏览器拦截弹窗的原因,网上搜了下,说是因为“ajax回调中的上下文已不是用户行为了,从安全角度出发,浏览器进行了拦截”,这意味着“在函数内部新建a标签再去触发a标签的click事件”也是不可行的。

2)方案二:控制a标签的href跳转

        于是有提议说是否可以“直接使用a标签替代table中的按钮,然后当用户点击时根据ajax的返回结果去‘阻止/放行’a标签的href行为”。这个想法听起来不太能做到,实际也确实没成功,不过测试中有点儿小发现,虽然目测没什么实用价值,但还是忍不住提一嘴:

        ① 首先,如果要阻止a标签的href跳转,常见的伎俩如下;

<a href="newPage.html" onclick="return false;">测试</a>

        ② 但这显然不满足此次的需求,得让返回值是可控的,所以尝试变形;

<a href="newPage.html" onmousedown="this.x=fn();" onclick="return this.x;">测试</a>
<script>
    function fn() {return false}
</script>

        ③ 上述②的变形是可以的,但那代码都是同步的,所以→再变;

<a href="newPage.html" onmousedown="this.x=fn();" onclick="return this.x;">测试</a>
<script>
    function fn() {
        setTimeout(function(){return false},0)
    }
</script>

       OK,到这里KO了,见证奇迹的时刻并未降临。

3)方案三:

        苦思无望,只好再到搜索引擎上找找思路,(其实就是解释弹窗为什么被拦截的那帖子),提到了一个思路“在click事件中先打开一个空白的新窗口,然后再进行ajax请求,请求后再去更改新窗口的url”。这方法不错,但可惜并不适用于此次的项目需求,毕竟如果请求发现res.data.isSuccess为false(即不应该打开新页面),“这时再用close去关”并不是一个好的用户体验,何况如果请求返回过慢,那个新窗口会以空白之身杵在那里很久,也不好。

4)结束

        后来,项目负责人提出暂通过后端来解决,方案如下:前端直接用a标签做按钮,在href上拼接上get请求的地址(即上述的ajax请求),当用户点击时触发请求,然后再由后端做302重定向。

3、求助

        各位如果有什么好对策,希望能点拨一下。


xue5hen
浏览 1061回答 1
1回答

慕勒0069038

很抱歉这几天都没有回复, 赶项目= = ,今天抽空看了一眼,给你写了一个 你试试<!DOCTYPE html> <html lang="en"> <head>   <meta charset="UTF-8">   <title>Title</title>   <script src="jquery/js/jquery.min.js"></script>   <script>      $(document).ready(function (e) {         $('span').bind('click',function(e,canjump){            console.log(1);           if(!canjump){              e.preventDefault();              $('span').trigger("myclick");              }         });         $('span').bind('myclick',function(e){            async function a() {               try{                  return await new Promise((resolve, reject) => {                     setTimeout(function () {                        resolve(true);                     }, 1000);                  });               }catch (e){                  return await Promise.reject(false);               }            }            a().then(function (canjump) {               console.log(13);               $('span').trigger("click",[true]);            }).catch(function (err) {               console.log(err);            })         });      });   </script> </head> <body>   <a href="test1.html" ><span>测试</span></a> </body> </html>

慕勒0069038

方案2  的 可以参考下 es6(es7) 的 async、await  方案2 你的不成功的原因是 应该是fn() 内部的setTimeout 相当于异步方法, 调用fn的时候 没有return false 出来,其实有个方法, 就是 成功后弹个确认框(layer就行) ,里面说 即将前往新的页面 ,给一个确定和取消, 确定就window.open(), 这样不就不会被拦截了么
随时随地看视频慕课网APP
我要回答