马黑黑 发表于 2024-6-14 08:09

大湖

本帖最后由 马黑黑 于 2024-6-14 08:48 编辑 <br /><br /><style>
#tz { margin: 30px 0 30px calc(50% - 721px); width: 1280px; height: 750px; background: lightblue; box-shadow: 3px 3px 6px rgba(0,0,0,.6); overflow: hidden; user-select: none; z-index: 1; perspective: 2000px; position: relative; }
#picbox { position: absolute; opacity: .8; border-radius: 20px; transform-style: preserve-3d; cursor: pointer; }
#vid { position: absolute; bottom: 0; width: 100%; height: calc(100% + 65px); object-fit: cover; pointer-events: none; }
</style>

<div id="tz">
        <video id="vid" src="https://img.tukuppt.com/video_show/2418175/00/01/83/5b4b0c1e236a1.mp4" autoplay loop muted disablePictureInPicture></video>
        <audio id="aud" src="https://music.163.com/song/media/outer/url?id=1411157155" autoplay loop></audio>
        <img id="picbox" src="https://638183.freep.cn/638183/small/hxxb.webp" alt="" />
</div>

<script>
(function() {
        const pics = new Array(5).fill(0).map((_,k) => 'https://638183.freep.cn/638183/t24/3/dh' + (k+1) + '.jpeg');
        let ani, ar = [];
        const loadImages = async urls => {
                const promises = [];
                for (let url of urls) {
                        promises.push(new Promise(resolve => {
                                const img = new Image();
                                img.onload = () => {
                                        ar.push([`${img.src}`, `${img.naturalWidth}`, `${img.naturalHeight}`]);
                                        resolve();
                                };
                                img.src = url;
                        }));
                }
                await Promise.all(promises);
                showPic();
        };
        const showPic = () => {
                let idx = Math.floor(Math.random() * pics.length);
                let w1 = tz.offsetWidth, h1 = tz.offsetHeight, w2 = ar, h2 = ar;
                let x = Math.random() > 0.5 ? w1 : -w1, y = Math.random() > 0.5 ? h1 : -h2;
                picbox.src = ar;
                const kfs = [
                        {left: `${x}px`, top: `${y}px`},
                        {left: `${(w1 - w2) / 2}px`, top: `${(h1 - h2) / 2}px`, transform: `rotateY(0)`, offset: 0.1},
                        {transform: `rotateY(-15deg)`},
                        {transform: `rotateY(0)`},
                        {transform: `scale(1.2)`},
                        {transform: `scale(0.8)`},
                        {transform: `rotateY(15deg)`},
                        {left: `${(w1 - w2) / 2}px`, top: `${(h1 - h2) / 2}px`, transform: `rotateY(0)`, offset: 0.9},
                        {left: `${x}px`, top: `${y}px`, transform: `rotateZ(180deg) scale(0)`},
                ];
                ani = picbox.animate(kfs, 10000);
                ani.onfinish = () => showPic();
        };
        picbox.onclick = () => aud.paused ? (aud.play(), ani.play()) : (aud.pause(), ani.pause());
        picbox.onmouseover = () => { if(!aud.paused) ani.pause(); };
        picbox.onmouseout = () => { if(!aud.paused) ani.play(); };
        loadImages(pics);
})();
</script>

马黑黑 发表于 2024-6-14 08:10

本帖最后由 马黑黑 于 2024-6-14 08:48 编辑

帖子代码
<style>
#tz { margin: 30px 0 30px calc(50% - 721px); width: 1280px; height: 750px; background: lightblue; box-shadow: 3px 3px 6px rgba(0,0,0,.6); overflow: hidden; user-select: none; z-index: 1; perspective: 2000px; position: relative; }
#picbox { position: absolute; opacity: .8; border-radius: 20px; transform-style: preserve-3d; cursor: pointer; }
#vid { position: absolute; bottom: 0; width: 100%; height: calc(100% + 65px); object-fit: cover; pointer-events: none; }
</style>

