目录
1、效果图
2、首先在components目录下创建Transform目录,包括index.css、index.js
?3、全局引入
?马上就要过节了,想把自己的项目搞得酷炫一些,对整个网站的按钮添加图标、飘花效果、首屏大图展示、顶部导航背景图,于是就写了这一遍文字,如有兴趣的小伙伴们可以一起学习进步,仅供参考。
1、效果图
效果图如下:
效果视频如下:
index.css主要定义了几种漂浮时的动画轨迹
/* index.css */
.animation1 {
display: inline-block;
position: fixed;
z-index: 2000;
opacity: 0;
top: -40px;
left: -40px;
animation: animation1 8s linear infinite;
}
.animation2 {
display: inline-block;
position: fixed;
z-index: 2000;
opacity: 0;
top: -40px;
left: -40px;
animation: animation2 9s 1s linear infinite;
}
.animation3 {
display: inline-block;
position: fixed;
z-index: 2000;
opacity: 0;
top: -40px;
left: -40px;
animation: animation3 9s linear infinite;
}
.animation4 {
display: inline-block;
position: fixed;
z-index: 2000;
opacity: 0;
top: -40px;
left: -40px;
animation: animation4 9s 2s linear infinite;
}
.animation5 {
display: inline-block;
position: fixed;
z-index: 2000;
opacity: 0;
top: -40px;
left: -40px;
animation: animation5 9s 1s linear infinite;
}
.animation6 {
display: inline-block;
position: fixed;
z-index: 2000;
opacity: 0;
top: -40px;
left: -40px;
animation: animation6 9s 3s linear infinite;
}
.animation7 {
display: inline-block;
position: fixed;
z-index: 2000;
opacity: 0;
top: -40px;
left: -40px;
animation: animation7 8s linear infinite;
}
.animation8 {
display: inline-block;
position: fixed;
z-index: 2000;
opacity: 0;
top: -40px;
right: -200px;
animation: animation8 10s linear infinite;
}
@keyframes animation1 {
0% {
top: 50%;
left: -80px;
opacity: 0;
}
90% {
opacity: 1;
}
100% {
top: 100%;
left: 20%;
opacity: 0;
}
}
@keyframes animation2 {
0% {
top: 80px;
left: -80px;
opacity: 0;
}
90% {
opacity: 1;
}
100% {
top: 100%;
left: 50%;
opacity: 0;
}
}
@keyframes animation3 {
0% {
top: 30%;
left: 20%;
opacity: 0;
}
90% {
opacity: 1;
}
100% {
top: 110%;
left: 75%;
opacity: 0;
}
}
@keyframes animation4 {
0% {
top: -80px;
left: -80px;
opacity: 0;
}
90% {
opacity: 1;
}
100% {
top: 101%;
left: 80%;
opacity: 0;
}
}
@keyframes animation5 {
0% {
top: 10%;
left: 40%;
opacity: 0;
}
90% {
opacity: 1;
}
100% {
top: 100%;
left: 120%;
opacity: 0;
}
}
@keyframes animation6 {
0% {
top: -80px;
left: 50%;
opacity: 0;
}
90% {
opacity: 1;
}
100% {
top: 100%;
left: 110%;
opacity: 0;
}
}
@keyframes animation7 {
0% {
top: -80px;
left: 70%;
opacity: 0;
}
90% {
opacity: 1;
}
100% {
top: 50%;
left: 110%;
opacity: 0;
}
}
@keyframes animation8 {
0% {
top: -75px;
right: -200px;
opacity: 0;
transform: rotate(0)
}
50% {
transform: rotate(-30deg)
}
90% {
opacity: 1;
}
100% {
top: 100%;
right: 100%;
transform: rotate(0);
opacity: 0;
}
}
:global .switchStyle {
z-index: 31;
}
.shadeWrapper {
z-index: 1050;
position: fixed;
top: 0;
left: 200px;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.3);
display: flex;
justify-content: center;
align-items: center;
}
.shadeWrapper .shadeClose {
cursor: pointer;
font-size: 30px;
position: absolute;
right: 30px;
top: 30px;
color: #fff;
}
index.js是主要的逻辑代码,下面对代码进行分析,完整代码如下
- 进入页面调用 this.getTableList() 方法,获取展示的图片列表,包括btn(按钮)、burst(首图)、float(漂浮)、header(顶部);
- 紧接着调用 this.initStyle() 方法,首先对列表进行循环,选择出当前时间在开始时间、结束时间之间的一条数据,然后再根据showoption对展示位置进行判断,并添置flag标志;
- 接下来调用 this.loadStyleString(sty),传入处理后的样式字符串,创建style标签,添加到head中。
对于漂浮的特效,由于只定义了七种轨迹,所以最多上传七张图片,initList(data, cb)方法进行了处理,如果不够七张,则会递归重复传入数组,超过七张后截取前七张,然后回调。
对于首屏大图,一天内只出现一次,关闭时会同时设置localStorage的有效期,设置有效期一天,这样就可以判断当前日期是否和localStorage中存的一样啦。
顶部的开启、关闭特效只对float(漂浮)做了控制,有效期为七天,超时会重新显示。
// index.js
import React, { PureComponent } from 'react';
import { Switch } from 'antd';
import { CloseCircleOutlined } from '@ant-design/icons';
import './index.css';
import moment from 'moment';
Storage.prototype.setExpire = (key, value, expire) => {
let obj = {
data: value,
time: Date.now(),
expire: expire,
};
//localStorage 设置的值不能为对象,转为json字符串
localStorage.setItem(key, JSON.stringify(obj));
};
Storage.prototype.getExpire = (key) => {
let val = localStorage.getItem(key);
if (!val) {
return val;
}
val = JSON.parse(val);
if (Date.now() - val.time > val.expire) {
localStorage.removeItem(key);
return null;
}
return val.data;
};
export default class Transform extends PureComponent {
constructor(props) {
super(props);
let storage = localStorage.getExpire(`floatFlag`);
if (storage == 'false' || storage == false) {
storage = false;
} else {
storage = true;
}
this.state = {
showBurst: false, // burst
pathBurst: '', // burst path
timeBurst: '', // burst time
showFloat: false,
showBtn: false,
floatFlag: storage,
floatList: [],
};
}
componentDidMount() {
this.getTableList();
}
// 获取七条数据
initList(data, cb) {
if (data && data.length < 7) {
let dt = data.concat(data);
this.initList(dt, cb);
} else {
cb(data.slice(0, 7));
}
}
// 获取列表
getTableList() {
let list = [
{
showoption: 'btn',
starttime: '2022-09-03',
endtime: '2023-09-03',
imagaddress: [
{
path: 'https://img-blog.csdnimg.cn/3e93fe58b6444c2c8165e85756118888.png',
},
],
},
{
showoption: 'burst',
starttime: '2022-09-03',
endtime: '2023-09-03',
imagaddress: [
{
path: 'https://img-blog.csdnimg.cn/a1c4ddc6b73b48c5a88512eba3a907fa.jpeg',
},
],
},
{
showoption: 'float',
starttime: '2022-09-03',
endtime: '2023-09-03',
imagaddress: [
{
path: 'https://img-blog.csdnimg.cn/3e93fe58b6444c2c8165e85756118888.png',
},
{
path: 'https://img-blog.csdnimg.cn/3e93fe58b6444c2c8165e85756118888.png',
},
],
},
{
showoption: 'header',
starttime: '2022-09-03',
endtime: '2023-09-03',
imagaddress: [
{
path: 'https://img-blog.csdnimg.cn/a1c4ddc6b73b48c5a88512eba3a907fa.jpeg',
},
],
},
];
this.setState(
{
tableList: list,
},
() => {
this.initStyle();
},
);
}
add0(m) {
return m < 10 ? '0' + m : m;
}
initStyle() {
try {
let tableList = JSON.parse(JSON.stringify(this.state.tableList));
let resDt = [];
let time = new Date();
var y = time.getFullYear();
var m = time.getMonth() + 1;
var d = time.getDate();
var H = time.getHours();
var FEN = time.getMinutes();
var Miao = time.getSeconds();
let newDe = moment(
`${y}-${this.add0(m)}-${this.add0(d)} ${this.add0(H)}:${this.add0(FEN)}:${this.add0(Miao)}`,
).format('YYYY-MM-DD HH:mm:ss');
for (let index = 0; index < tableList.length; index++) {
const element = tableList[index];
let strDe = moment(`${element.starttime} 00:00:00`).format('YYYY-MM-DD HH:mm:ss');
let endDe = moment(`${element.endtime} 23:59:59`).format('YYYY-MM-DD HH:mm:ss');
if (moment(strDe).isBefore(moment(newDe)) && moment(newDe).isBefore(moment(endDe))) {
resDt.push(element);
// break;
}
}
if (resDt && resDt.length > 0) {
for (let idx = 0; idx < resDt.length; idx++) {
const element = resDt[idx];
if (element.showoption == 'float') {
let str = element.imagaddress;
let list = [];
this.initList(str, (dt) => {
list = dt;
});
this.setState({
showFloat: true,
showBtn: true,
floatList: list,
});
} else if (element.showoption == 'btn') {
let strBtn = element.imagaddress[0].path;
let sty = `
.ant-btn::before {
content: " ";
display: block;
background: url(${strBtn}) no-repeat!important;
background-size: 20px !important;
height: 100%;
width: 100%;
position: absolute;
top: -10px;
left: -10px;
opacity: 1;
}
`;
let sty2 = `
.ant-btn::before {
content: " ";
display: block;
background: transparent!important;
background-size: 20px !important;
height: 100%;
width: 100%;
position: absolute;
top: -10px;
left: -10px;
opacity: 1;
}
`;
this.loadStyleString(sty);
} else if (element.showoption == 'burst') {
let tmZl = `${y}-${this.add0(m)}-${this.add0(d)}`;
let flag = true;
if (localStorage.getExpire(`timeBurstLocal`) == `${tmZl}`) {
flag = false;
}
this.setState({
showBurst: flag,
pathBurst: element.imagaddress[0].path,
timeBurst: tmZl,
});
} else if (element.showoption == 'header') {
let strH = element.imagaddress[0].path;
let styH = `
.ant-pro-global-header {
background-image: url(${strH});
background-repeat: no-repeat;
background-size: cover;
// opacity: 0.8;
}
`;
this.loadStyleString(styH);
}
}
} else {
this.setState({
showFloat: false,
showBtn: false,
floatFlag: false,
floatList: [],
});
}
} catch (error) {
this.setState({
showFloat: false,
showBtn: false,
floatFlag: false,
floatList: [],
});
}
}
loadStyleString(css) {
var style = document.createElement('style');
style.type = 'text/css';
try {
style.appendChild(document.createTextNode(css));
} catch (ex) {
style.styleSheet.cssText = css; //兼容IE
}
var head = document.getElementsByTagName('head')[0];
head.appendChild(style);
}
// burst关闭
CloseBurst() {
this.setState(
{
showBurst: false,
timeBurstLocal: this.state.timeBurst,
},
() => {
// 有效期两天
localStorage.setExpire(`timeBurstLocal`, `${this.state.timeBurstLocal}`, 86400000 * 2);
},
);
}
// 调用示例
// loadStyleString("body{background-color:red}");
selectHtml() {
if (this.state.showFloat && this.state.floatFlag) {
return (
<React.Fragment>
{this.state.floatList
? this.state.floatList.map((item, index) => {
let width = Math.round(Math.random() * 20 + 30);
return (
<div key={index} className={`animation${index}`}>
<img width={width} src={item.path} />
</div>
);
})
: ''}
</React.Fragment>
);
} else {
return null;
}
}
// 调用示例
selectHtmlBurst() {
var tempHeightRight = document.documentElement.clientHeight - 100;
if (this.state.showBurst && this.state.pathBurst) {
return (
<React.Fragment>
<div
onClick={() => {
this.CloseBurst();
}}
className="shadeWrapper"
style={{ cursor: 'pointer' }}
>
<div
onClick={() => {
this.CloseBurst();
}}
className="shadeClose"
>
<CloseCircleOutlined />
</div>
<div>
<img style={{ maxHeight: tempHeightRight }} src={this.state.pathBurst} />
</div>
</div>
</React.Fragment>
);
} else {
return null;
}
}
// 开启/关闭特效
switchCheck(e) {
// 有效期七天
localStorage.setExpire(`floatFlag`, e, 86400000 * 7);
this.setState(
{
floatFlag: e,
},
() => {
console.log('e', e);
// this.initStyle();
},
);
}
render() {
return (
<React.Fragment>
{this.state.showBtn ? (
<div
style={{
display: 'inline-block',
position: 'fixed',
top: '10px',
right: '300px',
zIndex: '31',
}}
>
<Switch
checkedChildren="关闭特效"
unCheckedChildren="开启特效"
checked={this.state.floatFlag}
onChange={(e) => this.switchCheck(e)}
/>
</div>
) : null}
{this.selectHtmlBurst()}
{this.selectHtml()}
</React.Fragment>
);
}
}
?3、全局引入
在layout布局中全局引入组件
|