杨帆 发表于 2025-11-3 22:50

《天际》(学习马老师帖《自定义元素缩放》)

本帖最后由 杨帆 于 2025-11-4 12:59 编辑 <br /><br /><style>
    @import 'https://638183.freep.cn/638183/web/css/tz01.css';
    @import 'https://638183.freep.cn/638183/web/tz/tz.min.css?v2';
    #pa { --offsetX: 81px;--bg: url('https://pic1.imgdb.cn/item/6902f6e53203f7be00b424ab.jpg') no-repeat center/cover;--state:running;overflow: hidden;user-drag: none; user-select: none; }
    #player { position: absolute;width: 200px;height: 200px;--state: running;right: 20px; bottom: 20px; background: radial-gradient(transparent 7%, lightgreen 7.5%, navy); clip-path: path('M0 100 A1 1 0 0 0 100 0 A1 1 0 0 0 200 100 A1 1 0 0 0 100 200 A1 1 0 0 0 0 100'); transition: transform .5s;cursor: pointer; animation: rotate 8s linear infinite var(--state); }
    #player:hover { animation-play-state: paused;}
    #player::after {content: '';position: absolute; width: 12px;height: 12px; background: red;border-radius: 50%;left: 50%;top: 50%; transform: translate(-50%, -50%); }
@keyframes rotate {from {transform: rotate(0);} to {transform: rotate(360deg);}}
.dancer {position: absolute; width:709px;height: 915px;left: -8%;top: 12%;z-index: 3;}
.hidden { display: none; }
.zoom { zoom: 1.2; }
.lz {width: 60px; height: 60px;border-radius: 50%;object-fit: cover; transition: 1.5s; opacity: var(--opacity,.8); background:url('https://www.emojiall.com/images/60/skype/1f496.png') no-repeat center/cover;border-radius: 100%;animation: rot 4s infinite alternate var(--state), opa 8s infinite alternate linear var(--state);z-index: 2; display: var(--display, block); }
@keyframes rot {to {transform: rotate(360deg); }}
.lrc{width: 800px;height: 120px;overflow: hidden;display: block;position: absolute;top:5%; right:-6%;z-index: 3;margin: 0 auto;}
.lrc #ullrc{width: 100%;padding: 0;list-style: none;margin: 0;}
.lrc #ullrc li{height: 70px;line-height: 60px;font-family:华文隶书;font-size: 0px;color: #000078;font-weight: bold;list-style-type: none;text-align: center;display: block;width: 100%;margin: 0 auto;}
.lrc #ullrc li.active{ font-size: 45px;text-align: center; color: transparent; background: repeating-linear-gradient(to right, gold, lightgreen) 50%/100px 80px; -webkit-background-clip: text;filter:drop-shadow(#000 1px 0 0)drop-shadow(#000 0 1px 0)drop-shadow(#000 -1px 0 0) drop-shadow(#000 0 -1px0);
}
#fullscreen { position: absolute; top: 30px;left: 30px; font: normal 1.5em 楷体; color: #fff; text-shadow: 0 0 3px #000; opacity: 1; cursor: pointer; user-select: none; z-index: 8; }
    #fullscreen:hover { font-style: italic; }
#jzg{width: 100%; height:80%;position:absolute;z-index: 2;left: 0%;top:0%; -webkit-mask-image: linear-gradient(to bottom, black 20%, transparent 50%);mask-image: linear-gradient(to bottom, black 20%, transparent 50%);}
#jzg img { width: 100%; height: 100%; }         
   #vid1 {position: absolute; width: 466px; height: 288px; right: 6%; top: 5%;object-fit: cover; border: 2px solid #ccc; box-shadow: 2px 2px 8px rgba(0, 0, 0, 0.3) inset; border-radius: 50%; overflow: hidden; pointer-events: none; display: var(--display); transition: .7s;opacity: .98;mix-blend-mode: darken;animation: opa 12s infinite alternate linear var(--state);z-index: 2;}
