【问题标题】:Changing element visibility just before form submitting in Safari doesn't work sometimes在 Safari 中提交表单之前更改元素可见性有时不起作用
【发布时间】:2021-08-07 01:26:56
【问题描述】:

这是我用来在整个应用程序中显示加载微调器的 html 元素(处于其原始状态)(主要使用 Bootstrap 类):

<div id="loadSpinner" class="overlay d-flex justify-content-center invisible">
  ...
</div>

这是视图中的表单(Rails 6):

  <%= form_with(url: result_path, 
      method: "patch", local: true) do |f| %>

    ...

    <%= f.submit "Finish", class: "btn btn-success btn-lg my-3",
        onclick: "finish();" %>

  <% end %>

这是显示加载微调器的“finish()”js 函数:

function finish() {
  ...
  document.querySelector('#loadSpinner').classList.remove('invisible');
}

它在 Chrome 和 Firefox 中运行良好,但加载微调器有时不显示在 Safari 中。

我已经添加了一些日志(console.log(document.querySelector('#loadSpinner')) 在 'invisible' 类删除之后)并且可以看到 'invisible' 类在提交之前实际上被删除了。所以 js 代码工作正常,但微调器没有出现。

另外,我尝试在删除“不可见”类后添加一个“可见”类 - 问题仍然存在。

有人知道为什么会在 Safari 中发生吗?

我有一个假设,实际上提交是在实际删除“不可见”类之前以某种方式发生的,但我不知道检查和修复它的方法。

【问题讨论】:

    标签: javascript ruby-on-rails bootstrap-4 safari


    【解决方案1】:

    如果您使用的是 Rails UJS,您可以使用 ajax:beforeSendajax:complete 事件来切换微调器:

    <%= form_with(url: result_path, method: "patch", remote: true, class: 'spinner-form') do |f| %>
    
    let form = document.querySelector('#myForm');
    let spinner = document.querySelector('#loadSpinner');
    
    document.addEventListener('ajax:beforeSend', (event)=>{
      if (!event.target.matches('.spinner-form)) return;
      spinner.classList.remove('invisible');
    });
    
    document.addEventListener('ajax:complete', (event)=>{
      if (!event.target.matches('.spinner-form)) return;
      spinner.classList.add('invisible');
    });
    

    如果你自己做,你想阻止默认事件处理程序:

    <%= f.submit "Finish", class: "btn btn-success btn-lg my-3",
            id: "myButton" %>
    
    let btn = document.querySelector('#myButton');
    let spinner = document.querySelector('#loadSpinner');
    
    btn.addEventListener('click', (event)=>{
      let form = event.target.form;
      event.preventDefault();
      spinner.classList.add('invisible');
    
      fetch(form.action)
        .then((response)=>{
           spinner.classList.remove('invisible');
         });
    });
    

    如果这不是 XHR (ajax) 请求,那么当页面重新加载时脚本执行会停止,这将无法正常工作。

    【讨论】:

    • 这不是 ajax。我必须将其保留在“本地:真实”中。无论如何,这与 Safari 有什么关系?
    • 不是很多。我怀疑你所做的实际上在任何浏览器中都能可靠地工作,因为它在概念上被破坏了。
    • 为什么?我认为 onclick js-functions 必须在实际提交之前执行。而且我在其他浏览器中看不到这个问题。
    • 除非您的函数实际上是阻塞的,例如调用alert 或者您停止事件默认情况下表单仍将提交,这实际上只是一个时间问题。您可能还没有发现它在其他浏览器上已损坏...
    • 是的。使用真正的事件处理程序而不是 onclick。使用event.preventDefault() 阻止默认设置 - 做你的事,然后使用event.target.form.submit() 触发表单提交。
    【解决方案2】:

    由于某种原因,Safari 在提交表单之前需要稍许延迟。

    所以解决方法如下。

    1. 将表单中的提交按钮改为简单按钮:
    <%= form_with(url: result_path, 
        method: "patch", local: true) do |f| %>
    
    ...
        
    <%= button_tag "Finish", type: "button",
              class: "btn btn-success btn-lg my-3",
              onclick: "finish();" %>
    
    <% end %>
    
    1. 稍微延迟提交数据:
    function finish() {
      ...
      document.querySelector('#loadSpinner').classList.remove('invisible');
      
      // submit form
      setTimeout(function() {
        document.querySelector('form').submit();
      }, 300);  
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-07-06
      • 1970-01-01
      • 1970-01-01
      • 2017-08-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多