马黑黑 发表于 2022-7-8 23:03

一个随机在边边角角运动的实例

<style>
#papa {
        margin: 50px auto 0;
        width: 720px;
        height: 600px;
        box-shadow: 4px 4px 24px #000;
        position: relative;
}
#piece {
        position: absolute;
        width: 90px;
        height: 66px;
        transition: all 4s;
}
</style>

<div id="papa">
        <imgid="piece" alt="" src="/data/attachment/forum/202207/08/225900jzc7ctq9wa99r83a.gif" />
</div>

<script>
let aniFlag = 0; //动画标识
let num = (min, max) => Math.floor(Math.random() * (max-min+1)) + min;

setTimeout(gogo,100); //初次运行动画

function gogo() { //动画函数
        let idx1 =num(0,1), idx2 = num(0,1);
        let w1 = papa.clientWidth, w2 = piece.clientWidth, h1 = papa.clientHeight, h2 = piece.clientHeight;
        piece.style.left = (w1 - w2) * idx1 + 'px';
        piece.style.top = (h1 - h2) * idx2 + 'px';
        setTimeout(gogo,6000);
}
</script>

马黑黑 发表于 2022-7-8 23:03

代码:
<style>
#papa {
        margin: 50px auto 0;
        width: 720px;
        height: 600px;
        box-shadow: 4px 4px 24px #000;
        position: relative;
}
#piece {
        position: absolute;
        width: 90px;
        height: 66px;
        transition: all 4s;
}

</style>

<div id="papa">
        <imgid="piece" alt="" src="/data/attachment/forum/202207/08/225900jzc7ctq9wa99r83a.gif" />
</div>

<script>
let aniFlag = 0; //动画标识
let num = (min, max) => Math.floor(Math.random() * (max-min+1)) + min;

setTimeout(gogo,100); //初次运行动画

function gogo() { //动画函数
        let idx1 =num(0,1), idx2 = num(0,1);
        let w1 = papa.clientWidth, w2 = piece.clientWidth, h1 = papa.clientHeight, h2 = piece.clientHeight;
        piece.style.left = (w1 - w2) * idx1 + 'px';
        piece.style.top = (h1 - h2) * idx2 + 'px';
        setTimeout(gogo,6000);
}
</script>

马黑黑 发表于 2022-7-8 23:03

本帖最后由 马黑黑 于 2022-7-8 23:15 编辑

预设的“飞行”路线是酱紫:
每一次都从四个角出发,有时候不出发,因为是随机的,上一个随机数可能与下一次随机数重合,有时候会重合几次。路线有边线,也有对角线。

驱动的实现,利用 left 与 top 值的变更促成:上一个 left 与 top,在一个定时器周期完成后转换为下一个 left 与 top,借助运动对象元素的 transition 设定,达成规定时间内沿两点间的位移效果。transition 的时间少于定时器周期时长,这是逻辑关系问题:动作做完之后才能发起下一个位移。

下楼讲讲JS代码。

马黑黑 发表于 2022-7-8 23:07

本帖最后由 马黑黑 于 2022-7-8 23:32 编辑

下面重点解释一下自定义的 gogo() 函数


[*]function gogo() { //动画函数
[*]      let idx1 =num(0,1), idx2 = num(0,1);
[*]      let w1 = papa.clientWidth, w2 = piece.clientWidth, h1 = papa.clientHeight, h2 = piece.clientHeight;
[*]      piece.style.left = (w1 - w2) * idx1 + 'px';
[*]      piece.style.top = (h1 - h2) * idx2 + 'px';
[*]      setTimeout(gogo,6000);
[*]}

函数不长。

首先,32行,声明并赋值两个变量,idx1和idx2,它们都是通过前面声明的 num() 函数获得 0 到 1 的整数,不是0就是1。这两个变量的作用是随机设定四个角的依据。着四个角,左上、右上、右下、左下可以记为 {0,0}、{0,1}、{1,1}、{0,1},其中,0表示left或top不变,是0px,1表示left或top有变,是父元素宽或高减去子元素宽或高之后的值。

接着,33行,用w1、w2分别获取父元素、子元素的宽度,用h1、h2分别获取父元素、子元素的高度;

34行,计算子元素(id="piece")的左边值(left),(父宽-子宽)* idx1 的式子能理解吧?idx1是随机获得是要么是0要么是1的数,是0时,left值就是0px了,是1时,left值则是 父宽-子宽 个像素的值。

35行,计算子元素的上边值(top),原理和34行同。

35行,setTimeout定时器调用本函数。setTimeout定时器在函数内部运行函数,叫递归调用,会循环不已,前提是要有的函数外的首次调用(这在前面已经有了)。

马黑黑 发表于 2022-7-8 23:37

这个例子,在使用UFO图片之前,我还加入了一个 animation 动画,它运动对象要么向左转动,要么向右旋转,这个UFO已经有这个动作(虽然性质不同),就取消掉了。

结合 @keyframes 令对象运动,可以使得运动的样式更为多样化。

马黑黑 发表于 2022-7-8 23:38

运动方向是随机的,能猜出它下一个运动方向的,去摸奖肯定能中{:4_170:}

马黑黑 发表于 2022-7-8 23:59

如果想设置更复杂的路线,比如可以在任一点停留,思路要改一改:

在 gogo 函数里用一个数组直接装载各点的{xy}像素值,像下面这样,

    let psAr = [,,, ....];

预存储的数组元素越多,运动的路线就越丰富。

然后,用随机数抓取数组中的xy点:

let idx1 = psAr,idx2 = psAr;

