哇咔咔,用js一镜到底来期盼除夕(放假)

PK创意闹新春,我正在参加「春节创意投稿大赛」,详情请看:春节创意投稿大赛

介绍

网页中的一镜到底,通常是指在页面中通过模仿镜头的拉伸,使得不同的画面元素陆续呈现在观众眼前的一种表现方式。因为其呈现效果与影视中的一镜到底十分相似,所以被称为“一镜到底”。

春节将至,我们本期就用svg+js来做一个一镜到底的网页特效,来等待我们心心念念的除夕夜吧。

当然我们先来康康效果吧:

VID_20220116_202540.gif

正文

1.HTML结构

<div id="app">
    <h1>
        <div>
            <p>距离除夕</p>
            <p>还有<span id="day">0</span></p>
        </div>
    </h1> 

    <div class="tiger">
        <svg class="tiger-icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2653"
            width="32" height="32">
            <!-- 拷贝 路径 -->
            <!--<path class="tiger-mask" d="..."></path>-->
            <!-- 拷贝 路径 -->
        </svg>
    </div>

    <video src="./assets/video.a1577323.mp4" loop autoplay muted playsinline></video>

    <h2>
        <div>
            <p></p>
            <p></p>
            <p></p>
            <p></p>
        </div>
    </h2>
</div>
复制代码

我们这里期望是做四个全屏的场景:

  • 场景一:提示距离除夕的天数,如果过了除夕我们就会在js里改成别的话术,不显示天数了。

  • 场景二:要找一个svg老虎图标复制代码到这里面,因为其路径实在太长这里注释了起来。

微信截图_20220116204546.png

  • 场景三:要找个喜气点的视频放进去,记住里面一定要放入loop autoplay muted playsinline这四个属性,会让其自动静音的循环播放。

  • 场景四:我们可以看到放了四个空的p标签,其实会在最后随机出四句祝福语送给大家,至于内容后面js逻辑中会看到。

2.css样式

html,
body {
    width: 100%;
    height: 6666px;
    position: relative;
}

#app {
    width: 100%;
    position: sticky;
    top: 0;
    width: 100%;
    height: 100vh;
    overflow: hidden;
}

video {
    width: 100%;
    height: 100%;
    position: absolute;
    object-fit: cover;
    left: 0;
    top: 0;
}

.tiger {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 20vh;
    height: 20vh;
    min-width: 20vh;
    min-height: 20vh;
    box-shadow: 0px 0px 0px 100vw rgb(170, 0, 0), 0px 0px 0px 50px rgb(170, 0, 0) inset;
    z-index: 10;
    background-color: rgb(170, 0, 0);

}

.tiger.transparent {
    background-color: transparent;
}

.tiger-icon {
    position: absolute;
    width: 100%;
    height: 100%;
    opacity: 0;
}

.tiger-line,.tiger-mask {
    fill: rgb(247, 191, 39)
}

h1,
h2 {
    position: absolute;
    width: 100%;
    height: 100vh;
    font-size: 11vh;
    color: rgb(247, 191, 39);
    position: absolute;
    font-family: 'fangsong', Arial, sans-serif;
    font-weight: bold;
    letter-spacing: 1vh;
    line-height: 20vh;
    top: 0;
    left: 0;
    z-index: 99;
    display: flex;
    align-items: center;
    justify-content: center;
    text-shadow: 2px 1px 15px rgb(247, 191, 39);
}

h1>div,
h2>div {
    text-align: center;
}

h2 {
    background-image: repeating-radial-gradient(circle at center center, transparent 0px, transparent 8px,
        rgba(255, 255, 255, 0.05) 8px, rgba(255, 255, 255, 0.05) 11px, transparent 11px, transparent 17px,
        rgba(255, 255, 255, 0.05) 17px, rgba(255, 255, 255, 0.05) 25px, transparent 25px, transparent 38px,
        rgba(255, 255, 255, 0.05) 38px, rgba(255, 255, 255, 0.05) 42px),
        repeating-radial-gradient(circle at center center, rgb(170, 0, 0) 0px, rgb(170, 0, 0) 11px, rgb(170, 0, 0) 11px, rgb(170, 0, 0) 19px, rgb(170, 0, 0) 19px, rgb(170, 0, 0) 24px, rgb(170, 0, 0) 24px, rgb(170, 0, 0) 33px, rgb(170, 0, 0) 33px, rgb(170, 0, 0) 44px, rgb(170, 0, 0) 44px, rgb(170, 0, 0) 46px);
    background-size: 60px 60px;
    opacity: 0;
    line-height: 15vh;
}

h2 p {
    height: 15vh;
    transition: .3s all;
}
复制代码

css里面主要注意的地方有:

  • body要加一个超大的高度,我这里随便写了个6666px,就图个吉利。
  • div#app,我们要用position: sticky,让其一直吸顶,来保证场景一直贴合屏幕。
  • 其他的那四个场景都是全屏的。
  • div.tiger用box-shadow去覆盖漏出来的场景空隙。

微信截图_20220116205511.png