<div id="tz">
      <video id="vid" src="https://img.tukuppt.com/video_show/2418175/00/01/83/5b4b0c1e236a1.mp4" autoplay loop muted disablePictureInPicture></video>
      <audio id="aud" src="https://music.163.com/song/media/outer/url?id=1411157155" autoplay loop></audio>
      <img id="picbox" src="https://638183.freep.cn/638183/small/hxxb.webp" alt="" />
</div>

<script>
(function() {
      const pics = new Array(5).fill(0).map((_,k) => 'https://638183.freep.cn/638183/t24/3/dh' + (k+1) + '.jpeg');
      let ani, ar = [];
      const loadImages = async urls => {
                const promises = [];
                for (let url of urls) {
                        promises.push(new Promise(resolve => {
                              const img = new Image();
                              img.onload = () => {
                                        ar.push([`${img.src}`, `${img.naturalWidth}`, `${img.naturalHeight}`]);
                                        resolve();
                              };
                              img.src = url;
                        }));
                }
                await Promise.all(promises);
                showPic();
      };
      const showPic = () => {
                let idx = Math.floor(Math.random() * pics.length);
                let w1 = tz.offsetWidth, h1 = tz.offsetHeight, w2 = ar, h2 = ar;
                let x = Math.random() > 0.5 ? w1 : -w1, y = Math.random() > 0.5 ? h1 : -h2;
                picbox.src = ar;
                const kfs = [
                        {left: `${x}px`, top: `${y}px`},
                        {left: `${(w1 - w2) / 2}px`, top: `${(h1 - h2) / 2}px`, transform: `rotateY(0)`, offset: 0.1},
                        {transform: `rotateY(-15deg)`},
                        {transform: `rotateY(0)`},
                        {transform: `scale(1.2)`},
                        {transform: `scale(0.8)`},
                        {transform: `rotateY(15deg)`},
                        {left: `${(w1 - w2) / 2}px`, top: `${(h1 - h2) / 2}px`, transform: `rotateY(0)`, offset: 0.9},
                        {left: `${x}px`, top: `${y}px`, transform: `rotateZ(180deg) scale(0)`},
                ];
                ani = picbox.animate(kfs, 10000);
                ani.onfinish = () => showPic();
      };
      picbox.onclick = () => aud.paused ? (aud.play(), ani.play()) : (aud.pause(), ani.pause());
      picbox.onmouseover = () => { if(!aud.paused) ani.pause(); };
      picbox.onmouseout = () => { if(!aud.paused) ani.play(); };
      loadImages(pics);
})();
</script>

马黑黑 发表于 2024-6-14 08:28

本帖:

(一)使用 async + wait 方式以异步方式同步加载图片,全部图片都加载完毕动画特效才会出来,任何一张图片加载失败就只能看到视频听听歌。

图片地址用数组形式组织,代码中的15行:

const pics = new Array(5).fill(0).map((_,k) => 'https://638183.freep.cn/638183/t24/3/dh' + (k+1) + '.jpeg');

5 就是 5张图片,图片必须真实存在且能有效访问。

可以使用下面的组织方式替换第15行:

const pics = [
    '图片地址1‘,
    '图片地址2‘,
    '图片地址3‘,
    '图片地址1‘,
    '图片地址1‘,
    '图片地址4‘,
];

图片多少张都可以,数组表达正确、图片地址有效就行。

(二)动画的编写其实是语义化的,代码在 37~47 行,花括号 {} 里的语句是描述每一步的动画状态,比如第 38 行,描述动画的位置,CSS的 left 和 top 属性,再比如第 46 行,除了 left、top 这两个CSS属性,还有两个 transform 转换动作,在Z轴旋转180度、缩小为0。描述动画的数据,有一些是事先准备的,如变量 x、y 的值是一定规律下的随机值,w*、h*则是根据父子元素宽高尺寸(可能存在动态变化)而来,有些是定死的,如 40~44 行的transform转换动画。

