前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >老板:你给我来个蜻蜓点水的特效

老板:你给我来个蜻蜓点水的特效

作者头像
饼干_
发布于 2022-09-19 07:16:14
发布于 2022-09-19 07:16:14
56100
代码可运行
举报
运行总次数:0
代码可运行

theme: channing-cyan

前言

最近,老板找到我说想搞点花哨的特效,于是乎,列举了各大让人抓狂的特效。

之后在我的深入评估(摸鱼)中,选取了一个稍微简单的特效,所谓蜻蜓点水实际就是波纹特效。

寻找思路

定好特效后,老板拿了张效果图给我:

好家伙,虽然我码的功能性的逻辑比较多,但是这种花哨的技能我也是不能落下的,我是基于react来编写该特效(也有vue版本的,后面会放上,有兴趣自行查看),接下来该理理思路,好为接下来的工作(摸鱼)做好准备。

首先,我们知道波纹会从中间扩散开来,且会有多个波纹叠加在一起,之后扩散开来的大小可以随机生成来拟真。

所以我们需要定义纹波圈层数以及波纹的最小最大尺寸,以及波纹的颜色等数据。

先定义一下波纹的配置:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import React from "react";
class App extends React.Component {
    get waveArr() {
            const wavesConfig = { ...this.state.wavesConfig };
            let total = [];
            for (let i = 1; i <= wavesConfig.total; i++) {
                    total.push(i);
            }
            return total;
    }
    constructor(props) {
        super(props);
        this.state = {
                waves: [], // 存放波纹的数组
                wavesConfig: {
                        maxSize: 200, // px,波纹最大尺寸
                        minSize: 100, // px,波纹最小尺寸
                        zIndexCount: 999, // 波纹父元素其实z-index数值
                        waveColor: "#40b6f0", //波纹基础颜色
                        total: 5, //波纹圈层数
                },			
                clickedCount: 0, //统计点击次数(这个后面说)
        };
    }

}

有了基本配置后,我们需要一个创建波纹的方法,那这个方法该如何实现呢?

理一下思路,首先新生成的波纹当然是要在之前波纹的上层产生叠加效果,之后给定随机范围内的波纹大小让其生成,并且往波纹数据里push一个新的波纹配置对象。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
createWave = (e) => {
        const wavesConfig = { ...this.state.wavesConfig };
        const { waves } = this.state;
        // 让新生成的波纹始终在之前波纹的上层产生叠加效果
        if (wavesConfig.zIndexCount > 99999) {
                wavesConfig.zIndexCount = 999;
        } else {
                wavesConfig.zIndexCount++;
        }
        // 在一定范围内随机生成波纹的大小
        const waveSize = parseInt(
                Math.random() * (wavesConfig.maxSize - wavesConfig.minSize) +
                        wavesConfig.minSize
        );
        //添加新的波纹数据
        waves.push({
                left: `${e.clientX - waveSize / 2}px`,
                top: `${e.clientY - waveSize / 2}px`,
                zIndex: wavesConfig.zIndexCount,
                width: `${waveSize}px`,
                height: `${waveSize}px`,
        });
        this.setState({
                waves,
                wavesConfig,
        });
};

有了创建波纹的方法后,当用户点击时候,将调用这个方法创建一个波纹。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
document.getElementById("root").onclick = (e) => {
    this.createWave(e);
}

那么有了波纹的基本配置,接下来就是波纹的特效,利用css动画和遍历来实现:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<div>
    <div className="main-container">
        <div className="waves">
        {waves.map((w, i) => {
            return (
            <div className="wave" style={{ ...w }} key={`w_${i}`}>
                {this.waveArr.map((n) => {
                    return (
                        <div
                        className="wave-item"
                        key={`wi_${n}`}
                        style={{
                                transform: `scale(${0.1 * Math.sqrt(n - 1)})`,
                                opacity: 0.3 * (1 / n),
                                animationDelay: `${(n - 1) * 0.12}s`,
                                animationDuration: `${0.6 + n * 0.3}s`,
                                backgroundColor: wavesConfig.waveColor,
                        }}
                        />
                    );
                })}
            </div>
            );
        })}
        </div>
    </div>
