通过随机选择吃啥了解js动画

参考:

JavaScript 权威指南(第6版)
HTML5 权威指南
JavaScript 高级程序设计(第3版)

前提:

看了抖音,看见别人要9宫格点击中间按钮,随机选择一种饭吃,有人要玩,也就做一个

目的:

  1. 方便展示,并且手机电脑都可以
    根据目的排除了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多个,然后玩了几次,不玩了,原因吃不起,哈哈哈哈哈,随机数那里应该根据平均消费增加权值,不然纯随机,算了
在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值