gpt4 book ai didi

javascript - 如何使用 Vue 禁用表单提交时的 window.onbeforeunload ?

转载 作者:行者123 更新时间:2023-12-03 02:10:36 28 4
gpt4 key购买 nike

我有一个名为 countdowntimer.vue 的组件,它显然只是一个倒计时器,我将它用于在线考试页面,我想申请 onbeforeunload窗口对象上的事件,但我也希望计时器在完成时自动提交,而不会被该窗口事件中断,我尝试将代码放入 vuejs 组件中,但它没有响应,它也不允许我提交而不中断,否则它根本不起作用,并且让任何事件在不中断的情况下离开页面。

这是倒计时器的代码:

<template>
<div>
<div v-if="finished" v-text="expiredText"></div>

<div v-else>
<span>{{ remaining.minutes }} Minutes, </span>
<span>{{ remaining.seconds }} Seconds</span>
left...
</div>
</div>
</template>

<script>
import moment from 'moment';
export default {
props: {
until: { default: 600000},
expiredText: { default: 'TIME IS UP' }
},
data () {
return { limiter: this.until * 10000};
},
created () {
this.refreshEverySecond();
document.addEventListener('beforeunload', this.redirect());
},
computed: {
finished () {
return this.remaining.total <= 0;
},
remaining () {
let remaining = moment.duration(this.limiter);
if (remaining <= 0) this.$emit('finished');
return {
total: remaining,
minutes: remaining.minutes(),
seconds: remaining.seconds()
};
},
},
methods: {
refreshEverySecond () {
let interval = setInterval(() => this.limiter = this.limiter - 1000, 1000);
this.$on('finished', () => clearInterval(interval));
this.$on('finished', () => this.timeUp());
},

timeUp() {
const form = document.querySelector('[data-form-submit]');
const radios = document.querySelectorAll('input[type=radio]');
radios.forEach(radio => radio.style.display = 'none');
form.submit(function(e) {
console.log(e);
});
},
redirect () {
// if(this.$on('finished')) {
// console.log(this.finished)
// window.onbeforeunload = function() {
// return "Do you really want to leave our brilliant application?";
// };
// }
// console.log(this.finished())
// return;
}
},
}
</script>

我尝试将该方法设置为计算属性并设置为具有不同 if 语句的观察程序,但它就像我上面提到的那样不起作用。

这是我正在使用的 Blade 模板

@extends('layouts.app')

@section('content')
<div class="container">
<div class="row">
<div class="col-md-6 col-md-offset-3">
<form method="POST" onsubmit="clicked()" data-form-submit>
{{ csrf_field() }}
<div class="panel panel-danger">
<div class="panel-heading">
{{ $quiz->quiz_name }}
</div>
<div class="panel-body">
<ol>
@foreach($quiz->questions as $index => $question)
<li><h4>{{ $question->title }} ? </h4></li>
<ul>
<div class="flex-align-baseline">
<li>{{$question->option_1}}</li>
<input type="radio" name="{{$index}}" value="{{ $question->option_1 }}">
<hr>
</div>
<div class="flex-align-baseline">
<li>{{$question->option_2}}</li>
<input type="radio" name="{{$index}}" value="{{ $question->option_2 }}">
<hr>
</div>
<div class="flex-align-baseline">
<li>{{$question->option_3}}</li>
<input type="radio" name="{{$index}}" value="{{ $question->option_3 }}">
<hr>
</div>
<div class="flex-align-baseline">
<li>{{$question->option_4}}</li>
<input type="radio" name="{{$index}}" value="{{ $question->option_4 }}">
<hr>
</div>
</ul>
<hr>
@endforeach
</ol>
<input type="submit" class="btn btn-success" onclick="clicked()" value="Submit">
</div>
</div>
</form>
</div>
<timer :until="{{ count($quiz->questions) }}" class="countdown col-md-3"></timer>
</div>
</div>

@endsection

<script>

let submitForm = false;
function clicked() {
submitForm = true;
}
window.onbeforeunload = function(e) {
if (submitForm) {
return null;
}
return "Do you really want to leave our brilliant application?";
};
</script>

如您所见,我在 @endsection 之外有一个脚本标记。 ,我开始明白的是,你可能不能这样做,它不会连接到 Blade 模板本身的任何元素,我试图像在 vue 组件中那样获取表单对象,但它返回 null 或我不记得了,你不能将事件监听器附加到未定义,但如果我在浏览器的控制台中运行相同的逻辑,它会按预期工作,onsubmit=""由于某种原因,我在表单上发生的事件没有到达底部的那些脚本标记, submitForm 的值变量不会改变,但奇怪的是,如果我手动单击提交按钮,它确实会触发函数 clicked() ,所以我在这里很困惑,我不知道我是否可以仅使用 vue 来实现这一点,如果不能,我不知道为什么 onsubmit=""事件不起作用,当然我无法移动 @section 内的脚本标签因为 vue 会发出嘎嘎声,如果你知道我应该用这段代码做什么,我将不胜感激。

最佳答案

首先,您应该将方法引用传递给 beforeunload,而不是调用该方法的结果。因此,删除 ():

created () {
this.refreshEverySecond();
document.addEventListener('beforeunload', this.redirect); // not this.redirect()
},

现在,启用/禁用处理程序的一个简单解决方案是添加一个标志:

    data () {
return {
limiter: this.until * 10000
preventSubmit: true
};
},

并且,在您的方法中,更新/使用该标志:

    methods: {
// ...
timeUp() {
this.preventSubmit = false; // ALLOW redirect now

const form = document.querySelector('[data-form-submit]');
const radios = document.querySelectorAll('input[type=radio]');
radios.forEach(radio => radio.style.display = 'none');
form.submit(function(e) {
console.log(e);
});
},
redirect () {
if (this.preventSubmit) {
// do your thing to prevent submit
}
}
},

替代方案

或者,您可以删除监听器:

created () {
this.refreshEverySecond();
document.addEventListener('beforeunload', this.redirect); // not this.redirect()
},

还有:

methods: {
// ...
timeUp() {
document.removeEventListener('beforeunload', this.redirect);
// ...

但我认为标志替代方案更安全。


正确处理unbeforeunload

根据评论,我添加了一个有关其工作原理的演示。

参见JSFiddle DEMO here或下面的演示。

new Vue({
el: '#app',
data: {
preventSubmit : true
},
mounted () {
window.addEventListener("beforeunload", this.redirect);
},
methods: {
redirect(event) {
if (this.preventSubmit) {
var confirmationMessage = "\o/";
event.returnValue = confirmationMessage; // Gecko, Trident, Chrome 34+
return confirmationMessage; // Gecko, WebKit, Chrome <34
}
}
}
})
<script src="https://unpkg.com/vue"></script>

<div id="app">
<p>preventSubmit ? {{ preventSubmit }}</p>
<button @click="preventSubmit = !preventSubmit ">Toggle preventSubmit </button>
</div>
<br>
<a href="/somewhere-else">click to try to navigate away</a>

关于javascript - 如何使用 Vue 禁用表单提交时的 window.onbeforeunload ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49589672/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com