您的第一个使用 React 和 React-Spring 的响应式动画导航栏
在本教程中,你将使用React JS构建一个简单、响应式且动画化的导航栏。你将使用styled-components编写 CSS,并使用react-springs实现动画。
您可以在此处查看该项目的最终结果。
Styled Components 是一个 CSS-in-JS 样式框架,它使用 JavaScript 中的带标签模板字面量和 CSS 的强大功能,提供了一个平台,允许你编写真实的 CSS 来设置 React 组件的样式。本质上,Styled Components 是使用 styled-components 库编写的易于编写的 React 组件,你可以在 JavaScript 代码中使用纯 CSS 来设置组件的样式。React-Spring 是一个基于 Spring Physics 的动画库,它能够以非常简单的方式满足你大部分 UI 相关的动画需求。
开始吧!
我假设您的计算机上已经安装了节点,您可以通过在终端中输入以下内容来检查它:
node -v
如果没有,请安装最新版本。
好的,一切就绪!您将使用create-react-app启动一个新项目,因此请打开终端并输入:
npx create-react-app react-navbar
并添加项目期间所需的依赖项
npm install styled-components react-spring
现在使用您最喜欢的代码编辑器打开新创建的项目,转到src文件夹并删除app.css、index.css和logo.svg。
打开index.js文件并删除以下行:
import “./index.css”
同时打开你的app.js并清理它,使其看起来像这样:
import React from “react”;
const App = () => {
return(
<div>
</div>
)
}
export default App;
在您的src文件夹中创建一个名为style的目录,并在其中包含Global.js文件,同时在您的src文件夹中创建一个components文件夹,一个名为navbar的子文件夹,并在该文件夹中创建以下文件:Brand.js , BurgerMenu.js , CollapseMenu.js 和 Navbar.js。
我们还将在src文件夹中创建一个名为assets的文件夹,并在其中放置一张图片,您可以从这里下载该文件。
您的项目树应该如下所示:
太好了,这将是你的起点。
首先,您要使用 Styled Components 创建全局样式文件,打开Global.js文件并添加以下代码:
import { createGlobalStyle } from 'styled-components';
const GlobalStyles = createGlobalStyle`
@import url('https://fonts.googleapis.com/css?family=Montserrat:400,600&display=swap');;
*,
*::after,
*::before {
margin: 0px;
padding: 0px;
box-sizing: inherit;
}
html {
font-size: 62.5%;
}
body {
box-sizing: border-box;
font-family: 'Montserrat', sans-serif;
}
`;
export default GlobalStyles;
现在您将打开您的App.js文件,将其重构为类组件,添加我们需要的依赖项,添加Global.js和Navbar.js组件以及导航栏的状态。
import React, { Component } from 'react'
import Navbar from "./components/navbar/Navbar";
import GlobalStyle from './styles/Global';
class App extends Component {
state = {
navbarOpen: false
}
handleNavbar = () => {
this.setState({ navbarOpen: !this.state.navbarOpen });
}
render() {
return (
<>
<Navbar
navbarState={this.state.navbarOpen}
handleNavbar={this.handleNavbar}
/>
<GlobalStyle />
</>
)
}
}
export default App
太好了,在开始处理Navbar.js组件之前,您将处理小组件,打开您的Brand.js并使其看起来像这样:
import React from 'react'
import styled from "styled-components";
import logo from "../../assets/logo-min.png";
const Brand = () => {
return (
<Image src={logo} alt="Company Logo" />
)
}
export default Brand
const Image = styled.img`
height: 85%;
margin: auto 0;
`;
现在BurgerMenu.js:
import React from 'react';
import styled from "styled-components";
const Burgermenu = (props) => {
return (
<Wrapper onClick={props.handleNavbar}>
<div className={ props.navbarState ? "open" : "" }>
<span> </span>
<span> </span>
<span> </span>
</div>
</Wrapper>
);
}
export default Burgermenu;
const Wrapper = styled.div`
position: relative;
padding-top: .7rem;
cursor: pointer;
display: block;
& span {
background: #fdcb6e;
display: block;
position: relative;
width: 3.5rem;
height: .4rem;
margin-bottom: .7rem;
transition: all ease-in-out 0.2s;
}
.open span:nth-child(2) {
opacity: 0;
}
.open span:nth-child(3) {
transform: rotate(45deg);
top: -11px;
}
.open span:nth-child(1) {
transform: rotate(-45deg);
top: 11px;
}
`;
太好了,现在是最后一个组件,首先是CollapseMenu.js:
import React from 'react';
import styled from 'styled-components';
import { useSpring, animated } from 'react-spring';
const CollapseMenu = (props) => {
const { open } = useSpring({ open: props.navbarState ? 0 : 1 });
if (props.navbarState === true) {
return (
<CollapseWrapper style={{
transform: open.interpolate({
range: [0, 0.2, 0.3, 1],
output: [0, -20, 0, -200],
}).interpolate(openValue => `translate3d(0, ${openValue}px, 0`),
}}
>
<NavLinks>
<li><a href="/" onClick={props.handleNavbar}>link n1</a></li>
<li><a href="/" onClick={props.handleNavbar}>link n2</a></li>
<li><a href="/" onClick={props.handleNavbar}>link n3</a></li>
<li><a href="/" onClick={props.handleNavbar}>link n4</a></li>
</NavLinks>
</CollapseWrapper>
);
}
return null;
};
export default CollapseMenu;
const CollapseWrapper = styled(animated.div)`
background: #2d3436;
position: fixed;
top: 4.5rem;
left: 0;
right: 0;
`;
const NavLinks = styled.ul`
list-style-type: none;
padding: 2rem 1rem 2rem 2rem;
& li {
transition: all 300ms linear 0s;
}
& a {
font-size: 1.4rem;
line-height: 2;
color: #dfe6e9;
text-transform: uppercase;
text-decoration: none;
cursor: pointer;
&:hover {
color: #fdcb6e;
border-bottom: 1px solid #fdcb6e;
}
}
`;
最后是Navbar.js;
import React from 'react'
import styled from "styled-components";
import { useSpring, animated, config } from "react-spring";
import Brand from "./Brand";
import BurgerMenu from "./BurgerMenu";
import CollapseMenu from "./CollapseMenu";
const Navbar = (props) => {
const barAnimation = useSpring({
from: { transform: 'translate3d(0, -10rem, 0)' },
transform: 'translate3d(0, 0, 0)',
});
const linkAnimation = useSpring({
from: { transform: 'translate3d(0, 30px, 0)', opacity: 0 },
to: { transform: 'translate3d(0, 0, 0)', opacity: 1 },
delay: 800,
config: config.wobbly,
});
return (
<>
<NavBar style={barAnimation}>
<FlexContainer>
<Brand />
<NavLinks style={linkAnimation}>
<a href="/">link n1</a>
<a href="/">link n2</a>
<a href="/">link n3</a>
<a href="/">link n4</a>
</NavLinks>
<BurgerWrapper>
<BurgerMenu
navbarState={props.navbarState}
handleNavbar={props.handleNavbar}
/>
</BurgerWrapper>
</FlexContainer>
</NavBar>
<CollapseMenu
navbarState={props.navbarState}
handleNavbar={props.handleNavbar}
/>
</>
)
}
export default Navbar
const NavBar = styled(animated.nav)`
position: fixed;
width: 100%;
top: 0;
left: 0;
background: #2d3436;
z-index: 1;
font-size: 1.4rem;
`;
const FlexContainer = styled.div`
max-width: 120rem;
display: flex;
margin: auto;
padding: 0 2rem;;
justify-content: space-between;
height: 5rem;
`;
const NavLinks = styled(animated.ul)`
justify-self: end;
list-style-type: none;
margin: auto 0;
& a {
color: #dfe6e9;
text-transform: uppercase;
font-weight: 600;
border-bottom: 1px solid transparent;
margin: 0 1.5rem;
transition: all 300ms linear 0s;
text-decoration: none;
cursor: pointer;
&:hover {
color: #fdcb6e;
border-bottom: 1px solid #fdcb6e;
}
@media (max-width: 768px) {
display: none;
}
}
`;
const BurgerWrapper = styled.div`
margin: auto 0;
@media (min-width: 769px) {
display: none;
}
`;
您已完成!
如果您不想编写所有这些代码,您可以fork我为此示例创建的github repo 。
很快会看到更多提示和教程!
链接:https://dev.to/nunocpnp/your-very-first-responsive-and-animated-navigation-bar-with-react-and-react-spring-17co