大湖
本帖最后由 马黑黑 于 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: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>
本帖:
(一)使用 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 08:10
帖子代码
包含内容有点多啊。
1. 有规律的构成图片地址;
2. 获取图片实际尺寸;
3. 随机的生成4种动态显示方式
4.………… 可以使用下面的组织方式替换第15行:
const pics = [
'图片地址1‘,
'图片地址2‘,
'图片地址3‘,
'图片地址1‘,
'图片地址1‘,
'图片地址4‘,
];
这个好,正想问呢,如果上传的图片的地址没有编号怎么办呢。用这个适用面更广了{:4_173:} 这个制作的构思也好,下面波光粼粼的效果,可以通过图片透明度的设置映射上来,每张图片的选择都有水呢,在风水学中,水被认为能够带来财运和幸福。例如,风水学中有“遇水则发”的说法,意味着水的存在能够为居住者带来财富和健康。{:4_173:} 从16到31的这套图片提取挺陌生,还需要好好学习{:4_204:} {left: `${(w1 - w2) / 2}px`, top: `${(h1 - h2) / 2}px`, transform: `rotateY(0)`, offset: 0.1},
这里的offset:是什么意思,看下面的变成了0.9 醉美水芙蓉 发表于 2024-6-14 11:29
这个好,昨天的图片也可以用这样的代码表达吗?
自然可以 醉美水芙蓉 发表于 2024-6-14 11:27
欣赏老师带来的美景!
{:4_190:} 红影 发表于 2024-6-14 10:24
这里的offset:是什么意思,看下面的变成了0.9
之前有过解释,可能你没主要到。
在属性描述中加上 offset 设定,表示对应运动节点在时间节点上的占比,相当于CSS @keyframes 设定 的 10% { 。。。 } 的百分比这个意思。 起个网名好难 发表于 2024-6-14 09:09
包含内容有点多啊。
1. 有规律的构成图片地址;
2. 获取图片实际尺寸;
{:4_190:} 红影 发表于 2024-6-14 09:55
这个好,正想问呢,如果上传的图片的地址没有编号怎么办呢。用这个适用面更广了
有条件的动态生成最好,条件不具备就老老实实写数组代码 红影 发表于 2024-6-14 10:20
从16到31的这套图片提取挺陌生,还需要好好学习
这个是异步加载图片的函数,以确保图片全部成功加载了才运行动画。它的好处是让动画的运行丝滑般流畅,缺点时只要有一张图片不能加载,动画效果出不来。
异步加载图片是个难题,你懂的搬用这个函数就行了。 图片转场效果的升级版。。
动作设计更加复杂。。{:4_199:}
进场出场比较隆重。 已完成一跟贴,用了8张图。
这个转场效果是真的漂亮。。。
特别适合多图呈现。。{:4_199:} 欣赏老师的精彩制作!{:4_187:} transform-style: preserve-3d; 又发现一新的设置