likes
comments
collection
share

(04)Header 组件开发——④ 换页旋转动画效果实现 | React.js 项目实战:PC 端“简书”开发

作者站长头像
站长
· 阅读数 4
转载请注明出处,未经同意,不可修改文章内容。

🔥🔥🔥“前端一万小时”两大明星专栏——“从零基础到轻松就业”、“前端面试刷题”,已于本月大改版,合二为一,干货满满,欢迎点击公众号菜单栏各模块了解。

1 需求

我们注意看下“简书”官网的效果: (04)Header 组件开发——④ 换页旋转动画效果实现 | React.js 项目实战:PC 端“简书”开发

在点击“换一批”所在区域的时候,前边的旋转 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">&#xe65f;</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。 */
  }
`;

看下页面效果: (04)Header 组件开发——④ 换页旋转动画效果实现 | React.js 项目实战:PC 端“简书”开发

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">&#xe63e;</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"}>&#xe65f;</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" >&#xe739;</span>
          <ExtraLink className="login" href="/">
            登录
          </ExtraLink>
          <ExtraLink className="register" href="/">
            注册
          </ExtraLink> 
      
          <ExtraLink className="writing" href="/">
            <span className="iconfont icon-pen">&#xe600;</span>
            写文章
          </ExtraLink>     
        </Extra>
      </HeaderWrapper>
    )
  }
  
  // 3️⃣-④:在这里写具体执行的逻辑!
  handleMouseDown() {
    this.setState({
      refresh: true // ❗️当鼠标“按下去”时,数据 refresh 变为 true,旋转动画执行~
    })
  }

  handleMouseUp() {
    this.setState({
      refresh: false // ❗️当鼠标“松开”时,数据 refresh 变为 false,旋转动画停止~
    })
  }
}

export default Header;

返回页面查看效果: (04)Header 组件开发——④ 换页旋转动画效果实现 | React.js 项目实战:PC 端“简书”开发

祝好,qdywxs ♥ you!