在 Safari 中提交表单之前更改元素可见性有时不起作用
Changing element visibility just before form submitting in Safari doesn't work sometimes
这是 html 元素(处于原始状态),我用来在整个应用程序中显示加载微调器(主要使用 Bootstrap classes):
<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' class 删除之后)并且可以看到 'invisible' class 实际上在之前被删除了提交。所以 js 代码工作正常,但微调器没有显示。
此外,我尝试在删除 'invisible' 后添加 'visible' class - 问题仍然存在。
有人知道为什么在 Safari 中会发生这种情况吗?
我有一个假设,实际上提交发生在 'invisible' class 实际被删除之前,但我不知道如何检查和修复它。
如果您使用 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) 请求,那么这将无法工作,因为在重新加载页面时脚本执行会停止。
出于某种原因,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);
}
这是 html 元素(处于原始状态),我用来在整个应用程序中显示加载微调器(主要使用 Bootstrap classes):
<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' class 删除之后)并且可以看到 'invisible' class 实际上在之前被删除了提交。所以 js 代码工作正常,但微调器没有显示。
此外,我尝试在删除 'invisible' 后添加 'visible' class - 问题仍然存在。
有人知道为什么在 Safari 中会发生这种情况吗?
我有一个假设,实际上提交发生在 'invisible' class 实际被删除之前,但我不知道如何检查和修复它。
如果您使用 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) 请求,那么这将无法工作,因为在重新加载页面时脚本执行会停止。
出于某种原因,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);
}