</div>
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
.waves {
  .wave {
    position: fixed;
    pointer-events: none; // 点击事件穿透,使得鼠标点击可以穿透波纹,兼容ie11及以上
    @keyframes wave {
      to {
        //波纹逐渐扩散变大变透明
        transform: scale(1);
        opacity: 0;
      }
    }
    .wave-item {
      width: 100%;
      height: 100%;
      position: absolute;
      border-radius: 100%;
      animation: wave forwards ease-out;
    }
  }
}

将上述代码码完后,随便往一个地方引入该组件(此处略N行代码):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import Wave from './Wave/app.jsx'
render() {
    return (
        <div>
            <Wave/>
        </div>
    )
}

跑起项目并点击页面你会看到如下效果:

为了防止过多dom积累占用内存,需要定时清理波纹内的数据:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
componentDidMount() {
        const { clickedCount, waves } = this.state;
        let num = clickedCount;
        document.getElementById("root").onclick = (e) => {
                num++; // 统计点击次数
                this.setState({
                        clickedCount: num,
                });
                this.createWave(e);
        };
        let lastCount = 0;
        // 2秒内无点击清空waves,防止过多的dom累积占用内存
        setInterval(() => {
                if (lastCount === clickedCount) {
                        console.log("hi");
                        console.log(clickedCount);
                        this.setState({
                                waves: [],
                        });
                }
                lastCount = clickedCount;
        }, 2000);
}

完整代码

app.jsx

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import React from "react";
class App extends React.Component {
    get waveArr() {
            const wavesConfig = { ...this.state.wavesConfig };
            let total = [];
            for (let i = 1; i <= wavesConfig.total; i++) {
                    total.push(i);
            }
            return total;
    }
    constructor(props) {
        super(props);
        this.state = {
                waves: [], // 存放波纹的数组
                wavesConfig: {
                        maxSize: 200, // px,波纹最大尺寸
                        minSize: 100, // px,波纹最小尺寸
                        zIndexCount: 999, // 波纹父元素其实z-index数值
                        waveColor: "#40b6f0", //波纹基础颜色
                        total: 5, //波纹圈层数
                },			
                clickedCount: 0, //统计点击次数(这个后面说)
        };
    }
    componentDidMount() {
        const { clickedCount, waves } = this.state;
        let num = clickedCount;
        document.getElementById("root").onclick = (e) => {
                num++; // 统计点击次数
                this.setState({
                        clickedCount: num,
                });
                this.createWave(e);
        };
        let lastCount = 0;
        // 2秒内无点击清空waves,防止过多的dom累积占用内存
        setInterval(() => {
                if (lastCount === clickedCount) {
                        console.log("hi");
                        console.log(clickedCount);
                        this.setState({
                                waves: [],
                        });
                }
                lastCount = clickedCount;
        }, 2000);
    }
    createWave = (e) => {
        const wavesConfig = { ...this.state.wavesConfig };
        const { waves } = this.state;
        // 让新生成的波纹始终在之前波纹的上层产生叠加效果
        if (wavesConfig.zIndexCount > 99999) {
                wavesConfig.zIndexCount = 999;
        } else {
                wavesConfig.zIndexCount++;
        }
        // 在一定范围内随机生成波纹的大小
        const waveSize = parseInt(
                Math.random() * (wavesConfig.maxSize - wavesConfig.minSize) +
                        wavesConfig.minSize
        );
        //添加新的波纹数据
        waves.push({
                left: `${e.clientX - waveSize / 2}px`,
                top: `${e.clientY - waveSize / 2}px`,
                zIndex: wavesConfig.zIndexCount,
                width: `${waveSize}px`,
                height: `${waveSize}px`,
        });
        this.setState({
                waves,
                wavesConfig,
        });
    };
    render() {
        const { waves, wavesConfig } = this.state;
        return (
            <div>
                <div className="main-container">
                    <div className="waves">
                        {waves.map((w, i) => {
                            return (
                            <div className="wave" style={{ ...w }} key={`w_${i}`}>
                                {this.waveArr.map((n) => {
                                    return (
                                        <div
                                        className="wave-item"
                                        key={`wi_${n}`}
                                        style={{
                                                transform: `scale(${0.1 * Math.sqrt(n - 1)})`,
                                                opacity: 0.3 * (1 / n),
                                                animationDelay: `${(n - 1) * 0.12}s`,
                                                animationDuration: `${0.6 + n * 0.3}s`,
                                                backgroundColor: wavesConfig.waveColor,
                                        }}
                                        />
                                    );
                                })}
                            </div>
                            );
                        })}
                    </div>
                </div>
            </div>
        )
    }

}

