文章目录
参考:
JavaScript 权威指南(第6版)
HTML5 权威指南
JavaScript 高级程序设计(第3版)
前提:
看了抖音,看见别人要9宫格点击中间按钮,随机选择一种饭吃,有人要玩,也就做一个
目的:
- 方便展示,并且手机电脑都可以
根据目的排除了c++(太麻烦qt),python(好像也是就python web,用Django杀鸡用牛刀?)
那直接用html + js + css , 界面搭建 和 展示都方便,还能练手让理论变实际
一开始的思路 :
step1. 搭建9宫格
step2. 生成随机数(主要功能)
step3. 动画展示(不熟,不会,留最后)
完成看似挺简单
1.搭建9宫格
本来是用元素p然后画格子,再调整布局
太麻烦,直接table不是更简单
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">
td {
border: medium black solid;
width: 50px;
height: 50px;
padding: 5px;
text-align: center;
background-color: white;
}
</style>
</head>
<body>
<div>
<table>
<tr>
<td id="a0">汉堡王</td>
<td id="a1">KFC</td>
<td id="a2">麻辣香锅</td>
</tr>
<tr>
<td id="a7">炒菜</td>
<td id="a8"><button id="start">开始</button></td>
<td id="a3">烤鱼</td>
</tr>
<tr>
<td id="a6">十足</td>
<td id="a5">烧烤</td>
<td id="a4">泡面</td>
</tr>
</table>
</div>
</body>
</html>
id的顺序a0,a1,a2,a3,a4,a5,a6,a7 也是根据之后想要显示的顺序,并且方便dom获取元素
注意:id不能以数字打头
2.生成随机数
点击开始按钮,生成随机数
...
</table>
</div>
<script>
var startBtn = document.getElementById("start");
startBtn.onclick = RunRandom
var selectNum = 0;
var allItems = 8;
function RunRandom() {
/*
开始随机
*/
selectNum = SelectFrom(0, 7);
console.log(selectNum);
// 显示动画
}
function SelectFrom(lowerValue, upperValue) {
/*
随机生成个数
lowerValue Number 最小范围
upperValue Number 最大范围
*/
var choices = upperValue - lowerValue + 1;
return Math.floor(Math.random() * choices + lowerValue);
}
</script>
</body>
</html>
3.动画生成
需要 a0 格子变化css样式变成红色,然后a0格子再变会原来样式,a1格子变成红色,交替进行,知道随机的格子停下
3.1. 测试js怎么控制改变颜色
3.1.1点击开始把a0边框变红
function RunRandom() {
/*
开始随机
*/
selectNum = SelectFrom(0, 7);
console.log(selectNum);
// 显示动画
document.getElementById("a0").style.border = "medium red solid";
}
3.1.2 css过渡动画
function RunRandom() {
/*
开始随机
*/
selectNum = SelectFrom(0, 7);
console.log(selectNum);
// 显示动画
document.getElementById("a0").style.border = "medium red solid";
document.getElementById("a0").style.transitionDelay = "1000ms";
document.getElementById("a0").style.transitionDuration = "2000ms";
}
效果:就是感觉不那么突兀,其实不要也没事
3.2. 如何刷新,交替,让a0 变化
想要了解的更多可以看 JavaScript高级程序设计(第3版) 第25章第1节 和 第8章第1.6节 和 JavaScript权威指南第14章第1节定时器和第16章脚本化css
function RunRandom() {
/*
开始随机
*/
selectNum = SelectFrom(0, 7);
console.log(selectNum);
// 显示动画
// document.getElementById("a0").style.border = "medium red solid";
// document.getElementById("a0").style.transitionDelay = "1000ms";
// document.getElementById("a0").style.transitionDuration = "2000ms";
DoAnim();
}
function DoAnim() {
/*
动画
*/
for (var i = 0; i < allItems; i++) {
var item = document.getElementById(GetIdString(i));
if (i != 0) {
var preItem = document.getElementById(GetIdString(i - 1));
preItem.style.border = "medium black solid"
}
item.style.border = "medium red solid";
}
}
function GetIdString(index) {
/*
根据位置获得元素id
index Number 位置(0开始)
*/
return "a" + index.toString();
}
一开始的测试思路,在debug模式下一步步调试,效果是想要的,但是正常情况下太快了,一闪而过,直接是最后一个,需要延迟下,类似于c++ 中的sleep(),但是js好像没有这个,因为不了解js机制,想着多线程怎么样,然而js是单线程,但js中有两种定时器
3.2.1.定时器
1. setTimeout(func, millisecond, param1, param2 …):
一个函数func在指定的毫秒内之后运行,只运行一次
注意: 这个是在指定毫秒后插入运行,之前的该干啥就干啥
下面是错误示范1:
function DoAnim() {
/*
动画
*/
for (var i = 0; i < allItems; i++) {
setTimeout(function() {
var item = document.getElementById(GetIdString(i));
if (i != 0) {
var preItem = document.getElementById(GetIdString(i - 1));
preItem.style.border = "medium black solid";
}
item.style.border = "medium red solid";
}, 1000);
}
}
想着每次i ++ 的时候延迟运行次setTimeout,但是实际是上面代码相当于(这个比喻不太好,因为函数入口还是在for循环里面)
function DoAnim() {
/*
动画
*/
var i = 0; // 这里提出来因为这个是闭包
for (; i < allItems; i++) {
// 等待1s中运行动画
}
var item = document.getElementById(GetIdString(i));
if (i != 0) {
var preItem = document.getElementById(GetIdString(i - 1));
preItem.style.border = "medium black solid";
}
item.style.border = "medium red solid";
}
也就是for循环了完了,等1s还没结束,1s后结束了,才进入函数位置执行setTimeout里面func的代码
下面是错误示范2:
function DoAnim() {
/*
动画
*/
for (var i = [0]; i[0] < allItems;) {
console.log(i[0]);
setTimeout(function() {
console.log("setTimeout");
var item = document.getElementById(GetIdString(i));
if (i != 0) {
var preItem = document.getElementById(GetIdString(i - 1));
preItem.style.border = "medium black solid";
}
item.style.border = "medium red solid";
i[0] += 1;
}, 1000);
}
}
那我i变化的话在setTimeOut中func内变化,也就是i循环到1s后调用func,再进行i + 1,下一个元素
一开始我以为这个感觉可行,但是定时器的执行方式是:js有个任务列表,任务会按照放的顺序依次运行,之前的没运行完后面的任务是不执行的,也就是setTimeOut过多少毫秒把任务func放的任务列表,如果任务列表为空,则func立刻运行,如果不为空,等上个任务完成后再进行
此方法上个任务也就是for循环一直没有结束,则setTimeOut这个方法不会运行
那我就不用循环,用if来跳出(这个方法太棒了,模拟setInterval)
function RunRandom() {
/*
开始随机
*/
selectNum = SelectFrom(0, 7);
console.log(selectNum);
// 显示动画
// document.getElementById("a0").style.border = "medium red solid";
// document.getElementById("a0").style.transitionDelay = "1000ms";
// document.getElementById("a0").style.transitionDuration = "2000ms";
var beginIndex = -1;
DoAnim(beginIndex);
}
function DoAnim(index) {
/*
动画
*/
index++;
if (index < allItems) {
if (index != 0) {
var preItem = document.getElementById(GetIdString(index - 1));
preItem.style.border = "medium black solid";
}
var item = document.getElementById(GetIdString(index));
item.style.border = "medium red solid";
setTimeout(DoAnim, 400, index);
}
}
这样动画就完成了,后面也就是让格子和随机数符合就行
2. setInterval(func, millisecond, param1, param2 …):
间隔几毫秒钟调用一次func
如果不手动取消clearInterval,则运行到页面结束
(其实这个就是可以看做刷新频率,多久运行次代码)
注意:真正开发很少用到,一般用setTimeout模拟,因为在有多个调用setInterval,不能确保下一个setInterval再上一个setInterval之后调用
function RunRandom() {
/*
开始随机
*/
selectNum = SelectFrom(0, 7);
console.log(selectNum);
// 显示动画
// document.getElementById("a0").style.border = "medium red solid";
// document.getElementById("a0").style.transitionDelay = "1000ms";
// document.getElementById("a0").style.transitionDuration = "2000ms";
var beginIndex = [-1];
// 动画
DoAnim(beginIndex);
}
var AnimInterval;
function DoAnim(beginIndex) {
AnimInterval = setInterval(doAnimDetail, 400, beginIndex);
}
function DoAnimDetail(index) {
index[0] = (index[0] + 1) % allItems;
if (index[0] == (allItems - 1)) {
clearInterval(AnimInterval);
}
if (index[0] != 0) {
var preItem = document.getElementById(GetIdString(index[0] - 1));
preItem.style.border = "medium black solid";
}
var item = document.getElementById(GetIdString(index[0]));
item.style.border = "medium red solid";
}
效果跟setTimeOut一致
3.3. 让最后的位置和随机数一致,并增加随机转几轮 (以setTimeOut为例子)
目的:让roundNum圈的时候结束,修改了部分逻辑
function RunRandom() {
/*
开始随机
*/
selectNum = SelectFrom(0, 7);
var roundNum = SelectFrom(2, 3)
console.log(selectNum, roundNum);
// 显示动画
// document.getElementById("a0").style.border = "medium red solid";
// document.getElementById("a0").style.transitionDelay = "1000ms";
// document.getElementById("a0").style.transitionDuration = "2000ms";
var beginIndex = 0;
var curRoundNum = 0;
// 动画
DoAnim(beginIndex, -1, curRoundNum, roundNum);
}
function DoAnim(index, preIndex, curRoundNum, roundNum) {
/*
动画
*/
if (index == 0) {
curRoundNum++;
}
if (curRoundNum < roundNum || (curRoundNum == roundNum && index < selectNum + 1)) {
if (preIndex != -1) {
var preItem = document.getElementById(GetIdString(preIndex));
preItem.style.border = "medium black solid";
}
var item = document.getElementById(GetIdString(index));
item.style.border = "medium red solid";
preIndex = index;
index = (index + 1) % allItems;
setTimeout(DoAnim, 300, index, preIndex, curRoundNum, roundNum);
}
}
效果:
3.4.细节调整
3.4.1. 重新来一局的时候刷新上一局状态
我直接最粗暴的全部刷新
function RunRandom() {
/*
开始随机
*/
for (var i = 0; i < allItems; i++) {
var item = document.getElementById(GetIdString(i));
item.style.border = "medium black solid";
}
selectNum = SelectFrom(0, 7);
var roundNum = SelectFrom(2, 3)
console.log(selectNum, roundNum);
// 显示动画
// document.getElementById("a0").style.border = "medium red solid";
// document.getElementById("a0").style.transitionDelay = "1000ms";
// document.getElementById("a0").style.transitionDuration = "2000ms";
var beginIndex = 0;
var curRoundNum = 0;
// 动画
DoAnim(beginIndex, -1, curRoundNum, roundNum);
}
效果:
3.4.2. 快到最后的时候有延迟的效果
也就是最后几个的时候等待时间变长
也修改了之前3.3.判断方式
var startBtn = document.getElementById("start");
startBtn.onclick = RunRandom
var selectNum = 0;
var allItems = 8;
var speed = 300;
function RunRandom() {
/*
开始随机
*/
speed = 300;
for (var i = 0; i < allItems; i++) {
var item = document.getElementById(GetIdString(i));
item.style.border = "medium black solid";
}
selectNum = SelectFrom(0, 7);
var roundNum = SelectFrom(2, 3)
console.log(selectNum, roundNum);
// 显示动画
// document.getElementById("a0").style.border = "medium red solid";
// document.getElementById("a0").style.transitionDelay = "1000ms";
// document.getElementById("a0").style.transitionDuration = "2000ms";
var beginIndex = 0;
var curNum = 0;
// 动画
DoAnim(beginIndex, -1, curNum, roundNum * allItems + selectNum + 1);
}
function DoAnim(index, preIndex, curNum, animCount) {
/*
动画
*/
if (curNum == animCount - 3) {
speed = 400;
}
if (curNum > animCount - 3) {
speed = speed + 100;
}
if (curNum < animCount) {
if (preIndex != -1) {
var preItem = document.getElementById(GetIdString(preIndex));
preItem.style.border = "medium black solid";
}
var item = document.getElementById(GetIdString(index));
item.style.border = "medium red solid";
preIndex = index;
index = (index + 1) % allItems;
curNum++;
setTimeout(DoAnim, speed, index, preIndex, curNum, animCount);
}
}
效果:
后话:
把这些增加了到30多个,然后玩了几次,不玩了,原因吃不起,哈哈哈哈哈,随机数那里应该根据平均消费增加权值,不然纯随机,算了