【问题标题】:Control whether a link is clickable or not控制链接是否可点击
【发布时间】:2022-01-07 12:50:56
【问题描述】:

我想控制一个链接是可点击还是显示错误(基于 ajax 调用的结果)。

<a class="lnkCustomer" href="http://localhost/viewcustomer" target="_blank" data-customerno="237">View</a>

我可以将链接设置为“允许点击”:

// Authorized
anchor.data("authorized", true);

但是,当我运行此代码时,链接仍然无法打开。理想情况下,一旦 ajax 调用完成,它应该调用 click 事件。我认为问题出在这一行。

// Trigger Anchor
anchor.click();

这是完整的代码:

<script type="text/javascript">

    $(".lnkCustomer").click(function(e)
    {

        var customerNo = $(this).data('customerno');
        var anchor = $(this);

        // Check for authorized
        if (anchor.data("authorized"))
        {
            return true;
        }

        $.ajax(
        {
            url: 'http://localhost/checkcustomer',
            type: 'POST',
            dataType: 'json',
            data: { customerNo: customerNo },
            cache: false,
            success: function (result)
            {
                if (result.success)
                {
                    // Authorize
                    anchor.data("authorized", true);
                    // Trigger Anchor
                    anchor.click();
                }
                else
                {
                    // Show a message in a alert or div
                    alert('Not authorized');
                }
             }
        });

        // Default to false (Do not process anchor)
        return false;

    });

</script>

注意:我在锚点中使用 class 而不是 id,因为我有各种链接会触发此事件。但是,正如您所看到的,这应该不是问题,因为我总是指的是单个对象:

var anchor = $(this);

【问题讨论】:

  • 您是在使用此检查来增强用户体验,还是打算将其用作防止未经授权访问的安全机制?如果是后者,那么这需要由您的服务器而不是您的客户端代码来处理。使用当前的解决方案,用户可以右键单击链接并在新选项卡中打开它,或者直接导航到您的 URL,绕过任何这些检查。

标签: javascript html jquery ajax


【解决方案1】:

如果没有启用弹出窗口或用户点击该事件,您将无法打开新标签。 你不能用 Promise 来延迟它或调用一个可信的点击事件。

如果您想验证用户是否可以点击您的链接,请在页面加载时执行 API 请求并存储结果。

或者将您的链接变成一个按钮,通过两次点击过程进行检查然后打开。

