一行行代码编织的温馨祝福 - 从贺卡设计看 JavaScript 的魅力

477 阅读3分钟

前言

节日期间,人们总会被生活中的温暖和幸福所包围。那要如何用代码的形式来传递这份节日祝福为亲朋好友带来惊喜和欣喜呢?文章中,我将与大家分享自己的 JavaScript 贺卡设计经历。让我们一起探索 JavaScript 在节日贺卡设计领域的无限可能,感受科技与艺术的完美融合。

实现

效果展示

可以通过按住鼠标左键打开请帖

image.png

image.png

代码讲解

html

<div class="book p3d">
        <!-- 右半本 -->
        <div class="book-cover p3d">
            <div class="page back flip"></div>
            <div class="page front p3d">
                <div class="shadow"></div>
                <div class="pic"></div>
            </div>
        </div>
        <!-- 左半本 -->
        <div class="front-cover p3d">
            <div class="page front flip p3d">
                <p>
                    亲爱的丁社长和铁锤:

                    恭喜你们迎来人生新的旅程,结婚是爱情的圆满,是幸福的开始。愿你们携手共度人生的每一刻,相互扶持,相互理解,相互包容。

                    在这个特别的日子里,愿你们的爱情如同新婚的阳光一样灿烂,如同甜蜜的蜜蜂一样温暖。愿你们的爱情,如同永恒的星辰,照耀着彼此的人生。

                    愿你们的婚姻充满欢笑与快乐,百年好合,幸福美满!

                    祝福语:
                    丁社长和铁锤,祝你们于2024年5月1日结婚纪念日快乐!

                    祝福你们永结同心,白头偕老!
                </p>
            </div>
            <!-- 外壳 -->
            <div class="page back"></div>
        </div>
    </div>
  1. 最外层是一个 <div> 元素,类名为 book p3d,表示这是一个书本元素,具有 3D 效果。

  2. 右半部分是书本的封面,由 <div class="book-cover p3d"> 包裹,其中包含:

    • 背面的页面 <div class="page back flip">
    • 正面的页面 <div class="page front p3d">
  3. 左半部分是书本正文内容,由 <div class="front-cover p3d"> 包裹,其中包含:

    • 正面的页面 <div class="page front flip p3d">
    • 页面内容为一段祝福语
    • 背面的页面 <div class="page back">
  4. 整个书本效果通过 CSS 属性 p3d 来实现 3D 效果,包括页面翻转、阴影等。

js

<script>
        var hold = false
        var frontCover = document.querySelector('.front-cover')
        var shadow = document.querySelector('.shadow')
        var pic = document.querySelector('.pic')
        var clamp = function (val, min, max) {
            return Math.max(min, Math.min(val, max))
        }
        //鼠标摁住事件
        //摁住为ture
        frontCover.onmousedown = function () {
            hold = true
        }
        //摁住为false
        window.onmouseup = function () {
            hold = false
        }
        //鼠标移动事件
        window.onmousemove = function (e) {
            //摁住才能执行
            if (hold == true) {
                var angle = clamp((window.innerWidth / 2 - e.pageX + 300) / 300 * -90, -180, 0)

                frontCover.style.transform = `rotateY(${angle}deg)`
                //pic 要立起来 绕x轴旋转(angle/2)
                pic.style.transform = `rotateX(${angle / 2}deg)`
                //shadow 要沿x轴倾斜(angle/8)
                shadow.style.transform = `skewX(${angle / 8}deg)`
            }

        }
    </script>
  1. 定义了几个全局变量:

    • hold: 标记鼠标是否按下的状态
    • frontCover: 左半部分书本封面的DOM元素
    • shadow: 页面阴影效果的DOM元素
    • pic: 页面图片效果的DOM元素
  2. 定义了一个clamp函数,用于将输入值限制在指定的范围内。

  3. 监听了frontCover元素的mousedown事件,当鼠标按下时将hold标记设为true

  4. 监听了windowmouseup事件,当鼠标松开时将hold标记设为false

  5. 监听了windowmousemove事件,当鼠标移动且hold标记为true时,执行以下操作:

    • 计算出页面左半部分书本封面的旋转角度angle,范围为-1800度。角度的计算公式是根据鼠标在水平方向上的位置来确定。
    • 将计算出的角度应用到frontCover元素的transform属性上,实现3D翻转效果。
    • 根据angle的值,计算出pic元素的旋转角度和shadow元素的倾斜角度,并应用到相应的transform属性上,实现3D效果。

