马黑黑 发表于 2023-6-29 07:17

生命之光

<style>
#mydiv {
        margin: 0 0 0 calc(50% - 593px);
        width: 1024px;
        height: 620px;
        border: 1px solid tan;
        background: url('https://638183.freep.cn/638183/t23/2/umvg_r.jpg'),
                url('https://638183.freep.cn/638183/rb2.jpg') no-repeat center/cover,
                url('https://638183.freep.cn/638183/t22/gif/wave.gif') no-repeat 300px 480px;
        background-blend-mode: screen,screen;
        box-shadow: 0 0 8px #000;
        position: relative;
        --state: paused;
}
.circle {
        width: 100px;
        height: 100px;
        top: 0;left: 0;
        border-radius: 50%;
        border: 6px solid tan;
        border-color: red tan pink purple;
        box-sizing: border-box;
        background: url('https://638183.freep.cn/638183/t23/2/umvg.jpg') no-repeat center/cover;
        display: block;
        position: absolute;
        offset-path: path('M30 300 Q512 -200, 994 300');
        cursor: pointer;
        opacity: .65;
        animation: rot 6s var(--delay) infinite linear var(--state);
}
@keyframes rot { to { transform: rotate(360deg); } }
</style>

<div id="mydiv"></div>
<audio id="aud" src="https://music.163.com/song/media/outer/url?id=132674" autoplay="autoplay" loop="loop"></audio>

<script>
(function() {
        let spans = [];
        let setRgb = () => {
                let ar = [];
                for(i = 0; i < 3; i ++) {
                        ar.push(Math.floor(Math.random() * 256));
                }
                return ar.join(',');
        };
        let mkEles = (papa,n) => {
                Array.from({length: n}).forEach( (item,key) => {
                        item = document.createElement('span');
                        item.className = 'circle';
                        item.style.cssText += `
                                border-color: rgb(${setRgb()}) rgb(${setRgb()}) rgb(${setRgb()}) rgb(${setRgb()});
                                offset-distance: ${100 / n * (key + .5)}%;
                                --delay: ${Math.random() * -6}s;
                        `;
                        spans.push(item);
                        papa.appendChild(item);
                });
        };
        mkEles(mydiv,8);
        let mState = () => mydiv.style.setProperty('--state', aud.paused ? 'paused' : 'running');
        aud.addEventListener('play', mState, false);
        aud.addEventListener('pause', mState, false);
        spans.forEach((item) => item.onclick = () => aud.paused ? aud.play() : aud.pause());
})();
</script>

马黑黑 发表于 2023-6-29 07:17

帖子代码
<style>
#mydiv {
        margin: 0 0 0 calc(50% - 593px);
        width: 1024px;
        height: 620px;
        border: 1px solid tan;
        background: url('https://638183.freep.cn/638183/t23/2/umvg_r.jpg'),
                url('https://638183.freep.cn/638183/rb2.jpg') no-repeat center/cover,
                url('https://638183.freep.cn/638183/t22/gif/wave.gif') no-repeat 300px 480px;
        background-blend-mode: screen,screen;
        box-shadow: 0 0 8px #000;
        position: relative;
        --state: paused;
}
.circle {
        width: 100px;
        height: 100px;
        top: 0;left: 0;
        border-radius: 50%;
        border: 6px solid tan;
        border-color: red tan pink purple;
        box-sizing: border-box;
        background: url('https://638183.freep.cn/638183/t23/2/umvg.jpg') no-repeat center/cover;
        display: block;
        position: absolute;
        offset-path: path('M30 300 Q512 -200, 994 300');
        cursor: pointer;
        opacity: .65;
        animation: rot 6s var(--delay) infinite linear var(--state);
}
@keyframes rot { to { transform: rotate(360deg); } }
</style>

<div id="mydiv"></div>
<audio id="aud" src="https://music.163.com/song/media/outer/url?id=132674" autoplay="autoplay" loop="loop"></audio>

<script>
(function() {
        let spans = [];
        let setRgb = () => {
                let ar = [];
                for(i = 0; i < 3; i ++) {
                        ar.push(Math.floor(Math.random() * 256));
                }
                return ar.join(',');
        };
        let mkEles = (papa,n) => {
                Array.from({length: n}).forEach( (item,key) => {
                        item = document.createElement('span');
                        item.className = 'circle';
                        item.style.cssText += `
                                border-color: rgb(${setRgb()}) rgb(${setRgb()}) rgb(${setRgb()}) rgb(${setRgb()});
                                offset-distance: ${100 / n * (key + .5)}%;
                                --delay: ${Math.random() * -6}s;
                        `;
                        spans.push(item);
                        papa.appendChild(item);
                });
        };
        mkEles(mydiv,8);
        let mState = () => mydiv.style.setProperty('--state', aud.paused ? 'paused' : 'running');
        aud.addEventListener('play', mState, false);
        aud.addEventListener('pause', mState, false);
        spans.forEach((item) => item.onclick = () => aud.paused ? aud.play() : aud.pause());
})();
</script>

