anime.js实现一个天气动画

在这里插入图片描述
有点累,不想说太多,以下是几个关键点,有兴趣自己看代码吧。

  • 月亮是用工具画的,svg格式
  • 太阳是用css代码写的
  • 每一颗雨滴都是一个单独的动画
  • 闪电是png图片,仔细看会有点锯齿
  • 大雨和小雨的切换是通过控制雨滴的v-show
  • 动画部分的代码有点乱,自己练习用的,不想整理
  • 山峰是用工具画的svg图,方便控制其颜色动画
  • 用vue实现起来简单太多了,推荐使用

参考代码 链接

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        body {
            display: flex;
            justify-content: center;
        }

        .container {
            position: relative;
            width: 300px;
            height: 400px;
            background-color: #171c2b;
            overflow: hidden;
        }

        .bigWater,
        .mediumWater,
        .smallWater {
            position: absolute;
            top: -10px;
            border-radius: 50%;
        }

        .bigWater::after,
        .mediumWater::after,
        .smallWater::after {
            content: "";
            position: absolute;
            top: -3px;
            left: 2px;
            border-radius: 50%;
        }

        .bigWater {
            height: 10px;
            width: 10px;
            background-color: #7fc1f9;
        }

        .bigWater::after {
            height: 7px;
            width: 7px;
            background-color: #7fc1f9;
        }

        .mediumWater {
            height: 8px;
            width: 8px;
            background-color: #8ec3f1;
        }

        .mediumWater::after {
            height: 5px;
            width: 5px;
            background-color: #8ec3f1;
        }

        .smallWater {
            height: 5px;
            width: 5px;
            background-color: #98bbda;
        }

        .smallWater::after {
            height: 3px;
            width: 3px;
            background-color: #98bbda;
        }

        .moon {
            position: absolute;
            left: -80px;
            bottom: 70px;
        }

        .fil0 {
            fill: #FFF8C7
        }

        .fil1 {
            fill: #EDE7B6
        }

        .fil2 {
            fill: #0f2850
        }

        .fil3 {
            fill: #173563
        }

        .fil4 {
            fill: #0f2850
        }

        .lightning {
            position: absolute;
            right: -3px;
            top: -3px;
            opacity: 0;
        }
        .moutain {
            position: absolute;
            bottom: -40px;
        }

        .sun {
            position: absolute;
            width: 71px;
            height: 71px;
            border-radius: 50%;
            right: -80px;
            bottom: 70px;
            background-color: #ffb9a1;
            box-shadow: 0 0 30px 0 #ffffff;
        }
    </style>
</head>