慢慢熟悉动画的描述并多加尝试后,可以自己修改甚至涉及自己的动画,建议练习是先简单地固定好各种数数据,比如让一张图片从左测跑到右侧或从上跑到下。

(三)用于转场的图片,建议其尺寸最好不要大于帖子宽高尺寸。

起个网名好难 发表于 2024-6-14 09:09

马黑黑 发表于 2024-6-14 08:10
帖子代码

包含内容有点多啊。
1. 有规律的构成图片地址;
2. 获取图片实际尺寸;
3. 随机的生成4种动态显示方式
4.…………

红影 发表于 2024-6-14 09:55

可以使用下面的组织方式替换第15行:

const pics = [
    '图片地址1‘,
    '图片地址2‘,
    '图片地址3‘,
    '图片地址1‘,
    '图片地址1‘,
    '图片地址4‘,
];

这个好,正想问呢,如果上传的图片的地址没有编号怎么办呢。用这个适用面更广了{:4_173:}

红影 发表于 2024-6-14 10:02

这个制作的构思也好,下面波光粼粼的效果,可以通过图片透明度的设置映射上来,每张图片的选择都有水呢,在风水学中,水被认为能够带来财运和幸福。例如,风水学中有“遇水则发”的说法,意味着水的存在能够为居住者带来财富和健康。{:4_173:}

红影 发表于 2024-6-14 10:20

从16到31的这套图片提取挺陌生,还需要好好学习{:4_204:}

红影 发表于 2024-6-14 10:24

{left: `${(w1 - w2) / 2}px`, top: `${(h1 - h2) / 2}px`, transform: `rotateY(0)`, offset: 0.1},

这里的offset:是什么意思,看下面的变成了0.9

醉美水芙蓉 发表于 2024-6-14 11:27

醉美水芙蓉 发表于 2024-6-14 11:29

马黑黑 发表于 2024-6-14 11:53

醉美水芙蓉 发表于 2024-6-14 11:29
这个好,昨天的图片也可以用这样的代码表达吗?

自然可以

马黑黑 发表于 2024-6-14 11:53

醉美水芙蓉 发表于 2024-6-14 11:27
欣赏老师带来的美景!

{:4_190:}

马黑黑 发表于 2024-6-14 11:56

红影 发表于 2024-6-14 10:24
这里的offset:是什么意思,看下面的变成了0.9

之前有过解释,可能你没主要到。

在属性描述中加上 offset 设定,表示对应运动节点在时间节点上的占比,相当于CSS @keyframes 设定 的 10% { 。。。 } 的百分比这个意思。

马黑黑 发表于 2024-6-14 11:57

起个网名好难 发表于 2024-6-14 09:09
包含内容有点多啊。
1. 有规律的构成图片地址;
2. 获取图片实际尺寸;


{:4_190:}

马黑黑 发表于 2024-6-14 11:58

红影 发表于 2024-6-14 09:55
这个好,正想问呢,如果上传的图片的地址没有编号怎么办呢。用这个适用面更广了

有条件的动态生成最好,条件不具备就老老实实写数组代码

马黑黑 发表于 2024-6-14 12:01

红影 发表于 2024-6-14 10:20
从16到31的这套图片提取挺陌生,还需要好好学习

这个是异步加载图片的函数,以确保图片全部成功加载了才运行动画。它的好处是让动画的运行丝滑般流畅,缺点时只要有一张图片不能加载,动画效果出不来。

异步加载图片是个难题,你懂的搬用这个函数就行了。

南无月 发表于 2024-6-14 12:49

图片转场效果的升级版。。
动作设计更加复杂。。{:4_199:}
进场出场比较隆重。

南无月 发表于 2024-6-14 12:55

已完成一跟贴,用了8张图。
这个转场效果是真的漂亮。。。
特别适合多图呈现。。{:4_199:}

梦江南 发表于 2024-6-14 13:46

欣赏老师的精彩制作!{:4_187:}

南无月 发表于 2024-6-14 18:08

transform-style: preserve-3d; 又发现一新的设置
页: [1] 2 3 4 5 6
查看完整版本: 大湖