在 Safari 中提交表单之前更改元素可见性有时不起作用
Posted
技术标签:
【中文标题】在 Safari 中提交表单之前更改元素可见性有时不起作用【英文标题】:Changing element visibility just before form submitting in Safari doesn't work sometimes 【发布时间】: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 中发生吗?
我有一个假设,实际上提交是在实际删除“不可见”类之前以某种方式发生的,但我不知道检查和修复它的方法。
【问题讨论】:
【参考方案1】:如果您使用的是 Rails UJS,您可以使用 ajax:beforeSend
和 ajax: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 在提交表单之前需要稍许延迟。
所以解决方法如下。
-
将表单中的提交按钮改为简单按钮:
<%= 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 %>
-
稍微延迟提交数据:
function finish()
...
document.querySelector('#loadSpinner').classList.remove('invisible');
// submit form
setTimeout(function()
document.querySelector('form').submit();
, 300);
【讨论】:
以上是关于在 Safari 中提交表单之前更改元素可见性有时不起作用的主要内容,如果未能解决你的问题,请参考以下文章
Vuejs - 如何在单个表单中仅提交可见元素(使用 Vuelidate)