<body>
    <div id="app">
        <div class="container">

            <svg class="moon" width="75px" height="75px" version="1.1" viewBox="0 0 75 75">
                <g>
                    <circle class="fil0" cx="37" cy="38" r="35" />
                    <circle class="fil1" cx="27" cy="14" r="2" />
                    <ellipse class="fil1" cx="49" cy="16" rx="5" ry="4" />
                    <circle class="fil1" cx="43" cy="38" r="7" />
                    <circle class="fil1" cx="63" cy="43" r="3" />
                    <ellipse class="fil1" cx="37" cy="68" rx="5" ry="4" />
                    <circle class="fil1" cx="23" cy="45" r="3" />
                    <circle class="fil1" transform="matrix(0.460443 -0.887689 0.718639 0.372757 12.5924 28.1206)"
                        r="5" />
                </g>
            </svg>

            <div class="sun"></div>

            <img src="./lightning.png" class="lightning" alt="">

            <svg class="moutain" width="300px" height="400px" viewBox="0 0 300 400">
                <g>
                    <path class="fil2"
                        d="M-97 370c21,-25 57,-71 85,-94 28,-23 48,-24 67,-11 19,13 38,40 54,65 16,25 30,50 37,62 7,12 7,12 -40,12 -47,0 -141,-1 -186,-3 -44,-2 -38,-6 -17,-31z" />
                    <path class="fil3"
                        d="M36 369c16,-19 44,-54 65,-72 21,-18 37,-18 52,-8 15,10 29,31 42,50 13,20 23,38 28,48 5,9 5,9 -31,9 -36,0 -109,-1 -143,-2 -34,-2 -29,-5 -13,-24z" />
                    <path class="fil4"
                        d="M186 319c27,-26 52,-45 69,-57 17,-11 26,-14 37,-9 11,5 25,19 44,44 19,24 44,59 57,80 14,21 16,27 -2,32 -18,4 -56,7 -98,7 -42,0 -87,-2 -115,-3 -28,-1 -40,-2 -49,-2 -10,-1 -18,-2 -8,-18 10,-16 38,-48 65,-73z" />
                </g>
            </svg>

            <div v-for="(item,i) in bigArr" :key="i" v-show="item.show" :style="{left: item.left+'px'}" :class="[bigWater, item.class]"></div>
            <div v-for="(item,i) in mediumArr" :key="i" v-show="item.show" :style="{left: item.left+'px'}" :class="[mediumWater, item.class]"></div>
            <div v-for="(item,i) in smallArr" :key="i" v-show="item.show" :style="{left: item.left+'px'}" :class="[smallWater, item.class]"></div>
        </div>
        <button @click="onLightning">闪电</button>
        <button @click="onBigRain">大雨</button>
        <button @click="onSmallRain">小雨</button>
        <button @click="onSunny">晴天</button>
    </div>
