我有一个名为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语句的观察者,但它只是不像我上面提到的那样工作。
这是我在
中使用的刀片模板@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
之外有一个脚本标记,我所了解的是您可能无法做到这一点,它无法连接到任何元素。刀片模板本身,我试图抓住表单对象,就像我在vue组件中做的那样,但它返回null或undefined我无法记住,并且你不能将事件监听器附加到undefined,但如果我在浏览器的控制台中按预期运行相同的逻辑,我在表单上的onsubmit=""
事件由于某种原因没有到达底部的脚本标记,submitForm
的值{1}}变量没有变化,但奇怪的是,如果我手动点击提交按钮它会触发函数clicked()
,所以我在这里很困惑,我不知道我是否可以只用vue实现这一点,如果不是,我不知道为什么onsubmit=""
事件不起作用,当然我不能在@section
内移动脚本标签因为vue会嘎嘎叫,如果你知道我应该怎么做我要感激一点代码。
答案 0 :(得分:1)
首先,您应该将方法引用传递给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);
// ...
但我认为标志替代方案更安全。
根据评论,我正在添加一个如何工作的演示。
请参阅下面的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>