@keyframes opa {to {opacity: 0;}}
#vid2 { position: absolute; top:-10%; left: 0; width: 100%; height:120%; object-fit: cover; pointer-events: none; opacity:.9; mask:linear-gradient(to bottom,red 0%,transparent 80%,transparent);-webkit-mask:linear-gradient(to bottom,red 0%,transparent 80%,transparent); z-index: 1; }
</style>
<div id="pa" class="pa">
    <div class="dancer hidden"></div>
    <img class="dancer" src="https://bbs.cnzv.cc/up/upload/pic/62/20251102-83a9c318bf1d7510bdcae2eea7b0e678.png" alt="" />
    <div id="player"></div>
    <div class="lrc">
      <ul id="ullrc"></ul>
    </div>
    <span id="fullscreen">全屏欣赏</span>
    <audio id="aud" src="https://upfile.mp3.wf/view.php/cc0492a0ae64f6f1e788cc01254367de.mp3" autoplay loop></audio>
    <video id="vid1" src="https://vd9.bdstatic.com/mda-rhv3megq0a3gzx78/mb/sc/cae_h264/1756527649294185847/mda-rhv3megq0a3gzx78.mp4" autoplay loop muted></video>
    <meta name="referrer" content="never" />
    <video id="vid2" src="https://img.tukuppt.com/video_show/2418175/00/02/01/5b4f55c95539b.mp4" autoplay loop muted></video>      
    <div id="jzg"><img id="Img" src="https://pic1.imgdb.cn/item/68df520fc5157e1a885256ea.png" alt="" /></div>
</div>
<script type="module">
    import TZ from 'https://638183.freep.cn/638183/web/tz/tz.f.v2.min.js?v2';
    const tz = TZ.TZ('pa');
    tz.lzRan(20, pa, {tag: 'div', className: 'lz', cc: true, delay: -8});