</body>
<!-- 2.6.x版 -->
<script src="./vue.min.js"></script>
<!-- 3.1.x版 -->
<script src="./anime.min.js"></script>
<script>
    var app = new Vue({
        el: '#app',
        data: {
            state: 'rain',
            bigWater: 'bigWater',
            mediumWater: 'mediumWater',
            smallWater: 'smallWater',
            bigAmount: 10,          // 大雨滴数量
            mediumAmount: 20,      // 中雨滴数量
            smallAmount: 30,       // 小雨滴数量
            bigArr: [],
            mediumArr: [],
            smallArr: []
        },
        created() {
            this.generateData()
        },
        mounted() {
            this.startAnimeWater()
            setTimeout(() => {
                this.animeMoon()
            }, 500);
        },
        methods: {
            generateData() {
                for (let i = 1; i < this.bigAmount; i++) {
                    let obj = {
                        class: `bigWater${i}`,
                        show: true,
                        left: anime.random(30, 280),
                        delay: anime.random(0, 1000) //值越大,雨滴越分散
                    }
                    this.bigArr.push(obj)
                }
                for (let i = 1; i < this.mediumAmount; i++) {
                    let obj = {
                        class: `mediumWater${i}`,
                        show: true,
                        left: anime.random(30, 300),
                        delay: anime.random(0, 1000)
                    }
                    this.mediumArr.push(obj)
                }
                for (let i = 1; i < this.smallAmount; i++) {
                    let obj = {
                        class: `smallWater${i}`,
                        show: true,
                        left: anime.random(10, 320),
                        delay: anime.random(0, 2000)
                    }
                    this.smallArr.push(obj)
                }
            },
            startAnimeWater() {
                const keyframeBig = [
                    {
                        translateX: -40, //相对值
                        translateY: 400,
                        duration: 750,   //下落速度
                    },
                    {
                        scaleX: 3,
                        duration: 100,
                    },
                ]
                this.animeWater(this.bigArr, keyframeBig)
                const keyframeMedium = [
                    {
                        translateX: -40,
                        translateY: 400,
                        duration: 1300,
                    }
                ]
                this.animeWater(this.mediumArr, keyframeMedium)
                const keyframeSmall = [
                    {
                        translateX: -40,
                        translateY: 400,
                        duration: 2000,
                    }
                ]
                this.animeWater(this.smallArr, keyframeSmall)
            },
            animeWater(arr, keyframes) {
                for (let i = 0; i < arr.length; i++) {
                    anime({
                        targets: `.${arr[i].class}`,
                        keyframes: keyframes,
                        delay: arr[i].delay,
                        easing: 'linear',
                        loop: true
                    })
                }
            },
            animeMoon() {
                anime({
                    targets: '.moon',
                    translateX: 120,
                    translateY: -230,
                    duration: 800,
                    easing: 'linear'
                })
            },
            onLightning() {
                if (this.state === 'sunny') {
                    return
                }
                anime({
                    targets: '.lightning',
                    keyframes: [
                        {
                            opacity: 1,
                            duration: 300,
                        }, {
                            opacity: 0,
                            duration: 500,
                        }
                    ]
                })
                anime({
                    targets: '.container',
                    keyframes: [
                        {
                            backgroundColor: '#fff',
                            delay: 200,
                            easing: 'spring(50, 100, 50, 0)'
                        }, {
                            backgroundColor: '#1a2238',
                            duration: 1000,
                        }
                    ]
                })
                anime({
                    targets: '.moutain',
                    keyframes: [
                        {
                            opacity: 0.3,
                            delay: 300,
                            duration: 1000,
                        }, {
                            opacity: 1,
                            duration: 1000,
                        }
                    ]
                })
            },
            onBigRain() {
                if (this.state === 'sunny') {
                    this.state = 'rain'
                    anime({
                        targets: '.container',
                        backgroundColor: '#171c2b',
                        duration: 1500,
                        easing: 'linear'
                    })
                    anime({
                        targets: '.sun',
                        translateX: 120,
                        translateY: 230,
                        duration: 1000,
                        easing: 'linear'
                    })
                    anime({
                        targets: '.fil2',
                        fill: '#0f2850',
                        duration: 1500,
                        easing: 'linear'
                    })
                    anime({
                        targets: '.fil3',
                        fill: '#173563',
                        duration: 1500,
                        easing: 'linear'
                    })
                    anime({
                        targets: '.fil4',
                        fill: '#0f2850',
                        duration: 1500,
                        easing: 'linear'
                    })
                    this.animeMoon()
                }
                this.bigArr.forEach((v,i) => {
                    v.show = true
                })
                this.mediumArr.forEach((v,i) => {
                    v.show = true
                })
                this.smallArr.forEach((v,i) => {
                    v.show = true
                })
            },
            onSmallRain() {
                this.bigArr.forEach((v,i) => {
                    if (i % 2 === 0) {
                        v.show = false
                    }
                })
                this.mediumArr.forEach((v,i) => {
                    if (i % 2 === 0) {
                        v.show = false
                    }
                })
                this.smallArr.forEach((v,i) => {
                    if (i % 2 === 0) {
                        v.show = false
                    }
                })
            },
            onSunny() {
                this.state = 'sunny'
                this.bigArr.forEach((v,i) => {
                    v.show = false
                })
                this.mediumArr.forEach((v,i) => {
                    v.show = false
                })
                this.smallArr.forEach((v,i) => {
                    v.show = false
                })
                anime({
                    targets: '.container',
                    backgroundColor: '#fdf8d4',
                    duration: 1500,
                    easing: 'linear'
                })
                anime({
                    targets: '.fil2',
                    fill: '#6da75c',
                    duration: 1500,
                    easing: 'linear'
                })
                anime({
                    targets: '.fil3',
                    fill: '#4cb52e',
                    duration: 1500,
                    easing: 'linear'
                })
                anime({
                    targets: '.fil4',
                    fill: '#4f8d3d',
                    duration: 1500,
                    easing: 'linear'
                })
                anime({
                    targets: '.moon',
                    translateX: -120,
                    translateY: 230,
                    duration: 1000,
                    easing: 'linear'
                })
                anime({
                    targets: '.sun',
                    translateX: -120,
                    translateY: -230,
                    duration: 1000,
                    easing: 'linear'
                })
                // keyframe不支持loop,只能播放一遍
                anime({
                    targets: '.sun',
                    backgroundColor: '#fffc4b',
                    loop: true,
                    duration: 2000,
                    delay: 1000,
                    direction: 'alternate',
                    easing: 'linear'
                })
            }

        }
    })