岩新新 发表于 2023-6-29 07:18

欣赏精彩制作!

马黑黑 发表于 2023-6-29 07:48

本帖最后由 马黑黑 于 2023-6-29 21:55 编辑

本帖构造:一个主 div 带 8 个子 span 。

一、主 div 是帖子的主体,它有 3 个背景图片:

第一张正常显示,其尺寸与帖子设定的一样,无需其他参数;
第二张尺寸和帖子的不太一致,因此有 no-repeat 和 center/cover 参数值,使得图片平铺在帖子之上。两张图片重叠,需要给第二张一个融合滤镜,background-blend-mode: screen, ...; ,将该图的黑色背景去掉;
第三种是水纹动图(悄然做的小图),所以也不给它复制(no-repeat),并设定位置在帖子主元素的{300px,400px}处。它也是黑色底的图片,所以给的滤镜和第二张一样,这句滤镜设置,是针对第二、三张背景图片的: background-blend-mode: screen, screen; 。

二、8 个 span 标签:

① 在CSS中设置基本属性:宽、高、位置、形状、动画、布局用的 offset-path 路径等等;
② 通过JS将这 8 个 span 在页面加载时动态追加到帖子 div 标签中(代码从39行至60行)。

三、关于 offset-path 路径:

第 26 行,offset-path: path('M30 300 Q512 -200, 994 300'); ,路径 path 用的是二次贝塞尔曲线,这里解释一下:

M30 300 表示,将路径起始点移到 {30,300} 坐标处;
Q512 -200, 994 300 中有两组xy坐标,第一组 512,-200 是曲线的控制点,这个点在帖子X轴的中央、Y轴的上方 -200px 处;第二组 994 300 是曲线的终点xy坐标值。大写 Q 表示用绝对数值来表示坐标点,两组数值代表的都是基于帖子上的xy坐标。
而 offset-distance 则用于布置每一个圆圈在路径上的位置,这个工作由JS完成,第 53 行代码,offset-distance: ${100 / n * (key + .5)}%; ,优化过的算法,欢迎感兴趣的朋友一起讨论。

红影 发表于 2023-6-29 10:08

8个小球播放器按钮,而且每个的外边框带颜色是构成是随机的。这个帖子里又好多新的东西{:4_199:}

红影 发表于 2023-6-29 10:11

马黑黑 发表于 2023-6-29 07:17
帖子代码

关于多个背景图片,黑黑之前讲过,这里算是复习了。
直接写成background-blend-mode: screen,screen;用于后两个图片,这个不太熟,还以为每个都要分开写呢{:4_173:}

红影 发表于 2023-6-29 10:31

马黑黑 发表于 2023-6-29 07:48
本帖构造:一个主 div 带 8 个子 span 。

一、主 div 是帖子的主体,它有 3 个背景图片:

关于8 个 span 标签的设置就不懂了,css部分还行,主要还是迷糊在JS上{:4_173:}
40-46句是设置小球的边框颜色的?要是没这个环节,JS应该会简单很多吧。
‘offset-distance: ${100 / n * (key + .5)}%; ,优化过的算法’,这个没看懂。小球在总路径里占的百分比为什么要加.5?

醉美水芙蓉 发表于 2023-6-29 11:48

马黑黑 发表于 2023-6-29 12:18

醉美水芙蓉 发表于 2023-6-29 11:48
欣赏老师新作品!

{:4_190:}

马黑黑 发表于 2023-6-29 12:32

本帖最后由 马黑黑 于 2023-6-29 12:38 编辑

红影 发表于 2023-6-29 10:31
关于8 个 span 标签的设置就不懂了,css部分还行,主要还是迷糊在JS上
40-46句是设置小球的边 ...
CSS不能动态地设置属性,它是静态的,设置完就完了。所以,需要JS来完成后续操作。

39行,设置一个数组,let span=[]; , 用以装载 span 数组元素;

40-46行,设计一个函数,生成rgb 颜色。rgb颜色格式为 rgb(R值, G值, B值) ,也就是红绿蓝三个值,所以用 for 语句循环三次;

