(04)Header 组件开发——④ 换页旋转动画效果实现 | React.js 项目实战:PC 端“简书”开发
转载请注明出处,未经同意,不可修改文章内容。
🔥🔥🔥“前端一万小时”两大明星专栏——“从零基础到轻松就业”、“前端面试刷题”,已于本月大改版,合二为一,干货满满,欢迎点击公众号菜单栏各模块了解。
1 需求
我们注意看下“简书”官网的效果:
在点击“换一批”所在区域的时候,前边的旋转 icon 是会转动的。在此之前,我们并没有去实现这个动画效果。
本篇我们就可以借助这个“旋转动画”来正式开始我们 React 的编码。
2 “旋转”效果实现
需求分析:
当鼠标“点击” PanelChange
样式组件时,里边的 icon 会旋转 360 度。我们给这个 icon 取一个 class 名为 refresh
,但这个名字一开始是 false
。
给这个 class 名为 refresh
的 icon 写一些“旋转动画”效果。
当“点击”(或者 mousedown)时,我们就让这个 icon 的 class 名为 true
,旋转动画生效。
当 mouseup 时,我们就让这个 icon 的 class 名为 false
,旋转动画不生效。
⚠️当然,这个“旋转动画”实现的方式很多,我下面的方式(mousedown 和 mouseup)并非最佳实践,大家可以自行多种方式实现,并评论区交流。但我个人的编码习惯是:动画方面的东西,能用 CSS3 解决的,绝不引入 JS 逻辑,CSS3 的性能会更好。本篇,为了照顾到后续文章的连贯性,我依然会用 CSS3 的动画去实现效果。而交互方面,则会引入 React “数据”驱动的逻辑。
🔗前置知识: 《CSS——CSS 拓展:⑥ CSS3 变形》 《CSS——CSS 拓展:⑦ CSS3 Animation》
1️⃣打开 header 目录下的 index.js
文件,定位到 PanelChange
部分,给 span
增加一个 refresh
类名 :
<PanelChange>
<span className="iconfont refresh"></span>
换一批
</PanelChange>
2️⃣打开 header 目录下的 style.js
文件:
import styled, {keyframes} from "styled-components"; /*
2️⃣-①:由于要用到“动画”,
因此在顶部引入 keyframs 模块;
*/
2️⃣-②:定位到 PanelChange
部分:
/*
2️⃣-③:首先在 PanelChange 上方声明一个 rotate 变量,
并将定义好的“关键帧”赋值给 rotate;
*/
const rotate = keyframes`
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
`;
export const PanelChange = styled.div`
float: right;
color: #888;
font-size: 13px;
font-weight: normal;
cursor: pointer;
&:hover {
color: #333;
}
.refresh { /*
2️⃣-④:当子元素 span 拥有名为 refresh 的 class 时,
让 span 执行 rotate 动画!
*/
display: inline-block;
animation: ${rotate} linear 0.3s infinite; /* ❗️为了演示效果,我们设置了一个 infinite。 */
}
`;
看下页面效果:
3 交互实现
3️⃣打开 header 目录下的 index.js
文件(请按序号按步骤阅读):
import React, {Component} from "react";
import {
HeaderWrapper,
Logo,
Navbar,
ItemList,
LinkList,
SearchArea,
SearchInput,
SearchPanel,
PanelTitle,
PanelChange,
PanelLabels,
LabelLink,
Extra,
ExtraLink
} from "./style";
class Header extends Component {
constructor(props) {
super(props);
this.state = {
refresh: false /*
3️⃣-①:首先,在 constructor 中定义一个“数据”refresh,
使其初始为 false;
*/
}
// ❗️在这里改变 this 的指向!
this.handleMouseDown = this.handleMouseDown.bind(this);
this.handleMouseUp = this.handleMouseUp.bind(this)
}
render() {
return (
<HeaderWrapper>
<Logo>
<img src="https://qdywxs.github.io/jianshu-images/logo.png" alt="logo" />
</Logo>
<Navbar className="clearfix">
<ItemList className="active">
<LinkList href="/">
首页
</LinkList>
</ItemList>
<ItemList>
<LinkList href="/">
下载APP
</LinkList>
</ItemList>
</Navbar>
<SearchArea>
<SearchInput />
<span className="iconfont icon-search"></span>
<SearchPanel>
<PanelTitle>
热门搜索
{/*
3️⃣-③:给 PanelChange 部分绑定两个事件 mousedown 和 mouseup;
❗️记得在上边的 constructor 中改变 this 的指向!
*/}
<PanelChange onMouseDown={this.handleMouseDown} onMouseUp={this.handleMouseUp}>
{/*
3️⃣-②:其次,我们给 span 添加一个“三元运算符”的判断,
如果 refresh 为 true,则 class 名为 iconfont 和 refresh;
否则 class 名只为 iconfont;
*/}
<span className={this.state.refresh ? "iconfont refresh" : "iconfont"}></span>
换一批
</PanelChange>
</PanelTitle>
<PanelLabels className="clearfix">
<LabelLink href="/">
区块链
</LabelLink>
<LabelLink href="/">
故事
</LabelLink>
<LabelLink href="/">
小程序
</LabelLink>
<LabelLink href="/">
前端一万小时
</LabelLink>
</PanelLabels>
</SearchPanel>
</SearchArea>
<Extra>
<span className="iconfont icon-textsize" ></span>
<ExtraLink className="login" href="/">
登录
</ExtraLink>
<ExtraLink className="register" href="/">
注册
</ExtraLink>
<ExtraLink className="writing" href="/">
<span className="iconfont icon-pen"></span>
写文章
</ExtraLink>
</Extra>
</HeaderWrapper>
)
}
// 3️⃣-④:在这里写具体执行的逻辑!
handleMouseDown() {
this.setState({
refresh: true // ❗️当鼠标“按下去”时,数据 refresh 变为 true,旋转动画执行~
})
}
handleMouseUp() {
this.setState({
refresh: false // ❗️当鼠标“松开”时,数据 refresh 变为 false,旋转动画停止~
})
}
}
export default Header;
返回页面查看效果:
祝好,qdywxs ♥ you!
转载自:https://juejin.cn/post/7338443551745425448