总结

本文介绍了如何用html、css、js去写一个富有互动性和个性化的电子贺卡,对于前端新手或者有兴趣学习JavaScript的同学来说,这是一个很好的入门练习项目,大家可以拿来练练手咯。

完整代码

html + js

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="style.css">
</head>

<body>
    <div class="book p3d">
        <!-- 右半本 -->
        <div class="book-cover p3d">
            <div class="page back flip"></div>
            <div class="page front p3d">
                <div class="shadow"></div>
                <div class="pic"></div>
            </div>
        </div>
        <!-- 左半本 -->
        <div class="front-cover p3d">
            <div class="page front flip p3d">
                <p>
                    亲爱的丁社长和铁锤:

                    恭喜你们迎来人生新的旅程,结婚是爱情的圆满,是幸福的开始。愿你们携手共度人生的每一刻,相互扶持,相互理解,相互包容。

                    在这个特别的日子里,愿你们的爱情如同新婚的阳光一样灿烂,如同甜蜜的蜜蜂一样温暖。愿你们的爱情,如同永恒的星辰,照耀着彼此的人生。

                    愿你们的婚姻充满欢笑与快乐,百年好合,幸福美满!

                    祝福语:
                    丁社长和铁锤,祝你们于2024年5月1日结婚纪念日快乐!

                    祝福你们永结同心,白头偕老!
                </p>
            </div>
            <!-- 外壳 -->
            <div class="page back"></div>
        </div>
    </div>

    <script>
        var hold = false
        var frontCover = document.querySelector('.front-cover')
        var shadow = document.querySelector('.shadow')
        var pic = document.querySelector('.pic')
        var clamp = function (val, min, max) {
            return Math.max(min, Math.min(val, max))
        }
        //鼠标摁住事件
        //摁住为ture
        frontCover.onmousedown = function () {
            hold = true
        }
        //摁住为false
        window.onmouseup = function () {
            hold = false
        }
        //鼠标移动事件
        window.onmousemove = function (e) {
            //摁住才能执行
            if (hold == true) {
                var angle = clamp((window.innerWidth / 2 - e.pageX + 300) / 300 * -90, -180, 0)

                frontCover.style.transform = `rotateY(${angle}deg)`
                //pic 要立起来 绕x轴旋转(angle/2)
                pic.style.transform = `rotateX(${angle / 2}deg)`
                //shadow 要沿x轴倾斜(angle/8)
                shadow.style.transform = `skewX(${angle / 8}deg)`
            }

        }
    </script>
</body>

</html>

css

* {
    margin: 0;
    padding: 0;
    border: 0;
    box-sizing: border-box;
}

html {
    height: 100%;
}

body {
    height: 100%;
    font: 100%/1.25 Helvetica, arial, helvetica;
    color: #fff;
    perspective: 1000px;
    background: linear-gradient(to bottom, #444, #999);
}

.book {
    width: 300px;
    height: 300px;
    position: absolute;
    left: 50%;
    margin-left: -150px;
    top: 50%;
    margin-top: -150px;
    cursor: pointer;
    user-select: none;
    transform: rotateX(60deg);
}

.page {
    width: 300px;
    height: 300px;
    padding: 1em;
    position: absolute;
    left: 0;
    top: 0;
    text-indent: 2em;
}

.front {
    background-color: #d93e2b;

}

.back {
    background-color: #fff;

}

.front-cover {
    transform-origin: 0 50%;
    transform: rotateY(0deg);

}

.p3d {
    transform-style: preserve-3d;
}

.front-cover .back {
    background-image: url(https://img2.baidu.com/it/u=2368431681,4265369131&fm=253&fmt=auto&app=138&f=JPEG?w=595&h=500);
    background-size: cover;
    transform: translateZ(3px);
}

.flip {
    transform: rotateY(180deg);
}

.shadow,
.pic {
    width: 196px;
    height: 132px;
    position: absolute;
    left: 60px;
    top: 60px;
    transform-origin: 0 100%;
}

.pic {
    background: url(https://foruda.gitee.com/avatar/1692538461019758393/12761759_c_shunyi_1692538460.png!avatar200);
    background-size: cover;
    background-position: center;

}

.shadow {
    background-color: rgba(0, 0, 0, 0.5);
}