电子手表一般有4个按键,有多种状态,在不同的状态下各个按键有不同的功能,若采用if-then结构则系统将变得特别复杂,下面考虑采用状态模式实现其功能,又因为其涉及众多的交互,所以系统采用MVC架构进行输入、输出管理。
系统功能如下: *在正常时间显示状态,按住START键,显示日期,按住RESET键,显示闹铃时间
*跑秒表使用方法:在正常时间显示下,按MODE键1次进入跑秒表工作模式,按START键跑表工作,再按START键跑表停止,显示计时数字,按RESET键数字清零,MODE键返回正常时间显示。
*日期设定: 在正常时间显示下,按MODE键2次,进入时间设定状态,天闪动,按START键,校对天,按RESET键,月闪动,按STSRT键校对月,再按RESET,年闪动,按START键和RESET,校对年,按MODE键返回
*时间设定:在正常时间显示下,按MODE键3次,进入时间设定状态,秒闪动,按START键,校对秒,按RESET键,分钟闪动,按STSRT键校对分钟,再按RESET,小时闪动,按START键校对小时,按MODE键返回
*闹铃时间设定:在正常时间显示下,按MODE键4次,闹铃开启/关闭闪动,再按START键可选择开启/关闭,按RESET键1次,分钟闪动,再按STSRT键设定分钟,按RESET键,再按动STSRT键,小时闪动,可设定小时,按MODE键返回
*闹铃:在闹铃响铃时,按任意键,闹铃停止。
系统代码如下,首先是界面:
<!DOCTYPE html>
<html>
<head>
<script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="myclock.js"></script>
<style>
#screen{
text-align:center;
height:40px;
width:120px;
background-color:darkcyan;
}
</style>
</head>
<body>
<table>
<tr>
<td id='light'>夜光</td><td ></td><td id='start'>启动</td>
</tr>
<tr>
<td></td><td id='screen'></td><td ></td>
</tr>
<tr>
<td id='mode'>模式</td><td ></td><td id='reset'>复位</td>
</tr>
</table>
</body>
</html>
下面是控制代码:
//myclock.js
$(document).ready(function () {
var Model = {
state: '',
milsecond: 0,
second: 0,
minute: 0,
hour: 0,
total_second: 0,
Alarm_on: 0,
Alarm_minute: 0,
Alarm_hour: 0,
start_stopwatch: 0,
stopwatch_milsecond: 0,
stopwatch_second: 0,
stopwatch_minute: 0,
month_days: [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
year: 2000,
month: 1,
day: 1,
configure_YMD: 0, //0->year,1->month,2->day
configure_year: 2000,
configure_month: 1,
configure_day: 1,
configure_HMS: 0, //0->hour,1->minute,3->second
configure_hour: 0,
configure_minute: 0,
configure_second: 0,
configure_Alarm: 0, //0->hour,1->minute
configure_Alarm_hour: 0,
configure_Alarm_minute: 0,
configure_Alarm_on: 0,
add_one_day: function () {
if (this.day < this.month_days[this.month - 1]) {
this.day++;
} else { //最后一天
this.day = 1;
if (12 == this.month) {
this.month = 1;
this.year++;
if ((this.year % 400 == 0) || (this.year % 100 != 0 && this.year % 4 == 0)) {
this.month_days[1] = 29;
} else {
this.month_days[1] = 28;
}
} else {
this.month++;
}
}
},
set_year: function (year) {
if (year <= 0)
year = 1;
if ((year % 400 == 0) || (year % 100 != 0 && year % 4 == 0))
Model.month_days[1] = 29;
else
Model.month_days[1] = 28;
Model.year = year;
Model.configure_year = year;
},
add: function () {
this.milsecond += 10;
if (this.milsecond >= 1000) {
this.second++;
this.milsecond = 0;
}
if (this.second >= 60) {
this.minute++;
this.second = 0;
}
if (this.minute >= 60) {
this.hour++;
this.minute = 0;
}
if (this.hour >= 24) {
this.hour = 0;
this.add_one_day();
}
if (this.start_stopwatch == 1) {
this.stopwatch_milsecond += 10;
if (this.stopwatch_milsecond >= 1000) {
this.stopwatch_second++;
this.stopwatch_milsecond = 0;
}
if (this.stopwatch_second >= 60) {
this.stopwatch_minute++;
this.stopwatch_second = 0;
}
}
if ((1 == this.Alarm_on) && (this.hour == this.Alarm_hour) && (this.minute == this.Alarm_minute) && (0 == this.second) && (0 == this.milsecond)) {
Controller.FSM.ChangeState(AlarmState);
}
},
};
var View = {
View: function () {},
View_NormalState: function () {
$("#screen").html(('0' + Model.hour).substr(-2) + ':' + ('0' + Model.minute).substr(-2) + ':' + ('0' + Model.second).substr(-2));
},
View_Date_Info: function () {
$("#screen").html(('00000' + Model.year).substr(-4) + '年' + ('0' + Model.month).substr(-2) + '月' + ('0' + Model.day).substr(-2) + '日');
},
View_Alarm_Info: function () {
$("#screen").html(('00000' + Model.Alarm_hour).substr(-2) + ':' + ('0' + Model.Alarm_minute).substr(-2) + (Model.Alarm_on == 1 ? " ON" : " OFF"));
},
flash: 0,
View_AlarmState: function () {
this.flash++;
$("#screen").html(('0' + Model.hour).substr(-2) + ':' + ('0' + Model.minute).substr(-2) + ':' + ('0' + Model.second).substr(-2));
var color = Math.trunc(this.flash / 50) % 2 ? "yellow" : "white";
$("table").css("background", color);
},
View_Stopwatch: function () {
$("#screen").html("<span class='blink' ><=></span>" + ('00000' + Model.stopwatch_minute).substr(-2) + ':' + ('0' + Model.stopwatch_second).substr(-2) + ':' + (1000 + Model.stopwatch_milsecond + '0').substr(1, 2));
},
View_Configure_YMD: function () {
var html = "";
var year = ('00000' + Model.configure_year).substr(-4);
var month = ('0' + Model.configure_month).substr(-2);
var day = ('0' + Model.configure_day).substr(-2);
switch (Model.configure_YMD) {
case 2: //year
html = "<span class='blink' >" + year + "</span>年" + month + "月" + day + "日";
break;
case 1: //month
html = year + "年<span class='blink' >" + month + "</span>月" + day + "日";
break;
case 0: //day
html = year + "年" + month + "月<span class='blink' >" + day + "</span>日";
break;
}
$("#screen").html(html);
},
View_Configure_HMS: function () {
var html = "";
var hour = ('0' + Model.configure_hour).substr(-2);
var minute = ('0' + Model.configure_minute).substr(-2);
var second = ('0' + Model.configure_second).substr(-2);
switch (Model.configure_HMS) {
case 2: //hour
html = "<span class='blink' >" + hour + "</span>:" + minute + ":" + second;
break;
case 1: //minute
html = hour + ":<span class='blink' >" + minute + "</span>:" + second;
break;
case 0: //second
html = hour + ":" + minute + ":<span class='blink' >" + second + "</span>";
break;
}
$("#screen").html(html);
},
View_Configure_Alarm: function () {
var html = "";
var hour = ('0' + Model.configure_Alarm_hour).substr(-2);
var minute = ('0' + Model.configure_Alarm_minute).substr(-2);
var Alarm_on = Model.configure_Alarm_on == 1 ? " ON" : " OFF";
switch (Model.configure_Alarm) {
case 2: //hour
html = "<span class='blink' >" + hour + "</span>:" + minute + Alarm_on;
break;
case 1: //minute
html = hour + ":<span class='blink' >" + minute + "</span>" + Alarm_on;
break;
case 0: //minute
html = hour + ":" + minute + "<span class='blink' >" + Alarm_on + "</span>";
break;
}
$("#screen").html(html);
},
blink: 0,
View_Blink: function () {
//if ((Model.state).substr(0, 9) != "Configure")
// return;
var color = View.blink ? "darkcyan" : "black";
View.blink = 1 - View.blink;
$(".blink").css("color", color);
},
};
var Controller = {
timer: null,
FSM: null,
click: function (e) {
Controller.FSM.Update(e);
},
light: function (e) {
if (e.type == "mousedown") {
$("table").css("background", "yellow");
} else {
$("table").css("background", "white");
}
},
};
var StateMachine = {
m_PreviousState: {
name: "",
Enter: function () {},
Exit: function () {},
Update: function (e) {},
},
m_CurrentState: {
name: "",
Enter: function () {},
Exit: function () {},
Update: function (e) {},
},
Update: function (e) {
if (this.m_CurrentState != null)
this.m_CurrentState.Update(e);
},
ChangeState: function (s) {
document.title = s.name;
this.m_PreviousState = this.m_CurrentState;
this.m_CurrentState.Exit();
this.m_CurrentState = s;
this.m_CurrentState.Enter();
},
RevertToPreviousState: function () {
this.ChangeState(this.m_PreviousState);
},
};
var NormalState = {
name: "NormalState",
Enter: function () {
Model.state = 'NormalState';
View.View = View.View_NormalState;
},
Exit: function () {},
Update(e) {
if (e.type == "mousedown") {
switch (e.target.id) {
case "mode": //进入跑秒状态
Controller.FSM.ChangeState(StopwatchState);
break;
case "reset": //显示闹钟时间
View.View = View.View_Alarm_Info;
break;
case "start": //显示日期
View.View = View.View_Date_Info;
break;
}
} else { //mouse up
switch (e.target.id) {
case "reset": //显示闹钟时间
case "start": //显示日期
View.View = View.View_NormalState;
break;
}
}
}
};
var AlarmState = {
name: "AlarmState",
Enter: function () {
Model.state = 'AlarmState';
View.View = View.View_AlarmState;
},
Exit: function () {
$("table").css("background", "white");
},
Update: function (e) {
if (e.type == "mouseup") {
return;
}
Controller.FSM.RevertToPreviousState();
},
};
var StopwatchState = {
name: "StopwatchState",
Enter: function () {
Model.state = 'StopwatchState';
View.View = View.View_Stopwatch;
},
Exit: function () {},
Update(e) {
if (e.type == "mouseup") {
return;
}
switch (e.target.id) {
case "mode": //进入设置年月日状态
Controller.FSM.ChangeState(ConfigureState_YMD);
break;
case "reset": //进入复位暂停状态
Model.stopwatch_milsecond = 0;
Model.stopwatch_second = 0;
Model.stopwatch_minute = 0;
Model.start_stopwatch = 0;
Controller.FSM.ChangeState(StopwatchState_pause);
break;
case "start": //开始计时
Controller.FSM.ChangeState(StopwatchState_start);
break;
}
}
};
var StopwatchState_start = {
name: "StopwatchState_start",
Enter: function () {
Model.start_stopwatch = 1;
},
Exit: function () {},
Update: function (e) {
if (e.type == "mouseup") {
return;
}
switch (e.target.id) {
case "mode": //进入正常状态
Controller.FSM.ChangeState(NormalState);
break;
case "reset": //进入复位暂停状态
Model.stopwatch_milsecond = 0;
Model.stopwatch_second = 0;
Model.stopwatch_minute = 0;
Model.start_stopwatch = 0;
Controller.FSM.ChangeState(StopwatchState_pause);
break;
case "start": //进入暂停状态
Controller.FSM.ChangeState(StopwatchState_pause);
break;
}
},
};
var StopwatchState_pause = {
name: "StopwatchState_pause",
Enter: function () {
Model.start_stopwatch = 0;
},
Exit: function () {},
Update: function (e) {
if (e.type == "mouseup") {
return;
}
switch (e.target.id) {
case "mode": //进入正常状态
Controller.FSM.ChangeState(NormalState);
break;
case "reset": //进入复位暂停状态
Model.stopwatch_milsecond = 0;
Model.stopwatch_second = 0;
Model.stopwatch_minute = 0;
Model.start_stopwatch = 0;
break;
case "start": //开始计时
Controller.FSM.ChangeState(StopwatchState_start);
break;
}
},
};
var ConfigureState_YMD = {
name: "ConfigureState_YMD",
Enter: function () {
Model.configure_year = Model.year;
Model.configure_month = Model.month;
Model.configure_day = Model.day;
Model.configure_YMD = 0;
Model.state = 'ConfigureState_YMD';
View.View = View.View_Configure_YMD;
},
Exit: function () {
Model.year = Model.configure_year;
Model.month = Model.configure_month;
Model.day = Model.configure_day;
Model.configure_YMD = 0;
},
Update(e) {
if (e.type == "mouseup") {
return;
}
switch (e.target.id) {
case "mode": //进入设置时分秒状态
Controller.FSM.ChangeState(ConfigureState_HMS);
break;
case "reset": //调节设置项
Model.configure_YMD++;
if (3 == Model.configure_YMD)
Model.configure_YMD = 0;
break;
case "start": //调节参数
switch (Model.configure_YMD) {
case 2: //year 年要加加减减
Controller.FSM.ChangeState(ConfigureState_YMD_year);
break;
case 1: //month
Model.configure_month++;
if (13 == Model.configure_month)
Model.configure_month = 1;
break;
case 0: //day
Model.configure_day++;
if (Model.configure_day > Model.month_days[Model.configure_month - 1])
Model.configure_day = 1;
break;
}
break;
}
}
};
var ConfigureState_YMD_year = {
name: "Configure_YMD_year",
Enter: function () {
Model.configure_year++;
Model.configure_YMD = 2;
},
Exit: function () {
Model.year = Model.configure_year;
Model.month = Model.configure_month;
Model.day = Model.configure_day;
Model.configure_YMD = 0;
Model.state = 'ConfigureState_YMD';
View.View = View.View_Configure_YMD;
},
Update: function (e) {
if (e.type == "mouseup") {
return;
}
switch (e.target.id) {
case "mode": //返回设置年月日状态
Controller.FSM.ChangeState(ConfigureState_YMD);
break;
case "reset":
Model.set_year(Model.year - 1);
break;
case "start":
Model.set_year(Model.year + 1);
break;
}
},
};
var ConfigureState_HMS = {
name: "ConfigureState_HMS",
Enter: function () {
Model.configure_hour = Model.hour;
Model.configure_minute = Model.minute;
Model.configure_second = Model.second;
Model.configure_HMS = 0;
Model.state = 'ConfigureState_HMS';
View.View = View.View_Configure_HMS;
},
Exit: function () {
Model.hour = Model.configure_hour;
Model.minute = Model.configure_minute;
Model.second = Model.configure_second;
Model.configure_HMS = 0;
},
Update(e) {
if (e.type == "mouseup") {
return;
}
switch (e.target.id) {
case "mode": //进入设置闹钟状态
Controller.FSM.ChangeState(ConfigureState_Alarm);
break;
case "reset": //调节设置项
Model.configure_HMS++;
if (3 == Model.configure_HMS)
Model.configure_HMS = 0;
break;
case "start": //开始配置时间
switch (Model.configure_HMS) {
case 2: //hour
Model.configure_hour++;
if (Model.configure_hour == 24)
Model.configure_hour = 0;
break;
case 1: //minute
Model.configure_minute++;
if (60 == Model.configure_minute)
Model.configure_minute = 0;
break;
case 0: //second
Model.configure_second++;
if (60 == Model.configure_second)
Model.configure_second = 0;
break;
}
break;
}
}
};
var ConfigureState_Alarm = {
name: "ConfigureState_Alarm",
Enter: function () {
Model.configure_Alarm_hour = Model.Alarm_hour;
Model.configure_Alarm_minute = Model.Alarm_minute;
Model.configure_Alarm_on = Model.Alarm_on;
Model.state = 'ConfigureState_Alarm';
View.View = View.View_Configure_Alarm;
},
Exit: function () {
Model.Alarm_hour = Model.configure_Alarm_hour;
Model.Alarm_minute = Model.configure_Alarm_minute;
Model.Alarm_on = Model.configure_Alarm_on;
},
Update(e) {
if (e.type == "mouseup") {
return;
}
switch (e.target.id) {
case "mode": //进入正常状态
Controller.FSM.ChangeState(NormalState);
break;
case "reset": //调节设置项
Model.configure_Alarm++;
if (3 == Model.configure_Alarm)
Model.configure_Alarm = 0;
break;
break;
case "start": //调节设置量
switch (Model.configure_Alarm) {
case 2: //hour
Model.configure_Alarm_hour++;
if (Model.configure_Alarm_hour == 24)
Model.configure_Alarm_hour = 0;
break;
case 1: //minute
Model.configure_Alarm_minute++;
if (60 == Model.configure_Alarm_minute)
Model.configure_Alarm_minute = 0;
break;
case 0: //Alarm_on
Model.configure_Alarm_on = 1 - Model.configure_Alarm_on;
break;
}
break;
}
}
};
//
$("#light").mousedown(Controller.light);
$("#light").mouseup(Controller.light);
$("#mode").mousedown(Controller.click);
$("#mode").mouseup(Controller.click);
$("#reset").mousedown(Controller.click);
$("#reset").mouseup(Controller.click);
$("#start").mousedown(Controller.click);
$("#start").mouseup(Controller.click);
Controller.FSM = StateMachine;
Controller.FSM.ChangeState(NormalState);
Controller.timer = setInterval(function () {
Model.add();
View.View();
View.View_Blink();
}, 10);
});