为了让网站能够炫酷一点,必然的动画是不可或缺的
现在实现一个类似canvas流动背景的功能,最初设计是遍历多个小球在页面上,然后小球在dom节点内移动变换。后决定加入小球一起变换,让小球跟随大球移动,同时小球也能有自己的运动轨迹
知识点dom渲染以及TweenMax
1.代码实现
根目录建立文件夹pages,内部建立Home文件夹,Home内建立index.jsx以及index.scss其中Home将作为我们的起始页面,这在router中可以配置根路径’/’。
index.jsx代码
//引入css
import './index.scss'
function Home(){
return (
<div>
//放入页面元素
</div>
)
}
export default Home
index.scss由于是模块化开发,这部分代码没有
既然我们建立了这个页面,现在我们需要把我们的swiper部分渲染到页面上
在component里面建立SwipperBanner文件夹,内部照例建立index.jsx以及index.scss文件
index.jsx代码
import './index.scss'
function SwiperBanner(params) {
const bigCirleRef=useRef(null)
const smallCirleRef=useRef(null)
return(
<div className='Allpart'>
<div className='bigimg'>
<img className='widthFixImg' src="../image/banner-img.png" alt="" />
<div className='allcircle'>
<div className='bigcircleList circle' ref={bigCirleRef}>
{/* <div className='bigcircle'></div> */}
</div>
<div className='smallcircleList circle' ref={smallCirleRef}>
</div>
</div>
<div className='center'>
<div className='center-img-box'>
<img className='center-text-img' src="../image/musicText.png" alt="" />
</div>
<div className='text'>
Share & Music Online & Love Dj
</div>
<div className='btn'>
LET LISTEN NOW
</div>
</div>
</div>
</div>
)
}
export default SwiperBanner
然后给我们的文件加入配置好的样式(index.scss)
.Allpart{
.bigimg{
position: relative;
z-index: -1;
.widthFixImg{
width: 100%;
height: auto;
object-fit: cover;
}
.allcircle{
position: absolute;
// z-index: 3;
top: 4.7rem;
width: 100%;
height: calc(100% - 4.7rem);
overflow: hidden;
.circle{
position: absolute;
top: 0;
// left: 30rem;
.bigcircle{
// width: 15rem;
// height: 15rem;
border-radius: 50%;
// background-color: yellowgreen;
opacity: 0.5;
transition: none linear 3s;
transition-property: left,top,background-color;
}
.smallcircle{
// width: 15rem;
// height: 15rem;
border-radius: 50%;
// background-color: yellowgreen;
opacity: 0.5;
transition: none linear 3s;
transition-property: left,top,background-color;
}
}
}
.center{
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
.center-img-box{
// position: relative;
.center-text-img{
width: 30rem;
}
}
.text{
color: white;
font-size: 1rem;
font-family: 'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif;
letter-spacing: 0.2rem;
text-align: center;
margin-top: 0.5rem;
}
.btn{
font-size: 0.7rem;
width: 8rem;
height: 1.6rem;
line-height: 1.6rem;
color: #f8f9fc;
background: linear-gradient(to right ,#d62eb2 ,#126fc6);
border-radius: 1rem;
text-align: center;
margin:1rem auto;
}
}
}
}
这里的代码思路呢是将大球通过js代码渲染到bigCirleRef节点,小球渲染到smallRef节点
所以我们需要写一下js代码(index.jsx)
import './index.scss'
//模块引入
import {useEffect,useRef} from 'react'
function SwiperBanner(params) {
//获取dom节点
const bigCirleRef=useRef(null)
const smallCirleRef=useRef(null)
//储存能移动的面积(x,y)
let aearMsg={}
//这里是全局定义的定时器
let interGetheight=''
//首先获取到dom的信息,包括dom的高度和宽度也就是我大小球能运动的范围
const getDomMsg=(dom)=>{
return new Promise((resolve,reject)=>{
console.log("clientWidth",dom.clientWidth);
console.log("clientHeight",dom.clientHeight);
aearMsg.canMoveX=dom.clientWidth;
aearMsg.canMoveY=dom.clientHeight
interGetheight=setInterval(() => {
console.log("clientHeight",dom.clientHeight);
if (dom.clientHeight!=0) {
//获取到dom高度后对定时器进行移除
clearInterval(interGetheight)
//轨迹大小
resolve({
canMoveX:dom.clientWidth,
canMoveY:dom.clientHeight
})
}
}, 1000);
})
}
//定义render函数将小大球渲染到页面
const render=(dom)=>{
console.log("ranmgeee");
getDomMsg(dom).then(res=>{
let {canMoveX,canMoveY}=res
//创建大球的函数
bigcircleRender(3,bigCirleRef.current,'15rem','15rem',canMoveX,canMoveY)
//创建小球的函数
smallcircleRender(3,smallCirleRef.current,'6rem','6rem',canMoveX,canMoveY)
smallcircleRender(2,smallCirleRef.current,'4rem','4rem',canMoveX,canMoveY)
})
}
//我们动态产生小球的函数num为数量,renderDom为我们需要渲染到的dom节点,width以及height为小球大小,canMoveX以及canMoveY为能移动的范围
const smallcircleRender=(num,renderDom,width,height,canMoveX,canMoveY)=>{
const cirlceNumber=num
let _fragment=document.createElement('div')
for (let index = 0; index < cirlceNumber; index++) {
let top=Math.floor(Math.random()*canMoveY+1)-150
let left=Math.floor(Math.random()*canMoveX+1)-150
if (top<0) {
top=0
}
if(left<0){
left=0
}
console.log(top,left);
let _dom= document.createElement('div')
_dom.setAttribute('class','smallcircle circle')
_dom.setAttribute('style',`top:${top}px;left:${left}px;background-color:${colorRandom()};width:${width};height:${height}`)
_dom.style.width=width
_dom.style.height=height
_fragment.appendChild(_dom)
}
// renderDom.innerHTML=_html
renderDom.appendChild(_fragment)
document.querySelectorAll('.smallcircle').forEach((domItem,index)=>{
new TimelineMax({
repeat:-1,
yoyo:true,
}).to(domItem,Math.random()+0.4,{
width:domItem.clientWidth*1.25,
height:domItem.clientWidth*1.25,
})
})
domMove(document.querySelectorAll('.smallcircle'),canMoveX,canMoveY,width,height)
}
//创建大球同理,至于为什么分开成两个函数,是因为想做小球会跟随大球的动画,写在一个函数不便于解耦
const bigcircleRender=(num,renderDom,width,height,canMoveX,canMoveY)=>{
const cirlceNumber=num
let _fragment=document.createElement('div')
for (let index = 0; index < cirlceNumber; index++) {
let top=Math.floor(Math.random()*canMoveY+1)-150
let left=Math.floor(Math.random()*canMoveY+1)-150
if (top<0) {
top=0
}
if(left<0){
left=0
}
let _dom= document.createElement('div')
_dom.setAttribute('class','bigcircle circle')
_dom.setAttribute('style',`top:${top}px;left:${left}px;background-color:${colorRandom()};width:${width};height:${height}`)
_dom.style.width=width
_dom.style.height=height
_fragment.appendChild(_dom)
}
// renderDom.innerHTML=_html
renderDom.appendChild(_fragment)
document.querySelectorAll('.bigcircle').forEach((domItem,index)=>{
new TimelineMax({
repeat:-1,
yoyo:true,
}).to(domItem,Math.random()+0.4,{
width:domItem.clientWidth*1.25,
height:domItem.clientWidth*1.25,
ease: Circ.easeOut,
glowFilter:'#fff'
})
})
domMove(document.querySelectorAll('.bigcircle'),canMoveX,canMoveY,width,height)
}
//上述运用到了colorRandom函数来实现随机颜色
const colorRandom=()=>{
var r = Math.floor(Math.random() * 256); //随机生成256以内r值
var g = Math.floor(Math.random() * 256); //随机生成256以内g值
var b = Math.floor(Math.random() * 256); //随机生成256以内b值
return `rgb(${r},${g},${b})`; //返回rgb(r,g,b)格式颜色
}
//需定义domMove函数来做小球的运动动画
const domMove=(dom,areaX,areaY,width,height)=>{
let doChange=()=>{
//遍历我们的球
dom.forEach((item,index)=>{
let top=Math.floor(Math.random()*(areaY-item.clientHeight)+1)
let left=Math.floor(Math.random()*(areaX-item.clientWidth)+1)
if (top<0) {
top=0
}
if(left<0){
left=0
}
// console.log("zhix",top,left);
item.style.top=top+'px'
item.style.left=left+'px'
item.style.backgroundColor=colorRandom()
})
}
//
doChange()
setInterval(() => {
//小球跟随动画
smallBarFollow()
}, 1000);
setInterval(() => {
doChange()
}, 3000);
}
//定义小球跟随动画
const smallBarFollow = () => {
document.querySelectorAll('.smallcircle').forEach((smallItem, index)=>{
document.querySelectorAll('.bigcircle').forEach((bigItem, index)=>{
//条件判断小球周围是否有大球
if ((bigItem.offsetTop-smallItem.offsetTop < 25 && bigItem.offsetTop - smallItem.offsetTop > -25) && (bigItem.offsetLeft - smallItem.offsetLeft < 25 && bigItem.offsetLeft - smallItem.offsetLeft < -25)) {
let smallBarTop = Math.floor(Math.random() * bigItem.style.top.replace(/px/g,'') + 1) + 'px',
smallBarLeft=Math.floor(Math.random() * bigItem.style.left.replace(/px/g,'') + 1) + 'px'
smallItem.style.top = smallBarTop
smallItem.style.left = smallBarLeft
// console.log("小球跟着大球走",smallBarLeft,smallBarTop);
}
})
})
}
//使用useEffect函数
useEffect(()=>{
render(document.querySelector('.allcircle'))
},[])
return(
<div className='Allpart'>
<div className='bigimg'>
<img className='widthFixImg' src="../image/banner-img.png" alt="" />
<div className='allcircle'>
<div className='bigcircleList circle' ref={bigCirleRef}>
{/* <div className='bigcircle'></div> */}
</div>
<div className='smallcircleList circle' ref={smallCirleRef}>
</div>
</div>
<div className='center'>
<div className='center-img-box'>
<img className='center-text-img' src="../image/musicText.png" alt="" />
</div>
<div className='text'>
Share & Music Online & Love Dj
</div>
<div className='btn'>
LET LISTEN NOW
</div>
</div>
</div>
</div>
)
}
export default SwiperBanner
将问题刨析开为
1.创建大小球
2.大小球动画
3.小球吸附大球轨迹
细节之颜色随机,只需要更换rgb值即可,这边是定义colorRandom函数去实现的
const colorRandom = () => {
var r = Math.floor(Math.random() * 256); //随机生成256以内r值
var g = Math.floor(Math.random() * 256); //随机生成256以内g值
var b = Math.floor(Math.random() * 256); //随机生成256以内b值
return `rgb(${r}, ${g}, ${b})`; //返回rgb(r,g,b)格式颜色
}
下一部分内容打算直接写完了,包括过渡动画板块,已经一些part和音乐插件的使用
找到工作了,年后要上班了,好起来了