再将idx1和idx2赋值给子元素的 left 和 top 值:

piece.style.left = idx1 + 'px';
piece.style.top = idx2 + 'px';

山人 发表于 2022-7-9 07:07

JS里,不见声明待操作元素的操作句柄,例如要对 <div id="piece"></div> 进行相关操作,必先取得其代理变量:

var piece = document.getElementById('piece');

然后才可通过 piece 进行相关的操作。本例直接操作 piece ,事先并未声明,是什么道理?

原来:在 HTML5 里,拥有唯一标识的元素,该标识直接指向该元素,JS中可以直接使用该标识对之进行识别与操作。可能部分浏览器不支持,但不支持的都是已经过时、被废弃的浏览器,如IE和基于IE内核的第三方封装浏览器。我们无需去兼容这一类浏览器,可以按照HTML5的标准去编写代码。

红影 发表于 2022-7-9 08:40

看到一个飞碟在探索边边角角,这是外星人要入侵的节奏么{:4_173:}

红影 发表于 2022-7-9 08:41

马黑黑 发表于 2022-7-8 23:59
如果想设置更复杂的路线,比如可以在任一点停留,思路要改一改:

在 gogo 函数里用一个数组直接装载各点 ...

这个是随机抓取,如果设计个线路,依次抓取是怎样的代码?

红影 发表于 2022-7-9 08:42

红影 发表于 2022-7-9 08:41
这个是随机抓取,如果设计个线路,依次抓取是怎样的代码?

随机的太难控,喜欢它按照约定的线路行进{:4_173:}

马黑黑 发表于 2022-7-9 08:53

本帖最后由 马黑黑 于 2022-7-9 08:57 编辑

红影 发表于 2022-7-9 08:41
这个是随机抓取,如果设计个线路,依次抓取是怎样的代码?
从头到尾依次获得数组中的位置,需要设置一个自增变量,放在JS的比较开始的位置,比如设定为 myIdx:

let myIdx = 0; //开始时是0

然后在自定义函数内,通过 myIdx 得到数组的第 myIdx 元素并将值分别赋予元素的left和top:

piece.style.left = psAr;
piece.style.top = psAr;

接着,在函数内处理 myIdx 增量问题:

myIdx ++;
if(myIdx > psAr.length - 1) myIdx = 0;

上面第一句,是 myIdx 使用完一次就增量,增量会突破数组元素总数,所以要处理一下,这就是第二句:如果 myIdx 大于等于数组元素总数减去1,则 myIdx 回到0,从头开始。读取数组下标从 0 开始,所以式子总是像上面那样去处置。

马黑黑 发表于 2022-7-9 08:53

红影 发表于 2022-7-9 08:40
看到一个飞碟在探索边边角角,这是外星人要入侵的节奏么

是要治理沙漠

马黑黑 发表于 2022-7-9 08:56

红影 发表于 2022-7-9 08:42
随机的太难控,喜欢它按照约定的线路行进

随机需要规定范围便可。既定路线,则需要编写好路线图(用数组装载xy坐标),这也是繁琐的工作。设计一个作品,设计的东西的确很多、很细。

红影 发表于 2022-7-9 09:00

山人 发表于 2022-7-9 07:07
JS里,不见声明待操作元素的操作句柄,例如要对进行相关操作,必先取得其代理变量:

var piece = docum ...

拥有唯一标识的元素,可以不用先取得其代理变量。嗯嗯,记下了{:4_187:}

红影 发表于 2022-7-9 09:01

马黑黑 发表于 2022-7-8 23:38
运动方向是随机的,能猜出它下一个运动方向的,去摸奖肯定能中

能猜出它下一个运动方向的,肯定第一个被外星人抓走{:4_170:}

马黑黑 发表于 2022-7-9 09:10

红影 发表于 2022-7-9 09:01
能猜出它下一个运动方向的,肯定第一个被外星人抓走

因为脑电波对上号了?

红影 发表于 2022-7-9 09:18

马黑黑 发表于 2022-7-8 23:07
下面重点解释一下自定义的 gogo() 函数




原来随机调用是let idx1 =num(0,1), idx2 = num(0,1);

这个let num = (min, max) => Math.floor(Math.random() * (max-min+1)) + min;没看懂,能详细解释一下么?

马黑黑 发表于 2022-7-9 09:41

红影 发表于 2022-7-9 09:18
原来随机调用是let idx1 =num(0,1), idx2 = num(0,1);

这个let num = (min, max) => Math.floor(Math. ...

这是箭头函数,简化的写法。两个参数,min, max,分别表示一大一小的两个数,调用时是这样:

num(1,100)

这将返回从 1(包含1)到 100(包含100)的一个随机整数。

函数的内容是一些运算机制,几个数学方法、式子套用,其中:

Math.random() * (max - min + 1)将得到一个随机浮点数,Math.random() 得到的是 从 0 到 1(不包含1)的浮点数,乘以 max-min+1 自己思考一下。浮点数之前加入Math.floor 表示向下取整。因为这一节获得的数字有可能是0,所以后面加上 min,确保 边界最小数能有机会获取。

红影 发表于 2022-7-9 15:30

马黑黑 发表于 2022-7-9 08:53
从头到尾依次获得数组中的位置,需要设置一个自增变量,放在JS的比较开始的位置,比如设定为 myIdx:

l ...

谢谢黑黑,有个这个,我貌似也应该做个帖子,试验一下按规定线路走{:4_173:}
页: [1] 2 3 4 5
查看完整版本: 一个随机在边边角角运动的实例