47-59行,设计一个函数,用于生成 span 元素并追加到宿主元素中,参数 papa 是宿主元素,n 是 多少个span标签。其中:

遍历 n 次,每一次都里 item 变量作为 span 元素,该元素 className 为 circle,该元素追加的 CSS 样式为 ①边框颜色,这里调用了前面的生成rgb颜色的函数四次,因为边框有四个;② offset-distance 属性,依据各自的序号 key 来计算它应在路径 offset-path 上的位置;③ CSS变量 --delay 的值,用负数是为了让各自随机提前运行关键帧动画,制造个体旋转的时差;④ 56和57行,分别是,将 item 即 span 标签加入数组 spans 中、将 item 即 span 标签追加到宿主元素中。

60行,运行生成span元素的函数。
64行:所有 span 标签的单击操作事件。

马黑黑 发表于 2023-6-29 12:43

红影 发表于 2023-6-29 10:11
关于多个背景图片,黑黑之前讲过,这里算是复习了。
直接写成background-blend-mode: screen,screen;用 ...
像本帖这样有三个背景图片,第一个是不用设置的,仅设置第二、三个。也就是说,

background-blend-mode: screen,screen;

两个融合滤镜值仅作用于第二和第三个背景图片。

假如我们这么设置背景:

background: #eee url(...), url(...), url(...);

则,第一个背景颜色是 #eee,这时,融合滤镜理论上要这么设置:

background-blend-mode: normal, screen,screen;

第一张图片用 normal 即正常滤镜就是不用滤镜,第二和第三张使用 screen 滤镜值。

马黑黑 发表于 2023-6-29 12:47

红影 发表于 2023-6-29 10:31
关于8 个 span 标签的设置就不懂了,css部分还行,主要还是迷糊在JS上
40-46句是设置小球的边 ...

优化后的公式看不懂正常。如果不优化,应看就能懂。

初中数学的提取公因式应该不会忘吧?想想能不能还原出优化前的式子。

梦缘 发表于 2023-6-29 16:54

问好老师,欣赏精彩佳作,谢谢分享,点赞!{:4_204:}

梦油 发表于 2023-6-29 17:03

八个圆各个都有 “机关” 啊!这八个都是播放器吧?

红影 发表于 2023-6-29 19:30

马黑黑 发表于 2023-6-29 12:32
CSS不能动态地设置属性,它是静态的,设置完就完了。所以,需要JS来完成后续操作。

39行,设置一个数 ...

这个解释更清晰了,谢谢黑黑{:4_187:}

红影 发表于 2023-6-29 19:32

马黑黑 发表于 2023-6-29 12:43
像本帖这样有三个背景图片,第一个是不用设置的,仅设置第二、三个。也就是说,

background-blend-mod ...

哦,这里还有这样的细节需要注意啊,现在知道了{:4_187:}

红影 发表于 2023-6-29 19:36

马黑黑 发表于 2023-6-29 12:47
优化后的公式看不懂正常。如果不优化,应看就能懂。

初中数学的提取公因式应该不会忘吧?想想能不能还 ...

打开这个算式就是100% / n * key +50% / n ?还是没明白为什么加后面这个{:4_173:}

马黑黑 发表于 2023-6-29 20:32

本帖最后由 马黑黑 于 2023-6-29 20:33 编辑

红影 发表于 2023-6-29 19:36
打开这个算式就是100% / n * key +50% / n ?还是没明白为什么加后面这个
你这个这是学霸的解法:100% / n * key + 50% / n

我不是学霸,是这么列算式的:100 / n * key + 100 / n / 2

这是有意思的:① 100 / n 是获得 n 个元素的百分比平均值,100 / n * key 则得出第 key 个元素在路径上处在百分之几的位置;② 由于元素有宽度,在offset-path 路径上要均匀分布,需要作细微调整,就是,每一个元素在自己的百分比位置上往右挪动平均百分比的一半,即 100 / n / 2,因此,初始算式是 100 / n * key + 100 / n / 2

马黑黑 发表于 2023-6-29 20:34

红影 发表于 2023-6-29 19:32
哦,这里还有这样的细节需要注意啊,现在知道了

这需要实际操作、总结经验

马黑黑 发表于 2023-6-29 20:35

红影 发表于 2023-6-29 19:30
这个解释更清晰了,谢谢黑黑

网页的动态与交互,基本离不开JS
页: [1] 2 3 4 5
查看完整版本: 生命之光