3.基本逻辑

let wordList = [
    "新春快乐 福寿安康 岁岁平安 年年有余",
    "财源广进 合家欢乐 飞黄腾达 万事顺意",
    "财源广进 幸福美满 财运亨通 美梦连连",
    "恭贺春节 财源广进 恭贺新喜 财运亨通",
    "合家欢乐 飞黄腾达 万事顺意 幸福美满",
    "心想事成 五福临门 五谷丰登 迎春接福",
    "吉星高照 吉祥如意 开春大吉 五谷丰登",
    "新年快乐 学业有成 福星高照 万事如意",
    "福星高照 恭贺新春 吉庆有余 福享新春",
    "万物回春 天开化宇 人在春台 一门瑞气"
]

let $day = document.getElementById("day")
let $h1 = document.querySelector("h1")
let $h2 = document.querySelector("h2")
let $TigerSvg = document.querySelector(".tiger-icon")
let $Tiger = document.querySelector('.tiger')
let $TigerMask = document.querySelectorAll('.tiger-mask')
let $plist = $h2.querySelectorAll("p")
let word = "";
复制代码

我们先来定义这些参数吧:

  • wordList就是底下要显示的祝福语,从这10个字符串中选出一个赋值到word里面,保证每次打开都是不同的。
  • 剩下的都是直接获取元素,避免后面反复操作了。

接下来,我们初始化一下:

function init() {
    let now = new Date();
    let cx = new Date("2022-1-31");
    word = wordList[~~(Math.random() * wordList.length)].split(" ");
    $plist.forEach((p, i) => p.innerText = word[i])
    if (now > cx) {
        $h1.querySelectorAll("p").forEach((p, i) => p.innerText = ["新年快乐", "虎年大吉"][i])
        return;
    }
    let d = Math.max(0, ~~((cx - now) / 1000 / 86400));
    $day.innerText = d;
}
init()
复制代码

初始化方法里,我们计算了距离除夕的时间,并且随机到了祝福语言生成字符串添加到了界面中。

微信截图_20220116212045.png

准备工作全做完了,可以怎样让其替换不同场景呢,注意,注意,重点来了,敲小黑板了~

window.addEventListener("scroll", e => {
    let scrolled = document.documentElement.scrollTop / (document.documentElement.scrollHeight - document.documentElement.clientHeight)
})
复制代码

这句就是我们要监听scroll方法,然后计算scrolled,意思就是我每次滚动,都要算出我当前滚动条的距离占可用高度的比值,这样就可以得到当前滚动到页面的百分之多少了,换句话说就是进度值。我们后面在根据这个进度值再滚动实时改变其场景内容的不同属性就可以完成一镜到底的效果。

window.addEventListener("scroll", e => {
    let scrolled = document.documentElement.scrollTop / (document.documentElement.scrollHeight - document.documentElement.clientHeight)
    $Tiger.style.width = $Tiger.style.height = document.documentElement.clientWidth * 36 * (scrolled * scrolled * scrolled) + 'px'
    if (scrolled <= 0.1) {
        $h1.style.opacity = (0.1 - scrolled) * 10
        $h1.style.marginTop = scrolled * 1000 * -1 + 'px'
    } else {
        $h1.style.opacity = 0
    }
    if (scrolled <= 0.2) {
        $TigerSvg.style.opacity = (scrolled - 0.1) * 10
    } else {
        $TigerSvg.style.opacity = 1
    }
    if (scrolled >= 0.36) {
        $TigerMask.forEach(n => n.style.opacity = (1 - scrolled) * 1.5);
        $Tiger.classList.add('transparent')
    } else {
        $TigerMask.forEach(n => n.style.opacity = 1);
        $Tiger.classList.remove('transparent')
    }
    if (scrolled >= 0.6) {
        let limit = ~~((scrolled - 0.75) * 100 / 5)
        $plist.forEach((p, i) => {
            p.style.opacity = limit >= i ? 1 : 0;
            p.style.transform = limit >= i ? "scale(1)" : "scale(3)"
        })
        $h2.style.opacity = (scrolled - 0.5) * 2;
    }
    else {
        $plist.forEach((p, i) => {
            p.style.opacity = 0;
            p.style.transform = "scale(3)"
        })
        $h2.style.opacity = 0;
    }
})
复制代码

处理当前的业务逻辑就只有那么多,可以看出我们通过scrolled进度值在不同阶段对其里面的内容做出了不同操作。比如不停的改变透明度,或者marginTop等等。这里就不再一一赘述了。

VID_20220116_202540.gif

结语

本次其实仅仅写了四个场景,因为是纯js完成,所以业务量还是挺大的,我们如果后面要做很大很多效果,也可以用gsap里用时间线去完成,会节省很多的业务处理,而且更加清晰。总之,核心的实现还是很简单的,就是计算你当前的进度值,来不停改变状态,有机会可以试试很好玩的。

最后,祝大家虎年大吉大利,来年要大显身手,虎气冲天!

おすすめ

転載: juejin.im/post/7053967485783146509