</script>
<script>
var mState = () => {
    const lz = document.querySelectorAll('.lz');
    player.style.setProperty('--state', aud.paused ? 'paused' : 'running');
    player.title = aud.paused ? '播放' : '暂停';
    pa.style.setProperty('--state', aud.paused ? 'paused' : 'running');
    vid1.style.setProperty('--display', aud.paused ? 'none' : 'block');
    lz.forEach(item => {
      item.style.setProperty('--display', aud.paused ? 'none' : 'block');
    });
    aud.paused ? (vid1.pause(), vid2.pause()) : (vid1.play(), vid2.play());
};
aud.oncanplay = aud.onplaying = aud.onpause = () => mState();
const getSize = (str) => {
    const match = str.match(/^([+-]?\d*\.?\d+)(+)$/);
    if (match) return { size: match, unit: match };
    return { size: '0', unit: 'px' };
};
const targetDancer = document.querySelector('.dancer');
let originalSize = null;
function initOriginalSize() {
    if (!targetDancer) return;
    const computedStyle = window.getComputedStyle(targetDancer);
    const widthData = getSize(computedStyle.getPropertyValue('width'));
    const heightData = getSize(computedStyle.getPropertyValue('height'));
    if (parseFloat(widthData.size) === 0 || parseFloat(heightData.size) === 0) {
      originalSize = { width: 709, height: 915, unit: 'px' };
    } else {
      originalSize = {
            width: parseFloat(widthData.size),
            height: parseFloat(heightData.size),
            unit: widthData.unit
      };
    }
    ranZoom(targetDancer);
}
const ranZoom = (element) => {
    if (!originalSize || !element) return;
    const ranpa = (max, min) => (Math.random() * (max - min) + min).toFixed(2);
    const zoom = parseFloat(ranpa(1.2, 0.8));
    const newWidth = Math.ceil(originalSize.width * zoom);
    const newHeight = Math.ceil(originalSize.height * zoom);
    element.style.transition = 'width .5s, height .5s';
    element.style.width = `${newWidth}${originalSize.unit}`;
    element.style.height = `${newHeight}${originalSize.unit}`;
};
if (targetDancer.complete) {
    initOriginalSize();
} else {
    targetDancer.onload = initOriginalSize;
}
window.addEventListener('load', initOriginalSize);
player.onclick = () => {
    aud.paused ? aud.play() : aud.pause();
    if (originalSize && targetDancer) {
      ranZoom(targetDancer);
    }
};
var lrc = `
天际 - 曲尔甲
词:余启翔
曲:绍兵
茫茫草原
散着你的羊群
散着我们曾经的美丽
蓝蓝天空飘着朵朵白云
云在风里你又在哪里
告诉我风儿
为何不见梦里声音
告诉我云儿
怎样才能打开我的心
你是不是那朵飘浮的云
飘在生命的天际
你是不是划过天边的心
划出轮回的身影
你是不是那朵飘浮的云
飘在生命的天际
你是不是划过天边的星
划出轮回的身影
茫茫草原
散着你的羊群
散着我们曾经的美丽
蓝蓝天空
飘着朵朵白云
云在风里你又在哪里
告诉我风儿
为何不见梦里身影
告诉我云儿
怎样才能打开我的心
你是不是那朵飘浮的云
飘在生命的天际
你是不是划过天边的星
划出轮回的身影
你是不是那朵飘浮的云
飘在生命的天际
你是不是划过天边的星
划出轮回的身影
你是不是那朵飘浮的云
飘在生命的天际
你是不是划过天边的星
划出轮回的身影
你是不是那朵飘浮的云
飘在生命的天际
你是不是划过天边的星
划出轮回的身影
`;
function $(id) { return document.getElementById(id); }
function getLrcArray() {
    var parts = lrc.split("\n");
    var validLrc = [];
    for (let index = 0; index < parts.length; index++) {
      const lrcObj = getLrcObj(parts);
      if (lrcObj.words && lrcObj.seconds >= 0) {
            validLrc.push(lrcObj);
      }
    }
    return validLrc;
}
function getLrcObj(content) {
    content = content.trim();
    if (!content || !content.startsWith('[')) return { seconds: -1, words: "" };   
    var timeMatch = content.match(/\[(\d{2}):(\d{2}\.\d{2})\]/);
    if (!timeMatch) return { seconds: -1, words: "" };
   
    var min = parseInt(timeMatch, 10);
    var secWithMs = parseFloat(timeMatch);
    var totalSeconds = min * 60 + secWithMs;   
    var words = content.replace(/\[\d{2}:\d{2}\.\d{2}\]/, "").trim();
    return { seconds: totalSeconds, words: words };
}
var lrcArray = getLrcArray();
function inputLrc() {
    const ullrc = $("ullrc");
    ullrc.innerHTML = "";
    for (let index = 0; index < lrcArray.length; index++) {
      var li = document.createElement("li");
      li.innerText = lrcArray.words;
      ullrc.appendChild(li);
    }
}
inputLrc();
function getLrcIndex() {
    var currentTime = $("aud").currentTime;
    if (currentTime < lrcArray.seconds) return 0;
    for (var index = 0; index < lrcArray.length - 1; index++) {
      const currentLrcSec = lrcArray.seconds;
      const nextLrcSec = lrcArray.seconds;   
      if (currentTime >= currentLrcSec && currentTime < nextLrcSec) {
            return index;
      }
    }
    return lrcArray.length - 1;
}
function setPosition() {
    var index = getLrcIndex();
    const ullrc = $("ullrc");
    const liElements = ullrc.children;
    if (liElements.length === 0) return;

    const lrcLiHeight = 70;
    const lrcContainerHeight = 120;

    const top = index * lrcLiHeight - (lrcContainerHeight - lrcLiHeight) / 2;
    const maxTop = (liElements.length - 1) * lrcLiHeight - (lrcContainerHeight - lrcLiHeight) / 2;
    const finalTop = Math.max(0, Math.min(top, maxTop));
   
    ullrc.style.marginTop = -finalTop + "px";   
    var activeLi = ullrc.querySelector(".active");
    if (activeLi) activeLi.classList.remove("active");
    liElements.classList.add("active");
}
var lrcUpdateTimer = null;
$("aud").ontimeupdate = function() {
    if (!lrcUpdateTimer) {
      lrcUpdateTimer = setTimeout(() => {
            setPosition();
            lrcUpdateTimer = null;
      }, 100);
    }
};
$("aud").onloadedmetadata = function() {
    setPosition();
};
if (targetDancer) {
    ranZoom(targetDancer);
}
let fs = true;
      let fsTimer;
      fullscreen.onclick = () => {
            fs ? (fullscreen.innerText = '退出全屏',pa.requestFullscreen()) : (fullscreen.innerText = '全屏欣赏', document.exitFullscreen());
            fs = !fs;
      };
      pa.addEventListener('mousemove', () => {
            clearTimeout(fsTimer);
            fullscreen.style.opacity = '1';
            fsTimer = setTimeout(() => {
                fullscreen.style.opacity = '0';
            }, 3000);
      });
   document.addEventListener('fullscreenchange', () => {
fs = !document.fullscreenElement;
fullscreen.innerText = fs ? '全屏欣赏' : '退出全屏';
});
</script>