【讨论】:

    【解决方案2】:

    有一个简单的答案:如果点击不是来自受信任的事件(更改、点击、dblclick、mouseup、重置、提交),则不能触发点击。

    在这里,您尝试在 AJAX(异步)请求后触发点击,这是不允许的。

    更多信息here

    按照建议,您可以将其替换为 window.open(href, '_blank');,但请注意它也可能被浏览器参数阻止。

    【讨论】:

      【解决方案3】:

      不幸的是,正如其他人提到的,href 不能延迟。我确实找到了适合特定情况的解决方法。当用户单击 href 时,我创建了一个中间页面。这个页面然后执行 ajax 请求(服务器端),如果它被验证,它会继续并显示资源。否则它会显示错误并停留在中间页面上。

      【讨论】:

        【解决方案4】:

        任何时候你想覆盖浏览器的默认操作,你需要在事件监听器的顶部调用.preventDefault()

        之后,由于每次单击链接时您都在服务器端验证链接,因此实际上没有理由将其存储为状态客户端。您可以直接调用 window.open(),而不是尝试重新单击链接,这是 achors 默认执行的操作。

        $('.lnkCustomer').on('click', function(e) {
          e.preventDefault(); //makes anchor click do nothing
          let href = this.href;
          
        //pretend this is the call back from your ajax call
        //$.ajax(
        //  success: function(result) {
          if (result.success) {
            window.open(href, '_blank'); //what an anchor click does when not prevented
          } else {
            alert('Not authorized');
          }
        });
        

        【讨论】:

        • 您好,PoorlyWrittenCode,感谢您提供解决方案。不幸的是,使用 window.open 导致浏览器“阻止”请求而不打开链接。
        【解决方案5】:

        尝试像这样触发点击:anchor[0].click(); 看看是否有效。

        为了可读性,您可以保存对锚点的 DOM 元素的引用,而不仅仅是 jQuery 对象:

        var anchor = $(this);
        var anchorEl = $(this)[0];
        

        并使用 DOM 元素触发点击:

        anchorEl.click();
        

        【讨论】:

        • 你知道$(this)[0] === this,对吧?
        【解决方案6】:

        我认为我们不能覆盖锚标记的默认行为,但我们可以解决它。在此解决方案中,我已将 href 替换为 data-link。并用window.open模拟锚机制。

        代码:

        <a class="lnkCustomer" data-link="http://localhost/viewcustomer1" data-customerno="111" data-auth>View</a>
        <a class="lnkCustomer" data-link="http://localhost/viewcustomer2" data-customerno="237" data-auth>View</a>
        <a class="lnkCustomer" data-link="http://localhost/viewcustomer3" data-customerno="237" data-auth>View</a>
            <script type="text/javascript">
                $(".lnkCustomer").click(function (e) {
                    var customerNo = $(this).data('customerno');
                    var linkToGo = $(this).data('link');
                    var anchor = $(this);
                    // Check for authorized
                    if (anchor.data("authorized")) {
                        var win = window.open(linkToGo, '_blank');
                    }else{
                        $.ajax(
                        {
                            url: './checkcustomer.php',
                            type: 'POST',
                            data: { customerNo: customerNo },
                            cache: false,
                            success: function (result) {
                                if (result == 'authorized') {
                                    anchor.data("authorized", true);
                                    //new code
                                    anchor.attr("href", linkToGo);
                                    anchor.click();
                                    // Dont us this due to popup blocker
                                    //var win = window.open(linkToGo, '_blank');
                                }
                                else {
                                    // Show a message in a alert or div
                                    alert('Not authorized');
                                }
                            }
                        });
        
                    }
                });
            </script>
        

        请注意:

        1. 新的安全注意事项:如您所见,我们正在使用一个非常明显的数据链接,任何人只要付出足够的努力就可以访问该链接,无论它是否被授权。如果上面的答案让您通过弹出窗口阻止程序,接下来您可以做的几件事可能只是从一开始就获取可访问的链接 或者添加一个“显示链接”按钮,然后只获取用户可访问的链接。你可以通过ajax来实现。而且你也不需要这个 JS/Jquery 代码。 或者为数据链接分配一个随机数,然后在您的 PHP 代码中获取,看看它是否被授权,然后只返回可访问的 HTTP 链接。有很多改进方法。
        2. 可以使用 CSS 来设置锚标签的样式,我的解决方案中没有
        3. 我尝试的一种方法是使用preventDeault,但它不起作用

        【讨论】:

        • 您好 Akash,感谢您的回复。我忘了补充说我确实尝试过 window.open。我不能使用 window.open 因为操作被浏览器的弹出窗口阻止程序阻止。锚点(href)不会被弹出窗口阻止程序阻止。这就是为什么我必须使用锚(href)标签。
        • 您好,我明白了...您可以尝试编辑的代码并让我知道它是否有效(绕过弹出窗口阻止程序)
        • 嗨 Akash,它仍然会阻止第一个 window.open。再次感谢您,我很感激。
        • 哈哈,我觉得他们的弹出窗口拦截器做得很好:),你用的是哪一个?也让我知道你为什么不首先获取授权链接
        【解决方案7】:

        AFAICT,您已经完成了 90%,只是缺少一些关键细节。

        Working JSFiddle.

        1. e.preventDefault():正如其他答案/cmets中已经提到的,您需要阻止事件触发的默认操作,否则浏览器将在您的JS仍在运行时开始导航到链接的过程。

        2. anchor.click() 将触发点击您的链接,这将...重新开始整个过程​​!你会陷入递归循环。单击完成,您现在要导航。 To open a new window in Javascript,使用window.open(href, '_blank');

        3. 如果您的链接已经获得授权,您需要执行与 AJAX 首次授权相同的操作。而不是return true;,您需要再次执行相同的window.open()

        还有一个建议 - the convention for using GET or POST 是:

        • 更改数据时使用 POST,例如创建用户,或进行购买,登录 - 如果您点击重新加载,则不应发生 2 次;
        • 查看数据时使用GET,无状态变化,重载无害;

        AFAICT,您只是在查询一些客户详细信息,所以这应该是一个 GET 请求。

        我已经修改了您的代码以使用 JSONPlaceholder - 一个为这种情况提供 JSON 数据的虚拟 REST API(我们需要测试具有有效响应的 AJAX 调用),因此我们可以模拟您的 AJAX称呼。它只接受 GET 请求,因此我将您的 POST 更改为 GET,并根据它发回的虚拟数据更新了响应测试。您可以看到我们正在为User ID 1User ID 2 处理的输出。

        由于您需要在多个地方执行“转到链接”代码块,因此我将其提取到一个您可以调用的函数中,因此我们不需要在多个地方重复该代码。

        我还添加了一些额外的警报,以便您确定发生了什么。

        See it all in action on JSFiddle.

        Javascript:

        // A function to actually open the new page, since we need to do this in
        // more than one place.
        function goToLink(anchor) {
            let href=anchor.attr('href');
            window.open(href, '_blank');
        }
        
        $(".lnkCustomer").click(function(e) {
        
          // Prevent the default action this event would normally trigger from 
          // happening - in this case, navigating to the target href.
          e.preventDefault();
        
          var customerNo = $(this).data('customerno');
          var anchor = $(this);
        
          // Check for authorized, and open the link if so
          if (anchor.data("authorized")) {
            alert("Already authorized, let's go!");
            goToLink(anchor);
          }
          
          // https://jsonplaceholder.typicode.com/ is a dummy REST JSON generator.
          // Let's use it to simulate your AJAX call.  User ID 1's username is Bret,
          // user ID 2's username is Antonette.  Let's use customerNo in the URL to
          // retrieve user ID 1 or 2, and simply allow the click if the username is
          // Antonette.
          
          // First build the URL:
          let url = 'https://jsonplaceholder.typicode.com/users/' + customerNo
        
          $.ajax({
            url: url,
            type: 'GET',
            dataType: 'json',
            data: {
              customerNo: customerNo
            },
            cache: false,
            success: function(result) {
              if (result.username === 'Antonette') {
                // Authorize and go
                alert("Authorization success, let's go!");
                anchor.data("authorized", true);
                goToLink(anchor);
              } else {
                // Show a message in a alert or div
                alert('Not authorized');
              }
            }
          });
        
          // Default to false (Do not process anchor)
          return false;
        });
        

        HTML:

        <ul>
          <li><a class="lnkCustomer" href="https://google.com/" target="_blank" data-customerno="1">Google (no go)</a></li>
        
          <li><a class="lnkCustomer" href="https://stackoverflow.com/" target="_blank" data-customerno="2">Stackoverflow (allowed)</a></li>
        </ul>
        

        【讨论】:

        • 您好,不要惊慌,感谢您提供解决方案。不幸的是,使用 window.open 导致浏览器“阻止”请求而不打开链接。
        猜你喜欢
        • 1970-01-01
        • 2020-09-07
        • 1970-01-01
        • 1970-01-01
        • 2015-05-26
        • 1970-01-01
        • 2022-11-09
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多