</script>

</html>

热门文章

暂无图片
编程学习 ·

C语言二分查找详解

二分查找是一种知名度很高的查找算法&#xff0c;在对有序数列进行查找时效率远高于传统的顺序查找。 下面这张动图对比了二者的效率差距。 二分查找的基本思想就是通过把目标数和当前数列的中间数进行比较&#xff0c;从而确定目标数是在中间数的左边还是右边&#xff0c;将查…
暂无图片
编程学习 ·

GMX 命令分类列表

建模和计算操作命令&#xff1a; 1.1 . 创建拓扑与坐标文件 gmx editconf - 编辑模拟盒子以及写入子组(subgroups) gmx protonate - 结构质子化 gmx x2top - 根据坐标生成原始拓扑文件 gmx solvate - 体系溶剂化 gmx insert-molecules - 将分子插入已有空位 gmx genconf - 增加…
暂无图片
编程学习 ·

一文高效回顾研究生课程《数值分析》重点

数值分析这门课的本质就是用离散的已知点去估计整体&#xff0c;就是由黑盒子产生的结果去估计这个黑盒子。在数学里这个黑盒子就是一个函数嘛&#xff0c;这门课会介绍许多方法去利用离散点最大化地逼近这个函数&#xff0c;甚至它的导数、积分&#xff0c;甚至微分方程的解。…
暂无图片
编程学习 ·

在职阿里5年,一个28岁女软测工程师的心声

简单的先说一下&#xff0c;坐标杭州&#xff0c;14届本科毕业&#xff0c;算上年前在阿里巴巴的面试&#xff0c;一共有面试了有6家公司&#xff08;因为不想请假&#xff0c;因此只是每个晚上去其他公司面试&#xff0c;所以面试的公司比较少&#xff09; ​ 编辑切换为居中…
暂无图片
编程学习 ·

字符串左旋c语言

目录 题目&#xff1a; 解题思路&#xff1a; 第一步&#xff1a; 第二步&#xff1a; 第三步&#xff1a; 总代码&#xff1a; 题目&#xff1a; 实现一个函数&#xff0c;可以左旋字符串中的k个字符。 例如&#xff1a; ABCD左旋一个字符得到BCDA ABCD左旋两个字符…
暂无图片
编程学习 ·

设计模式--观察者模式笔记

模式的定义与特点 观察者&#xff08;Observer&#xff09;模式的定义&#xff1a;指多个对象间存在一对多的依赖关系&#xff0c;当一个对象的状态发生改变时&#xff0c;所有依赖于它的对象都得到通知并被自动更新。这种模式有时又称作发布-订阅模式、模型-视图模式&#xf…
暂无图片
编程学习 ·

睡觉突然身体动不了,什么是睡眠痽痪症

很多朋友可能有这样的体验&#xff0c;睡觉过程中突然意识清醒&#xff0c;身体却动弹不了。这时候感觉非常恐怖&#xff0c;希望旁边有一个人推自己一下。阳光以前也经常会碰到这样的情况&#xff0c;一年有一百多次&#xff0c;那时候很害怕晚上到来&#xff0c;睡觉了就会出…
暂无图片
编程学习 ·

深入理解C++智能指针——浅析MSVC源码

文章目录unique_ptrshared_ptr 与 weak_ptrstd::bad_weak_ptr 异常std::enable_shared_from_thisunique_ptr unique_ptr 是一个只移型别&#xff08;move-only type&#xff0c;只移型别还有std::mutex等&#xff09;。 结合一下工厂模式&#xff0c;看看其基本用法&#xff…
暂无图片
编程学习 ·

