Javascript 如何在计时器倒计时为0时触发事件
我有一个父组件,其中包含计时器组件。计时器从15分钟开始,倒计时到0。当我的计时器显示时间为0时,我想触发提交按钮事件,提交按钮位于测验组件内(测验组件也是父组件的子组件)。我发现当p标记改变时,我可能可以使用MutationObserver。我不确定这是正确的、唯一的方法还是有更好的方法来实现这一点 父组件:Javascript 如何在计时器倒计时为0时触发事件,javascript,reactjs,timer,Javascript,Reactjs,Timer,我有一个父组件,其中包含计时器组件。计时器从15分钟开始,倒计时到0。当我的计时器显示时间为0时,我想触发提交按钮事件,提交按钮位于测验组件内(测验组件也是父组件的子组件)。我发现当p标记改变时,我可能可以使用MutationObserver。我不确定这是正确的、唯一的方法还是有更好的方法来实现这一点 父组件: import React, { Component } from 'react'; import '../css/App.css' import Quiz from './Quiz';
import React, { Component } from 'react';
import '../css/App.css'
import Quiz from './Quiz';
import Timer from './Timer';
import { connect } from 'react-redux';
import { ActionTypes } from '../redux/constants/actionTypes';
import { saveQuizAll, getQuizIndex } from '../commonjs/common.js';
const mapStateToProps = state => { return { ...state.quiz, ...state.quizAll } };
const mapDispatchToProps = dispatch => ({
onQuizLoad: payload => dispatch({ type: ActionTypes.QuizLoad, payload }),
onQuizChange: payload => dispatch({ type: ActionTypes.QuizAnswerAll, payload }),
onPagerUpdate: payload => dispatch({ type: ActionTypes.PagerUpdate, payload })
});
class QuizContainer extends Component {
state = {
quizes: [
{ id: 'data/class1.json', name: 'Class 1' },
{ id: 'data/class2.json', name: 'Class 2' },
{ id: 'data/class3.json', name: 'Class 3' },
{ id: 'data/class4.json', name: 'Class 4' },
],
quizId: 'data/class1.json'
};
pager = {
index: 0,
size: 1,
count: 1
}
componentDidMount() {
console.log('componentDidMount');
this.load(this.state.quizId);
}
load(quizId, isValReload) {
console.log('In load');
let url = quizId || this.props.quizId;
if (isValReload) {
let quiz = this.props.quizAll.find(a => url.indexOf(`${a.id}.`) !== -1);
console.log('In load quiz : ', quiz);
this.pager.count = quiz.questions.length / this.pager.size;
this.props.onQuizLoad(quiz);
this.props.onPagerUpdate(this.pager);
}
else {
fetch(`../${url}`).then(res => res.json()).then(res => {
let quiz = res;
quiz.questions.forEach(q => {
q.options.forEach(o => o.selected = false);
});
quiz.config = Object.assign(this.props.quiz.config || {}, quiz.config);
this.pager.count = quiz.questions.length / this.pager.size;
this.props.onQuizLoad(quiz);
this.props.onPagerUpdate(this.pager);
});
}
}
//This event implements restriction to change class without finishing curretnly selectd class
onClassClick = (e) => {
let qus = this.props.quiz.questions;
// console.log(qus);
let isNotAllAns = qus.some((q, i) => {
var isNot = false;
if (q.answerType.id !== 3 && q.answerType.id !== 4) {
isNot = (q.options.find((o) => o.selected === true)) === undefined;
}
else {
// console.log('q', q);
isNot = ((q.answers === "" || q.answers.length === 0));
}
return isNot;
});
if (isNotAllAns) {
alert('Please complete the quiz.');
e.stopPropagation();
}
}
/*
saveQuizAll(_quizAll, _quiz) {
let allQuiz = [];
// , _quizAll, _quiz;
// if (true) {
// _quiz = this.quiz;
// _quizAll = this.quizAll;
// }
console.log(this, _quiz, _quizAll);
if (_quiz.questions.length !== 0) {
if (_quizAll.length !== undefined) {
console.log('Not Initial Setup Splice', _quiz.id);
allQuiz = _quizAll;
const qIndex = this.getQuizIndex(_quiz.id.toString());
if (qIndex > -1) {
allQuiz.splice(qIndex, 1, _quiz);
}
else {
allQuiz.splice(_quizAll.length, 0, _quiz);
// allQuiz.splice(this.props.quizAll.length-1, 0, this.props.quizAll, this.props.quiz);
}
}
else {
allQuiz[0] = _quiz;
}
return allQuiz;
// if (true) {
// this.onQuizChange(allQuiz);
// }
}
}
*/
onChange = (e) => {
// console.log(this.props.quizAll, this.props.quizAll.length);
let allQuiz = [];
allQuiz = saveQuizAll(this.props.quizAll, this.props.quiz);
//below code converted into saveQuizAll funstion
/*
if (this.props.quizAll.length !== undefined) {
console.log('Not Initial Setup Splice', this.props.quiz.id);
allQuiz = this.props.quizAll;
const qIndex = this.getQuizIndex(this.props.quiz.id.toString());
if (qIndex > -1) {
allQuiz.splice(qIndex, 1, this.props.quiz);
}
else {
allQuiz.splice(this.props.quizAll.length, 0, this.props.quiz);
// allQuiz.splice(this.props.quizAll.length-1, 0, this.props.quizAll, this.props.quiz);
}
}
else {
allQuiz[0] = this.props.quiz;
}
*/
// console.log('allQuiz Out - ', allQuiz);
this.props.onQuizChange(allQuiz);
console.log('Check QuizAll - ', this.props.quizAll);
const aQuiz = JSON.parse(JSON.stringify(this.props.quizAll));
this.setState({ quizId: e.target.value });
if (aQuiz.length !== undefined && getQuizIndex(this.props.quizAll, e.target.value) > -1) {
// console.log(aQuiz.findIndex(a => e.target.value.indexOf(`${a.id}.`) !== -1));
this.load(e.target.value, true);
}
else {
this.setState({ quizId: e.target.value });
this.load(e.target.value, false);
}
}
// getQuizIndex(qID) {
// return this.props.quizAll.findIndex(a => (qID.indexOf(`${a.id}.`) !== -1 || qID.indexOf(`${a.id}`) !== -1));
// }
render() {
return (
<div className="container">
<header className="p-2">
<div className="row">
<div className="col-6">
<h3>DADt Application</h3>
</div>
<div className="col-6 text-right">
<label className="mr-1">Select Quiz:</label>
<select onChange={this.onChange} onClick={this.onClassClick}>
{this.state.quizes.map(q => <option key={q.id} value={q.id}>{q.name}</option>)}
</select>
</div>
</div>
</header>
<Timer duration={900}/>
<Quiz quiz={this.state.quiz} quizId={this.state.quizId} saveAll={saveQuizAll} mode={this.state.mode} />
</div>
);
}
}
export default connect(mapStateToProps, mapDispatchToProps)(QuizContainer);
import React, { Component } from 'react';
import { ActionTypes } from '../redux/constants/actionTypes';
import Review from './Review';
import Questions from './Questions';
import Result from './Result';
import { connect } from 'react-redux';
// import { saveQuizAll } from '../commonjs/common.js';
const mapStateToProps = state => { return { ...state.quiz, ...state.mode, ...state.pager, ...state.quizAll } };
const mapDispatchToProps = dispatch => ({
onSubmit: payload => dispatch({ type: ActionTypes.QuizSubmit, payload }),
onQuizChange: payload => dispatch({ type: ActionTypes.QuizAnswerAll, payload }),
onPagerUpdate: payload => dispatch({ type: ActionTypes.PagerUpdate, payload })
});
class Quiz extends Component {
move = (e) => {
let id = e.target.id;
let index = 0;
if (id === 'first')
index = 0;
else if (id === 'prev')
index = this.props.pager.index - 1;
else if (id === 'next') {
index = this.props.pager.index + 1;
}
else if (id === 'last')
index = this.props.pager.count - 1;
else
index = parseInt(e.target.id, 10);
if (index >= 0 && index < this.props.pager.count) {
let pager = {
index: index,
size: 1,
count: this.props.pager.count
};
this.props.onPagerUpdate(pager);
}
}
saveStore(e) {
let allQuiz = [];
console.log(this, e);
allQuiz = this.props.saveAll(e.props.quizAll, e.props.quiz);
console.log(allQuiz);
this.props.onQuizChange(allQuiz);
}
setMode = (e) => this.props.onSubmit(e.target.id);
// setMode(e) {
// console.log('in mode',e);this.props.onSubmit(e.target.id);
// }
renderMode() {
console.log('Inside here', this.props.mode);
if (this.props.mode === 'quiz') {
return (<Questions move={this.move} />)
} else if (this.props.mode === 'review') {
return (<Review quiz={this.props.quiz} move={this.move} />)
} else {
console.log('Before Results');
const divSel = document.querySelector('div.col-6.text-right');
// console.log('divSel', divSel);
if (divSel) {
divSel.style.display = "none";
}
return (<Result questions={this.props.quizAll || []} />)
}
}
render() {
return (
<div>
{this.renderMode()}
{(this.props.mode !== 'submit') &&
<div>
<hr />
<button id="quiz" className="btn btn-primary" onClick={this.setMode}>Quiz</button>
<button id="review" className="btn btn-primary" onClick={this.setMode}>Review</button>
<button id="submit" className="btn btn-primary" onClick={(e) => {this.setMode(e); this.saveStore(this)}}>Submit Quiz</button >
</div >}
</div>
)
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Quiz);
import React,{Component}来自'React';
导入“../css/App.css”
从“./quick”导入测验;
从“./Timer”导入计时器;
从'react redux'导入{connect};
从“../redux/constants/ActionTypes”导入{ActionTypes};
从“../commonjs/common.js”导入{saveQuizAll,getQuizIndex};
const mapStateToProps=state=>{return{…state.quick,…state.quizAll};
const mapDispatchToProps=调度=>({
onQuizLoad:payload=>dispatch({type:ActionTypes.QuizLoad,payload}),
onQuizChange:payload=>dispatch({type:ActionTypes.quizanswrall,payload}),
onPagerUpdate:payload=>dispatch({type:ActionTypes.PagerUpdate,payload})
});
类QuizContainer扩展组件{
状态={
提问:[
{id:'data/class1.json',name:'Class 1'},
{id:'data/class2.json',name:'Class 2'},
{id:'data/class3.json',name:'class3'},
{id:'data/class4.json',name:'class4'},
],
quizId:'data/class1.json'
};
寻呼机={
索引:0,
尺寸:1,
计数:1
}
componentDidMount(){
log('componentDidMount');
this.load(this.state.quizId);
}
装载(quizId、isValReload){
console.log('In load');
让url=quizId | | this.props.quizId;
if(isValReload){
让quick=this.props.quizAll.find(a=>url.indexOf(`${a.id}.`)!=-1);
log('In load quick:',quick);
this.pager.count=quick.questions.length/this.pager.size;
这个.props.onQuizLoad(测验);
this.props.onPagerUpdate(this.pager);
}
否则{
获取(`../${url}`)。然后(res=>res.json())。然后(res=>{
让测验=res;
测验。问题。forEach(q=>{
q、 options.forEach(o=>o.selected=false);
});
quick.config=Object.assign(this.props.quick.config | |{},quick.config);
this.pager.count=quick.questions.length/this.pager.size;
这个.props.onQuizLoad(测验);
this.props.onPagerUpdate(this.pager);
});
}
}
//此事件实现了在不完成currentlyselectd类的情况下更改类的限制
onClassClick=(e)=>{
让qus=this.props.quick.questions;
//控制台日志(qus);
让isNotAllAns=qus.some((q,i)=>{
var isNot=false;
if(q.answerType.id!==3&&q.answerType.id!==4){
isNot=(q.options.find((o)=>o.selected==true))==未定义;
}
否则{
//console.log('q',q);
isNot=((q.answers==“”| | q.answers.length==0));
}
返回不是;
});
如果(isNotAllAns){
警惕('请完成测验');
e、 停止传播();
}
}
/*
saveQuizAll(_quizAll,_测验){
让所有测验=[];
//,quizAll,测验;
//如果(真){
//_quick=this.quick;
//_quizAll=this.quizAll;
// }
日志(这是一个测验,_quizAll);
如果(_quick.questions.length!==0){
如果(_quizAll.length!==未定义){
log('不是初始设置拼接',_quick.id);
所有测验=_quizAll;
const qIndex=this.getQuizIndex(_quick.id.toString());
如果(qIndex>-1){
所有测验.拼接(qIndex,1,_测验);
}
否则{
Allquick.拼接(_quizAll.length,0,_quick);
//allquick.splice(this.props.quizAll.length-1,0,this.props.quizAll,this.props.quizAll);
}
}
否则{
所有测验[0]=\u测验;
}
返回所有测验;
//如果(真){
//这个.onQuizChange(allquick);
// }
}
}
*/
onChange=(e)=>{
//log(this.props.quizAll,this.props.quizAll.length);
让所有测验=[];
allquick=saveQuizAll(this.props.quizAll,this.props.quick);
//下面的代码转换为saveQuizAll funstion
/*
if(this.props.quizAll.length!==未定义){
console.log('不是初始设置拼接',this.props.quick.id);
allquick=this.props.quizAll;
const qIndex=this.getQuizIndex(this.props.quick.id.toString());
如果(qIndex>-1){
allquick.splice(qIndex,1,this.props.quick);
}
否则{
allquick.splice(this.props.quizAll.length,0,this.props.quick);
//allquick.splice(this.props.quizAll.length-1,0,this.props.quizAll,this.props.quizAll);
}
}
否则{
allquick[0]=this.props.quick;
}
*/
//log('allquick Out-',allquick);
this.props.onQuizChange(allquick);
log('Check QuizAll-',this.props.QuizAll);
const-aQuiz=JSON.parse(JSON.stringify(this.props.quizAll));
this.setState({quizId:e.target.value});
if(aQuiz.length!==undefined&&getQuizIndex(this.props.quizAll,e.target.value)>-1){
//log(aQuiz.findIndex(a=>e.target.value.indexOf(`${a.id}.`)!=-1));
此.load(即目标值,true);
}
否则{
this.setState({quizId:e.target.value});
此.load(例如,target.value,false);
}
}
//getQuizIndex(qID){
//返回这个.props.quizAll.findIndex(a=>(qID.indexOf(`a.id}.`)!=-1 | | qID.indexOf(`a.id})!=-1);
// }
render(){
返回(
DADt应用
选择测验:
{this.state.quizes.map(q=>{q.name}}
);
}
}
导出默认连接(MapStateTops、mapDispatchToProps)(QuizContainer);
这是我的<
import React, { Component } from 'react';
import { ActionTypes } from '../redux/constants/actionTypes';
import Review from './Review';
import Questions from './Questions';
import Result from './Result';
import { connect } from 'react-redux';
// import { saveQuizAll } from '../commonjs/common.js';
const mapStateToProps = state => { return { ...state.quiz, ...state.mode, ...state.pager, ...state.quizAll } };
const mapDispatchToProps = dispatch => ({
onSubmit: payload => dispatch({ type: ActionTypes.QuizSubmit, payload }),
onQuizChange: payload => dispatch({ type: ActionTypes.QuizAnswerAll, payload }),
onPagerUpdate: payload => dispatch({ type: ActionTypes.PagerUpdate, payload })
});
class Quiz extends Component {
move = (e) => {
let id = e.target.id;
let index = 0;
if (id === 'first')
index = 0;
else if (id === 'prev')
index = this.props.pager.index - 1;
else if (id === 'next') {
index = this.props.pager.index + 1;
}
else if (id === 'last')
index = this.props.pager.count - 1;
else
index = parseInt(e.target.id, 10);
if (index >= 0 && index < this.props.pager.count) {
let pager = {
index: index,
size: 1,
count: this.props.pager.count
};
this.props.onPagerUpdate(pager);
}
}
saveStore(e) {
let allQuiz = [];
console.log(this, e);
allQuiz = this.props.saveAll(e.props.quizAll, e.props.quiz);
console.log(allQuiz);
this.props.onQuizChange(allQuiz);
}
setMode = (e) => this.props.onSubmit(e.target.id);
// setMode(e) {
// console.log('in mode',e);this.props.onSubmit(e.target.id);
// }
renderMode() {
console.log('Inside here', this.props.mode);
if (this.props.mode === 'quiz') {
return (<Questions move={this.move} />)
} else if (this.props.mode === 'review') {
return (<Review quiz={this.props.quiz} move={this.move} />)
} else {
console.log('Before Results');
const divSel = document.querySelector('div.col-6.text-right');
// console.log('divSel', divSel);
if (divSel) {
divSel.style.display = "none";
}
return (<Result questions={this.props.quizAll || []} />)
}
}
render() {
return (
<div>
{this.renderMode()}
{(this.props.mode !== 'submit') &&
<div>
<hr />
<button id="quiz" className="btn btn-primary" onClick={this.setMode}>Quiz</button>
<button id="review" className="btn btn-primary" onClick={this.setMode}>Review</button>
<button id="submit" className="btn btn-primary" onClick={(e) => {this.setMode(e); this.saveStore(this)}}>Submit Quiz</button >
</div >}
</div>
)
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Quiz);
{ !(this.props.duration-this.state.seconds) && this.props.onTimeFinished() }
// state
state = {
triggerSubmit: false
}
// functions
doSubmit = () => {
this.setState({ triggerSubmit: true });
}
resetSubmit = () => {
this.setState({ triggerSubmit: false });
}
// jsx
<Timer duration={900} doSubmit={this.doSubmit} />
<Quiz
quiz={this.state.quiz}
quizId={this.state.quizId}
saveAll={saveQuizAll}
mode={this.state.mode}
resetSubmit={this.resetSubmit}
triggerSubmit={this.state.triggerSubmit} />
// function
doSubmit = (timeLeft) => {
if (timeLeft === 0) {
this.props.doSubmit();
}
}
// jsx
<p className="badge badge-success"
onChange={() => {this.doSubmit(timeLeft)}>
Time Left: {minutesDisplay}{secondsDisplay}
</p>
// state
state = {
triggerSubmit: this.props.triggerSubmit
}
// function
triggerSubmit = () => {
if (this.state.triggerSubmit) {
your trigger submit code here...
this.props.resetSubmit();
}
}
// ...
constructor(props) {
// ...
this.state = {
timeExpired: false
};
}
const onTimeExpired = () => {
this.setState({timeExpired: true});
}
// ...
render() {
return (
<div className="container">
{ // ... }
<Timer duration={900} onTimeExpired={onTimeExpired}/>
<Quiz quiz={this.state.quiz} quizId={this.state.quizId} saveAll={saveQuizAll} mode={this.state.mode} triggerSubmit={this.state.timeExpired} />
</div>
);
}
// ...
componentDidUpdate() {
if (this.state.seconds === this.props.duration) {
this.props.onTimeExpired();
}
}
// ...
// ...
componentDidUpdate() {
if (this.props.triggerSubmit) {
// Do whatever you do on submit
}
}
// ...
// ...
componentDidUpdate() {
if (this.state.seconds === this.props.duration) {
const quizForm = document.getElementById('quizFormId');
quizForm && quizForm.submit();
}
}
// ...