梦江南 发表于 2025-11-4 10:23

画面漂亮,小播中间的颜色变成了红色。
欣赏杨帆的精美制作,学习了!{:4_187:}

未知名 发表于 2025-11-4 11:30

玩得花样翻新,玩得越来越溜了!{:4_199:}

樵歌 发表于 2025-11-4 11:44

不断地有基础上创新,非常漂亮!{:4_178:}

杨帆 发表于 2025-11-4 15:03

梦江南 发表于 2025-11-4 10:23
画面漂亮,小播中间的颜色变成了红色。
欣赏杨帆的精美制作,学习了!

问好江南,谢谢鼓励{:4_204:}

杨帆 发表于 2025-11-4 15:05

未知名 发表于 2025-11-4 11:30
玩得花样翻新,玩得越来越溜了!

谢谢未知名支持与鼓励,祝玩得开心{:4_191:}

杨帆 发表于 2025-11-4 15:22

本帖最后由 杨帆 于 2025-11-4 15:28 编辑

樵歌 发表于 2025-11-4 11:44
不断地有基础上创新,非常漂亮!
问好樵歌管理员,由衷感谢鼓励~{:4_180:}

本帖拟尝试tzMaker与之前发帖模式的融合,进度条bgprog 指令 :tz.bgprog()尚无法加入{:4_173:}

小辣椒 发表于 2025-11-4 22:11

欣赏杨帆的精彩制作,{:4_199:}

小辣椒 发表于 2025-11-4 22:14

小辣椒还是建议用素材最好要高清一点的,像素大一点,全屏欣赏画面会清晰多了

杨帆 发表于 2025-11-4 22:27

小辣椒 发表于 2025-11-4 22:14
小辣椒还是建议用素材最好要高清一点的,像素大一点,全屏欣赏画面会清晰多了

是的,可未找到高像素的合适图片呢,谢谢小辣椒的中肯建议{:4_187:}

红影 发表于 2025-11-4 23:33

元素缩放是指那女子的身影会变化吧?好像点击小播那剪影随机变大变小了。
欣赏杨帆好帖{:4_199:}

杨帆 发表于 2025-11-5 00:03

红影 发表于 2025-11-4 23:33
元素缩放是指那女子的身影会变化吧?好像点击小播那剪影随机变大变小了。
欣赏杨帆好帖


是的。用马老师说的第四个方法:新增的CSS 的 scale 属性,功能实现要便捷一些

偶然~ 发表于 2025-11-17 13:49

来欣赏杨帆的精品佳作,祝您创作如春泉涌流不息!
页: [1]
查看完整版本: 《天际》(学习马老师帖《自定义元素缩放》)