@TableField(exist = false)

TableField(exist false) //申明此字段不在数据库存在&#xff0c;但代码中需要用到它&#xff0c;通知Mybatis-plus在做写库操作是忽略它。,.
暂无图片
编程学习 ·

Java Web day15

第十二章文件上传和下载 一、如何实现文件上传 要实现Web开发中的文件上传功能&#xff0c;通常需要完成两步操作&#xff1a;一.是在Web页面中添加上传输入项&#xff1b;二是在Servlet中读取上传文件的数据&#xff0c;并保存到本地硬盘中。 需要使用一个Apache组织提供一个…
暂无图片
编程学习 ·

【51nod 2478】【单调栈】【前缀和】小b接水

小b接水题目解题思路Code51nod 2478 小b接水 题目 输入样例 12 0 1 0 2 1 0 1 3 2 1 2 1输出样例 6解题思路 可以发现最后能拦住水的都是向两边递减高度&#xff08;&#xff1f;&#xff09; 不管两个高积木之间的的积木是怎样乱七八糟的高度&#xff0c;最后能用来装水的…
暂无图片
编程学习 ·

花了大半天写了一个UVC扩展单元调试工具

基于DIRECTSHOW 实现的&#xff0c;用的是MFC VS2019. 详见&#xff1a;http://www.usbzh.com/article/detail-761.html 获取方法 加QQ群:952873936&#xff0c;然后在群文件\USB调试工具&测试软件\UVCXU-V1.0(UVC扩展单元调试工具-USB中文网官方版).exe USB中文网 USB中文…
暂无图片
编程学习 ·

贪心(一):区间问题、Huffman树

区间问题 例题一&#xff1a;区间选点 给定 N 个闭区间 [ai,bi]请你在数轴上选择尽量少的点&#xff0c;使得每个区间内至少包含一个选出的点。 输出选择的点的最小数量。 位于区间端点上的点也算作区间内。 输入格式 第一行包含整数 N&#xff0c;表示区间数。 接下来 …
暂无图片
编程学习 ·

C语言练习实例——费氏数列

目录 题目 解法 输出结果 题目 Fibonacci为1200年代的欧洲数学家&#xff0c;在他的着作中曾经提到&#xff1a;「若有一只免子每个月生一只小免子&#xff0c;一个月后小免子也开始生产。起初只有一只免子&#xff0c;一个月后就有两只免子&#xff0c;二个月后有三只免子…
暂无图片
编程学习 ·

Android开发(2): Android 资源

个人笔记整理 Android 资源 Android中的资源&#xff0c;一般分为两类&#xff1a; 系统内置资源&#xff1a;Android SDK中所提供的已经定义好的资源&#xff0c;用户可以直接拿来使用。 用户自定义资源&#xff1a;用户自己定义或引入的&#xff0c;只适用于当前应用的资源…
暂无图片
编程学习 ·

零基础如何在短时间内拿到算法offer

​算法工程师是利用算法处理事物的职业 算法&#xff08;Algorithm&#xff09;是一系列解决问题的清晰指令&#xff0c;也就是说&#xff0c;能够对一定规范的输入&#xff0c;在有限时间内获得所要求的输出。 如果一个算法有缺陷&#xff0c;或不适合于某个问题&#xff0c;执…
暂无图片
编程学习 ·

人工智能:知识图谱实战总结

人工智能python&#xff0c;NLP&#xff0c;知识图谱&#xff0c;机器学习&#xff0c;深度学习人工智能&#xff1a;知识图谱实战前言一、实体建模工具Protegepython&#xff0c;NLP&#xff0c;知识图谱&#xff0c;机器学习&#xff0c;深度学习 人工智能&#xff1a;知识图…
暂无图片
编程学习 ·

【无标题】

这里写自定义目录标题欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注…