app.less

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
.waves {
  .wave {
    position: fixed;
    pointer-events: none; // 点击事件穿透,使得鼠标点击可以穿透波纹,兼容ie11及以上
    @keyframes wave {
      to {
        //波纹逐渐扩散变大变透明
        transform: scale(1);
        opacity: 0;
      }
    }
    .wave-item {
      width: 100%;
      height: 100%;
      position: absolute;
      border-radius: 100%;
      animation: wave forwards ease-out;
    }
  }
}

最后

以上故事纯属虚构,出自作者开源项目的组件,也许不是最佳写法,欢迎提出建议。

react版源码:react-dark-photo

vue版源码:vue-dark-photo

都看到这了,不给的赞吗?

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-09-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
【React】学习笔记(二)——组件的生命周期、React脚手架使用
生命周期是React中非常重要的一个部分,可以说学了React但不会生命周期 = 白学
鸡先生
2022/10/29
2.4K0
【React】学习笔记(二)——组件的生命周期、React脚手架使用
React修仙笔记,筑基初期之更新数据
在之前的一篇文章中我们有了解到react函数组件和class组件,以及react数据流,状态提升,以及react设计哲学,在我们了解了这些基本的知识后,我们需要了解react内部更深的一些知识
Maic
2022/12/21
5380
React修仙笔记,筑基初期之更新数据
react完成井字棋小游戏
这次我们搭建本地react开发环境,首先需要将node升级到14以上并且npm需要5.6以上,这个去官网下载安装包覆盖安装即可
阿超
2022/08/21
6350
React入门六: 组件基础练习
代码优化: this.state.comments出现多次。声明个变量接收它
用户4793865
2023/01/12
3730
「React进阶」 React全部api解读+基础实践大全(夯实基础万字总结)
很多同学用react开发的时候,真正用到的React的api少之又少,基本停留在Component,React.memo等层面,实际react源码中,暴露出来的方法并不少,只是我们平时很少用。但是React暴露出这么多api并非没有用,想要玩转react,就要明白这些API究竟是干什么的,应用场景是什么,今天就让我们从react 到 react-dom,一次性把react生产环境的暴露api复习个遍(涵盖90%+)。
用户6835371
2021/06/01
2.2K0
「React进阶」 React全部api解读+基础实践大全(夯实基础万字总结)
React 折腾记 - (3) 结合Mobx实现一个比较靠谱的动态tab水平菜单,同时关联侧边栏
前言 动态tab水平菜单,这个需求很常见,特别是对于后台管理系统来说; 因为当我们侧边栏层级多了,你要找到一个子菜单,必须找,展开,点击. 而有了这个,我们就能节省不少时间,体验上来说也会改善不少 实
CRPER
2018/08/28
3.2K0
React 折腾记 - (3) 结合Mobx实现一个比较靠谱的动态tab水平菜单,同时关联侧边栏
如何使用 React 中制作一个贪吃蛇游戏?
Snake Game 使用 ReactJS 项目实现功能组件并相应地管理状态。开发的游戏允许用户使用箭头键控制蛇或触摸屏幕上显示的按钮来收集食物并增长长度。游戏的目标是在不与墙壁或蛇自己的身体碰撞的情况下吃尽可能多的食物。
用户1418987
2023/11/03
4990
如何使用 React 中制作一个贪吃蛇游戏?
React:FrontendWiki前端维基项目&amp;&amp;用纯CSS实现树
首先很幸运,我们的组长来自北大研院,从未与北大学子共事过,今日闻名不如人,真真实实感受到思维上的不一样之处,从思维角度就让我或多或少有些成长。
源心锁
2022/08/01
6080
React:FrontendWiki前端维基项目&amp;&amp;用纯CSS实现树
「react进阶」年终送给react开发者的八条优化建议
笔者是一个 react 重度爱好者,在工作之余,也看了不少的 react 文章, 写了很多 react 项目 ,接下来笔者讨论一下 React 性能优化的主要方向和一些工作中的小技巧。送人玫瑰,手留余香,阅读的朋友可以给笔者点赞,关注一波 。陆续更新前端文章。
用户6835371
2021/06/01
1.8K0
「react进阶」年终送给react开发者的八条优化建议
「React 基础」组件生命周期函数componentDidMount()介绍
大家好,今天我们将通过一个实例——番茄计时器,学习下如何使用函数生命周期的一个重要函数componentDidMount():componentDidMount()在组件加载完成, render之后进行调用,只会执行一次。
前端达人
2020/02/03
1.6K0
「React 基础」组件生命周期函数componentDidMount()介绍
RLayer:基于React.js多功能弹层组件
RLayer.js 一款基于react.js构建的pc桌面端自定义弹出层组件。拥有精致的UI及极简的调用方式,支持顺滑拖拽、缩放及最大化等功能,让复杂的弹框场景变得简单化。
andy2018
2020/12/07
2.4K0
RLayer:基于React.js多功能弹层组件
【React】归纳篇(七)React脚手架 | 写一个表单
React 提供了用于创建react项目的脚手架库:create-react-app,使用这个脚手架开发项目具有“模块化、组件化、工程化”特点。
前端修罗场
2023/10/07
2300
【React】归纳篇(七)React脚手架 | 写一个表单
React----组件生命周期知识点整理
如果是自定义方法,React不会自己去调用,因此一般使用变量+箭头函数的形式,将该自定义方法作为一个事件的触发函数
大忽悠爱学习
2021/11/15
1.6K0
React-组件-原生动画 和 React-组件-性能优化
可以在 shouldcomponentupdate 该生命周期函数当中进行决定是否需要进行重新渲染,官方文档:https://zh-hans.reactjs.org/docs/react-component.html#shouldcomponentupdate
杨不易呀
2023/09/30
2790
React实现分页器效果
世间万物皆对象
2024/03/20
1700
React.js简单轮播图组件封装
如何使用 https://player.bilibili.com/player.html?aid=370886286 轮播图 /* * imgUrl : 轮播图数据 * speed :
用户6379025
2022/12/26
8.2K0
React全局消息组件
--- layout: post title: React全局消息组件 date: 2019-10-06 author: 霁 header-img: catalog: true categories: 学习 React tags: React --- 需求 为了在项目里构建一个能够使用的全局消息组件,以达到反馈。 参考连接: clancysong github mobile ant design [uOtXB8.gif] 开始 消息不需要一直存在于页面中。 主要是在需要的时候往页面中插入一个div, 再利用
我已经洗完澡了
2019/10/14
2K0
React全局消息组件
React基础
React起源于FaceBook的内部项目,用来架设Instagram的网站,并于2013年5月开源。
小二丶
2023/11/28
1.3K1
建站四部曲之前端显示篇(React+上线)
本系列分为四篇: 建站四部曲之后端接口篇(SpringBoot+上线) 建站四部曲之Python数据爬虫篇(selenium) 建站四部曲之前端显示篇(React+上线) 建站四部曲之移动端篇(Android) ---- 零、前言 本系列为了总结一下手上的知识,致敬我的2018 本篇的重点在于:用前两篇的数据使用React搭建一个简单网站 本篇总结的技术点: React的组件封装、React实现简单的懒加载、React中的网络请求、搜索功能 React中form表单与接口的对接、路由react-
张风捷特烈
2018/12/26
3.4K0
React:像message.success()一样实现Message通用容器及Message组件
对于Message这样的组件,在各个页面都有可能使用到。但我们是不希望在各个页面都必须引入一个容器的,也不希望还必须做专门的组件挂载,这样的组件能用,但不是很能用。
源心锁
2022/08/12
1.4K0
React:像message.success()一样实现Message通用容器及Message组件
推荐阅读
相关推荐
【React】学习笔记(二)——组件的生命周期、React脚手架使用
更多 >
领券
社区富文本编辑器全新改版!诚邀体验~
全新交互,全新视觉,新增快捷键、悬浮工具栏、高亮块等功能并同时优化现有功能,全面提升创作效率和体验
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文